V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
dataman
V2EX  ›  推广

Docker Swarm 在生产环境中的进阶指南

  •  
  •   dataman · 2017-05-08 15:40:54 +08:00 · 4068 次点击
    这是一个创建于 2782 天前的主题,其中的信息可能已经有所发展或是发生改变。

    上周数人云给大家分享了——《你可能需要的关于 Docker Swarm 的经验分享》。今天给大家带来这位作者大大的后续文章——《 Docker Swarm 在生产环境中的进阶指南》

    当在本地开发环境中使用 Docker,或者已经在单台生产服务器上部署 Docker,却发现它不足以支撑更多的流量。应该如何解决?本文将给出若干提示,如何在生产环境中使用 Docker Swarm。

    附:如果对 Swarm 不熟悉,请查看之前的文章《你可能需要知道的关于 Docker Swarm 的经验分享》

    阅读官方文档

    这里不重复官方 Swarm 的入门教程和文档。入门教程很简短,它会让你明白 Swarm 是如何工作的。这里也不讲解设置和部署 Swarm 环境,网上有很多初级的教程,可供参考如——

    Digitalocean 上的教程 :( https://www.digitalocean.com/community/tutorials/how-to-create-a-cluster-of-docker-containers-with-docker-swarm-and-digitalocean-on-ubuntu-16-04

    或者 google 搜索相关教程。

    附:一个牛 X 的:Ansible role ( https://galaxy.ansible.com/atosatto/docker-swarm/)

    Docker Swarm 用法实例

    就观察而言,用于 Swarm 内部信息共享和调度的 Cpu 开销确实很低。得益于此,管理节点同时也可以是工作节点。如果要跑一个 1000+个节点的大集群,管理节点开销需要非常多的资源,但当集群是小规模到中等规模时,这种资源消耗和开销是可以忽略不计的。参考这里—— ( https://sematext.com/blog/2016/11/14/docker-swarm-lessons-from-swarm3k/) Swarm3k, 一个运行 4700 个节点的集群实验。

    • 路由匹配(服务发现、负载均衡、跨容器通讯)非常可靠。在单个端口上运行一个服务,Swarm 节点的任意主机都可以访问,负载均衡完全在后台实现。之前遇到过一些难题,但使用 Docker1.13 版本后,问题得到解决。

    • 在配置初始化完成后,只需要几行命令作为日常运维。下面是日常使用的命令:

    # let's create new service  创建一个新的服务
    docker service create \  
      --image nginx \
      --replicas 2 \
      nginx 
    
    # ... update service ...   更新服务
    docker service update \  
      --image nginx:alpine \
      nginx 
    
    # ... and remove   删除服务
    docker service rm nginx
    
    # but usually it's better to scale down 但是更好的办法是缩容,而不是直接删除服务
    docker service scale nginx=0
    
    # you can also scale up   扩容
    docker service scale nginx=5
    
    # show all services 列出所有的服务
    docker service ls
    
    # show containers of service with status   列出一个服务的所有实例(包括服务的健康状况)
    docker service ps nginx
    
    # detailed info  服务的详细信息
    docker service inspect nginx
    
    • 服务零宕机,是完美的持续部署方案。
    # lets build new version and push to the registry 创建新版本的镜像,并且推送到 registry
    docker build -t hub.docker.com/image .  
    docker push hub.docker.com/image
    
    # and now just update (on a master node) 现在更新服务(在 master 节点上)
    docker service update --image hub.docker.com/image service
    
    • 易于启动:分布式系统本身就很复杂。相比于其他解决方案( Mesos, Kubernetes ), Swarm 简单易学,即便无任何 Swarm 的知识,从单台服务器 Docker-compose 方式的部署,扩展到 20 台服务器,分布式可伸缩的解决方案,也只需要大约一周。

    • 无需修改。容器实例同时跑在多台服务器上。修改任何东西,需要打包一个新的镜像,适当的测试和部署是成功的关键。

    Docker Swarm 上的容器选择

    并不是所有的应用都适合跑在 Docker swarm 上,比如,数据库和一些有状态的服务。

    从理论上而言,可以使用标签的方式固定某个容器跑在某个特定的资源上,但是,更难的是从 Swarm 集群外部来访问这个容器提供的服务。(在 Docker1.12 版本里面没有简单的方式来实现,在 Docker1.13+版本可以使用附加的 Overlay 网络模式)。

    比如,想开放一个数据库服务给外部访问,让外部所有节点都可以访问数据库,但是这不是真正想要实现的结果(只想让特定节点访问数据库) 。 又如,Swarm 里面的跨主机存储卷挂载几个月之前还不可靠,用户上传文件这样简单的操作也会引发问题。

    适用于容器化的是那些由环境变量驱动无状态的应用容器。是时候准备自己使用过的开源软件 Docker 镜像了,例如配置完善的 Nginx 镜像。

    跑在 swarm 上的服务

    • web 服务器( Django channels - Daphne and workers )

    • 反向代理( Nginx )

    • Periodic workers (Celery)

    • 指标收集器 (Sensu)

    不跑在 swarm 上的容器

    • 数据库( Postgres )

    • Redis

    由于获取真实 IP 的问题( https://github.com/moby/moby/issues/25526 ),也会把 Sginx 单独移出来不跑在 Swarm 模式下,至少应该使用 Nost 网络模式,但在 Docker 1.12 版本下,这是唯一的选择。

    设置好 Docker 仓库

    Docker 仓库或是自己的服务器,也许是 Dockerhub、Gitlab.com(作者选择这个)此类。在服务器上创建镜像已经不适用了,因为有太多服务器且在创建服务时( Docker service create )要指明镜像。如果仓库是私有仓库,记得增加--with-registry-auth 这个参数,否则其他节点无法拉取镜像。同时应该使用 Tag 来标明发布的版本号,这样发现问题时可以快速回滚。

    改造无状态化应用容器

    “部分有状态”是指有一些共享而不重要的文件。可以尝试使用共享存储卷挂载,更好的方法是迁移到亚马逊 S3 或者其他云存储。记住,扩张的时候,云是最佳选择。

    如例子中,不得不创建自己有合适参数的 Nginx 镜像。通过共享存储卷挂载在以前非常不可靠、不方便。

    准备日志收集服务

    集中式的日志和指标是使用分布式文件系统的必须项,如 ELK,Graphana,Graylog 等等。

    这里有许多可选项,有开源项目,也有 SaaS 类服务。这些打造和整合成可靠的服务是复杂且艰难的。建议先使用云端服务(如 Loggly, Logentries ), 当成本上涨的时候,再开始架设自己的日志收集服务。 例:ELK 栈日志处理配置:

    docker service update \  
      --log-driver gelf \
      --log-opt gelf-address=udp://monitoring.example.com:12201 \
      --log-opt tag=example-tag \
      example-service
    

    创建可附加的网络

    记得使用它,否则无法在 Docker Swarm 下一条命令跑起一个容器。这是 Docker1.13+新功能。如果使用旧版本的 Docker, 最好升级下。

    代码:

    docker network create --driver=overlay --attachable core
    

    增加环境变量

    如果创建 Docker 镜像的时候,遵循了最佳实践原则( https://rock-it.pl/how-to-write-excellent-dockerfiles/),允许在运行的时候通过环境变量设置一切配置项,那么把应用迁到 Swarm 的过程完全没有问题。

    例,有用的命令:

    docker service create \  
      --env VAR=VALUE \
      --env-file FILENAME \
      ...
    
    docker service update \  
      --env-add VAR=NEW_VALUE \
      --env-rm VAR \
      ..
    

    下一个级别就是使用非公开的 API 挂载文件像挂载秘钥那样( Authorized keys, SSL certs 等)。作者暂时还未使用此功能,不能详述,但这个功能特性绝对值得思考和使用。

    设置适当实例和批量更新

    保持适当数量的实例,以应对高流量和实例或者节点不可用的情况。同时太多的实例数也会占用 CPU 和内存,并且导致争抢 CUP 资源。

    update-parallelism 的默认值是 1,默认只有一个实例在运行。但这个更新速度太慢了,建议是 replicas / 2。

    相关命令:

    docker service update \  
      --update-parallelism 10 \
      webapp
    
    # You can scale multiple services at once
    docker service scale redis=1 nginx=4 webapp=20
    
    # Check scaling status
    docker service ls
    
    # Check details of a service (without stopped containers)
    docker service ps webapp | grep -v "Shutdown"
    

    把 Swarm 配置保存为代码

    最好使用 Docker Compose v3 版本的语法( https://docs.docker.com/compose/compose-file/#deploy )。

    他允许使用代码指定几乎所有的服务选项。作者在开发的时候使用 Docker-compose.yml,在生产环境( swarm )配置使用 Docker-compose.prod.yml . 部署 Docker-compose 文件中所描述的服务,需要 Docker stack deploy 命令(属于新版本 Stack 命令集合中的一部分[https://docs.docker.com/engine/reference/commandline/stack/])

    Docker compose v3 例子:

    # docker-compose.prod.yml
    version: '3'  
    services:  
      webapp:
        image: registry.example.com/webapp
        networks:
          - ingress
        deploy:
          replicas: ${WEBAPP_REPLICAS}
          mode: replicated
          restart_policy:
            condition: on-failure
    
      proxy:
        image: registry.example.com/webapp-nginx-proxy
        networks:
          - ingress
        ports:
          - 80:80
          - 443:443
        deploy:
          replicas: ${NGINX_REPLICAS}
          mode: replicated
          restart_policy:
            condition: on-failure
    
    networks:  
      ingress:
        external: true
    

    部署的例子(创建或者更新服务):

    export NGINX_REPLICAS=2 WEBAPP_REPLICAS=5
    
    docker login registry.example.com  
    docker stack deploy \  
      -c docker-compose.prod.yml\
      --with-registry-auth \
      frontend
    

    提示:Docker-compose 文件支持环境变量 (${VARIABLE}), 所以,可以动态调整配置作为测试等。

    设置限制

    就经验而言,可以为所有服务设置 CPU 使用限制。当某一个容器应用占用掉所有主机资源时,此限制可以避免这种情况发生。

    当想把所有容器均匀地发布在所有主机上或是想确保有足够的资源来响应操作时,需使用 Reserve-cpu 这个参数。

    例如:

    docker service update  
      --limit-cpu 0.25
      --reserve-cpu 0.1
      webapp
    

    监控连接

    曾经在 Swarm 网络上遇到过一些问题。很多次所有的流量都被路由到同一个容器实例上,而同时有 9 个容器实例正常且健康的。这种情况下——即流量持续导到一个实例上,做扩容或者缩容操作的时候,加上这个参数--endpoint-mode。

    在没有适当的集中式日志时,要发现这个问题还真不容易。

    原文作者:Jakub Skałecki

    原文链接: https://rock-it.pl/my-experience-with-docker-swarm-when-you-need-it/

    欢迎关注数人云微信公众号,如有后续文章,我们会在第一时间进行跟进。

    3 条回复    2017-05-10 21:24:06 +08:00
    firefox12
        1
    firefox12  
       2017-05-09 11:04:23 +08:00 via iPhone
    我一直不明白外部网络如何访问 容器的服务。如果一个 swarm 启动一个 2 节点的 nginx 服务,外部客户端用什么 ip 来访问它? 如果采用全集群一个网关做 2 层转发,如何解决它的扩展 性能 和单点的问题?
    PhilC
        2
    PhilC  
       2017-05-10 17:21:21 +08:00
    @firefox12 你在每个节点上的 80 端口都访问到 nginx,即使这个节点上没有 nginx
    firefox12
        3
    firefox12  
       2017-05-10 21:24:06 +08:00
    @PhilC 所有是一个 proxy 代理所有请求 这样这个代理就是个性能瓶颈。也是单点
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   3077 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 31ms · UTC 14:05 · PVG 22:05 · LAX 06:05 · JFK 09:05
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.