Docker Swarm 入门

来源:互联网 发布:淘宝商城托管 编辑:程序博客网 时间:2024/05/17 03:25

Docker Swarm 入门一篇文章就够了



1.Swarm简介



Docker自诞生以来,其容器特性以及镜像特性给DevOps爱好者带来了诸多方便。然而在很长的一段时间内,Docker只能在单host上运行,其跨host的部署、运行与管理能力颇受外界诟病。跨host能力的薄弱,直接导致Docker容器与host的紧耦合,这种情况下,Docker容器的灵活性很难令人满意,容器的迁移、分组等都成为很难实现的功能点。

Swarm是Docker公司在2014年12月初新发布的容器管理工具。和Swarm一起发布的Docker管理工具还有Machine以及Compose。

Swarm是一套较为简单的工具,用以管理Docker集群,使得Docker集群暴露给用户时相当于一个虚拟的整体。Swarm使用标准的Docker API接口作为其前端访问入口,换言之,各种形式的Docker Client(dockerclient in go, docker_py, docker等)均可以直接与Swarm通信。Swarm几乎全部用Go语言来完成开发,并且还处于一个Alpha版本,目前在github上发布的版本仅有v0.1.0-rc1。然而Swarm的发展十分快速,功能和特性的变更迭代还非常频繁。因此,可以说Swarm还不推荐被用于生产环境中,但可以肯定的是Swarm是一项很有前途的技术。

Swarm的设计和其他Docker项目一样,遵循“batteries included but removable”原则。笔者对该原则的理解是:batteries included代表设计Swarm时,为了完全体现分布式容器集群部署、运行与管理功能的完整性,Swarm和Docker协同工作,Swarm内部包含了一个较为简易的调度模块,以达到对Docker集群调度管理的效果;“but removable”意味着Swarm与Docker并非紧耦合,同时Swarm中的调度模块同样可以定制化,用户可以按照自己的需求,将其替换为更为强大的调度模块,如Mesos等。另外,这套管理引擎并未侵入Docker的使用,这套机制也为其他容器技术的集群部署、运行与管理方式提供了思路。

本文将从以下两点分析Swarm:

  • Swarm架构
  • Swarm命令

2.Swarm架构

Swarm作为一个管理Docker集群的工具,首先需要将其部署起来,可以单独将Swarm部署于一个节点。另外,自然需要一个Docker集群,集群上每一个节点均安装有Docker。具体的Swarm架构图可以参照下图:

17
 

图2.1 Swarm架构图
Swarm架构中最主要的处理部分自然是Swarm节点,Swarm管理的对象自然是Docker Cluster,Docker Cluster由多个Docker Node组成,而负责给Swarm发送请求的是Docker Client。

3.Swarm命令

Swarm架构图可以让大家对Swarm有一个初步的认识,比如Swarm的具体工作流程:Docker Client发送请求给Swarm;Swarm处理请求并发送至相应的Docker Node;Docker Node执行相应的操作并返回响应。除此之外,Swarm的工作原理依然还不够明了。

深入理解Swarm的工作原理,可以先从Swarm提供的命令入手。Swarm支持的命令主要有4个:swarm create、swarm manage、swarm join、swarm list。当然还有一个swarm help命令,该命令用于指导大家如何正确使用swarm命令,本文不再赘述。

3.1 swarm create

Swarm中swarm create命令用于创建一个集群标志,用于Swarm管理Docker集群时,Docker Node的节点发现功能。

发起该命令之后,Swarm会前往Docker Hub上内建的发现服务中获取一个全球唯一的token,用以唯一的标识Swarm管理的Docker集群。

注:Swarm的运行需要使用服务发现,目前该服务内建与Docker Hub,该服务发现机制目前还在alpha版本,站点为:http://discovery-stage.hub/docker.com 。

3.2 swarm manage

Swarm中swarm manage是最为重要的管理命令。一旦swarm manage命令在Swarm节点上被触发,则说明用户需要swarm开始管理Docker集群。从运行流程的角度来讲,swarm经历的阶段主要有两点:启动swarm、接收并处理Docker集群管理请求。

Swarm启动的过程包含三个步骤:

  1. 发现Docker集群中的各个节点,收集节点状态、角色信息,并监视节点状态的变化;
  2. 初始化内部调度(scheduler)模块;
  3. 创建并启动API监听服务模块;

第一个步骤,Swarm发现Docker集群中的节点。发现(discovery)是Swarm中用于维护Docker集群状态的机制。既然涉及到发现(discovery),那在这之前必须先有注册(register)。Swarm中有专门负责发现(discovery)的模块,而关于注册(register)部分,不同的discovery模式下,注册(register)也会有不同的形式。

目前,Swarm中提供了5种不同的发现(discovery)机制:Node Discovery、File Discovery、Consul Discovery、EtcD Discovery和Zookeeper Discovery。

第二个步骤,Swarm内部的调度(scheduler)模块被初始化。swarm通过发现机制发现所有注册的Docker Node,并收集到所有Docker Node的状态以及具体信息。此后,一旦Swarm接收到具体的Docker管理请求,Swarm需要对请求进行处理,并通过所有Docker Node的状态以及具体信息,来筛选(filter)决策到底哪些Docker Node满足要求,并通过一定的策略(strategy)将请求转发至具体的一个Docker Node。

第三个步骤,Swarm创建并初始化API监听服务模块。从功能的角度来讲,可以将该模块抽象为Swarm Server。需要说明的是:虽然Swarm Server完全兼容Docker的API,但是有不少Docker的命令目前是不支持的,毕竟管理Docker集群与管理单独的Docker会有一些区别。当Swarm Server被初始化并完成监听之后,用户即可以通过Docker Client向Swarm发送Docker集群的管理请求。

Swarm的swarm manage接收并处理Docker集群的管理请求,即是Swarm内部多个模块协同合作的结果。请求入口为Swarm Server,处理引擎为Scheduler,节点信息依靠Disocovery。

3.3 swarm join

Swarm的swarm join命令用于将Docker Node添加至Swarm管理的Docker集群中。从这点也可以看出swarm join命令的执行位于Docker Node,因此在Docker Node上运行该命令,首先需要在Docker Node上安装Swarm,由于该Swarm只会执行swarm join命令,故可以将其当成Docker Node上用于注册的agent模块。

功能而言,swarm join可以认为是完成Docker Node在Swarm节点处的注册(register)工作,以便Swarm在执行swarm manage时可以发现该Docker Node。然而,上文提及的5种discovery模式中,并非每种模式都支持swarm join命令。不支持的discovery的模式有Node Discovery与File Discovery。

Docker Node上swarm join执行之后,标志着Docker Node向Swarm注册,请求加入Swarm管理的Docker集群中。Swarm通过注册信息,发现Docker Node,并获取Docker Node的状态以及具体信息,以便处理Docker请求时作为调度依据。

3.4 swarm list

Swarm中的swarm list命令用以列举Docker集群中的Docker Node。

Docker Node的信息均来源于Swarm节点上注册的Docker Node。而一个Docker Node在Swarm节点上注册,仅仅是注册了Docker Node的IP地址以及Docker监听的端口号。

使用swarm list命令时,需要指定discovery的类型,类型包括:token、etcd、file、zk以及<ip>。而swarm list并未罗列Docker集群的动态信息,比如Docker Node真实的运行状态,或者Docker Node在Docker集群中扮演的角色信息。

4.总结

Swarm的架构以及命令并没有很复杂,同时也为希望管理Docker集群的Docker爱好者降低了学习和使用门槛。

俗话说得好,没有一种一劳永逸的工具,有效的管理Docker集群同样也是如此。缺乏场景来谈论Swarm的价值,意义并不会很大。相反,探索和挖掘Swarm的特点与功能,并为Docker集群的管理提供一种可选的方案,是Docker爱好者更应该参与的事。

本文初步介绍Swarm,并涉及架构与命令,下期将带来Swarm的具体使用,以及Swarm的架构剖析。



Swarm 在 Docker 1.12 版本之前属于一个独立的项目,在 Docker 1.12 版本发布之后,该项目合并到了 Docker 中,成为 Docker 的一个子命令。目前,Swarm 是 Docker 社区提供的唯一一个原生支持 Docker 集群管理的工具。它可以把多个 Docker 主机组成的系统转换为单一的虚拟 Docker 主机,使得容器可以组成跨主机的子网网络。

1. Swarm 最佳实践

Swarm 是目前 Docker 官方唯一指定(绑定)的集群管理工具。Docker 1.12 内嵌了 swarm mode 集群管理模式。

为了方便演示跨主机网络,我们需要用到一个工具——Docker Machine,这个工具与 Docker Compose、Docker Swarm 并称 Docker 三剑客,下面我们来看看如何安装 Docker Machine:

$ curl -L https://github.com/docker/machine/releases/download/v0.9.0-rc2/docker-machine-`uname -s`-`uname -m` >/tmp/docker-machine &&    chmod +x /tmp/docker-machine &&    sudo cp /tmp/docker-machine /usr/local/bin/docker-machine

安装过程和 Docker Compose 非常类似。现在 Docker 三剑客已经全部到齐了。
在开始之前,我们需要了解一些基本概念,有关集群的 Docker 命令如下:

  • docker swarm:集群管理,子命令有 init, join,join-token, leave, update
  • docker node:节点管理,子命令有 demote, inspect,ls, promote, rm, ps, update
  • docker service:服务管理,子命令有 create, inspect, ps, ls ,rm , scale, update
  • docker stack/deploy:试验特性,用于多应用部署,等正式版加进来再说。

2. 创建集群

首先使用 Docker Machine 创建一个虚拟机作为 manger 节点。

$ docker-machine create --driver virtualbox manager1                                    Running pre-create checks...(manager1) Unable to get the latest Boot2Docker ISO release version:  Get https://api.github.com/repos/boot2docker/boot2docker/releases/latest: dial tcp: lookup api.github.com on [::1]:53: server misbehavingCreating machine...(manager1) Unable to get the latest Boot2Docker ISO release version:  Get https://api.github.com/repos/boot2docker/boot2docker/releases/latest: dial tcp: lookup api.github.com on [::1]:53: server misbehaving(manager1) Copying /home/zuolan/.docker/machine/cache/boot2docker.iso to /home/zuolan/.docker/machine/machines/manager1/boot2docker.iso...(manager1) Creating VirtualBox VM...(manager1) Creating SSH key...(manager1) Starting the VM...(manager1) Check network to re-create if needed...(manager1) Found a new host-only adapter: "vboxnet0"(manager1) Waiting for an IP...Waiting for machine to be running, this may take a few minutes...Detecting operating system of created instance...Waiting for SSH to be available...Detecting the provisioner...Provisioning with boot2docker...Copying certs to the local machine directory...Copying certs to the remote machine...Setting Docker configuration on the remote daemon...Checking connection to Docker...Docker is up and running!To see how to connect your Docker Client to the Docker Engine running on this virtual machine, run: docker-machine env manager1

查看虚拟机的环境变量等信息,包括虚拟机的 IP 地址:

$  docker-machine env manager1export DOCKER_TLS_VERIFY="1"export DOCKER_HOST="tcp://192.168.99.100:2376"export DOCKER_CERT_PATH="/home/zuolan/.docker/machine/machines/manager1"export DOCKER_MACHINE_NAME="manager1"# Run this command to configure your shell: # eval $(docker-machine env manager1)

然后再创建一个节点作为 work 节点。

$ docker-machine create --driver virtualbox worker1

现在我们有了两个虚拟主机,使用 Machine 的命令可以查看:

$ docker-machine ls                             NAME     ACTIVE   DRIVER       STATE    URL                        SWARM  DOCKER   ERRORSmanager1   -      virtualbox   Running  tcp://192.168.99.100:2376         v1.12.3   worker1    -      virtualbox   Running  tcp://192.168.99.101:2376         v1.12.3

但是目前这两台虚拟主机并没有什么联系,为了把它们联系起来,我们需要 Swarm 登场了。
因为我们使用的是 Docker Machine 创建的虚拟机,因此可以使用 docker-machine ssh 命令来操作虚拟机,在实际生产环境中,并不需要像下面那样操作,只需要执行 docker swarm 即可。

把 manager1 加入集群:

$ docker-machine ssh manager1 docker swarm init --listen-addr 192.168.99.100:2377 --advertise-addr 192.168.99.100Swarm initialized: current node (23lkbq7uovqsg550qfzup59t6) is now a manager.To add a worker to this swarm, run the following command:    docker swarm join \    --token SWMTKN-1-3z5rzoey0u6onkvvm58f7vgkser5d7z8sfshlu7s4oz2gztlvj-c036gwrakjejql06klrfc585r \    192.168.99.100:2377To add a manager to this swarm, run 'docker swarm join-token manager' and follow the instructions.

用 --listen-addr 指定监听的 ip 与端口,实际的 Swarm 命令格式如下,本例使用 Docker Machine 来连接虚拟机而已:

$ docker swarm init --listen-addr <MANAGER-IP>:<PORT>

接下来,再把 work1 加入集群中:

$ docker-machine ssh worker1 docker swarm join --token \    SWMTKN-1-3z5rzoey0u6onkvvm58f7vgkser5d7z8sfshlu7s4oz2gztlvj-c036gwrakjejql06klrfc585r \    192.168.99.100:2377This node joined a swarm as a worker.

上面 join 命令中可以添加 --listen-addr $WORKER1_IP:2377 作为监听准备,因为有时候可能会遇到把一个 work 节点提升为 manger 节点的可能,当然本例子没有这个打算就不添加这个参数了。

注意:如果你在新建集群时遇到双网卡情况,可以指定使用哪个 IP,例如上面的例子会有可能遇到下面的错误。

$ docker-machine ssh manager1 docker swarm init --listen-addr $MANAGER1_IP:2377Error response from daemon: could not choose an IP address to advertise since this system has multiple addresses on different interfaces (10.0.2.15 on eth0 and 192.168.99.100 on eth1) - specify one with --advertise-addrexit status 1

发生错误的原因是因为有两个 IP 地址,而 Swarm 不知道用户想使用哪个,因此要指定 IP。

$ docker-machine ssh manager1 docker swarm init --advertise-addr 192.168.99.100 --listen-addr 192.168.99.100:2377 Swarm initialized: current node (ahvwxicunjd0z8g0eeosjztjx) is now a manager.To add a worker to this swarm, run the following command:    docker swarm join \    --token SWMTKN-1-3z5rzoey0u6onkvvm58f7vgkser5d7z8sfshlu7s4oz2gztlvj-c036gwrakjejql06klrfc585r \    192.168.99.100:2377To add a manager to this swarm, run 'docker swarm join-token manager' and follow the instructions.

集群初始化成功。

现在我们新建了一个有两个节点的“集群”,现在进入其中一个管理节点使用 docker node 命令来查看节点信息:

$ docker-machine ssh manager1 docker node lsID                       HOSTNAME  STATUS  AVAILABILITY  MANAGER STATUS23lkbq7uovqsg550qfzup59t6 *  manager1    Ready      Active         Leaderdqb3fim8zvcob8sycri3hy98a    worker1     Ready      Active

现在每个节点都归属于 Swarm,并都处在了待机状态。Manager1 是领导者,work1 是工人。

现在,我们继续新建虚拟机 manger2、worker2、worker3,现在已经有五个虚拟机了,使用 docker-machine ls 来查看虚拟机:

NAME     ACTIVE    DRIVER       STATE     URL                         SWARM   DOCKER    ERRORSmanager1   -       virtualbox   Running   tcp://192.168.99.100:2376           v1.12.3   manager2   -       virtualbox   Running   tcp://192.168.99.105:2376           v1.12.3   worker1    -       virtualbox   Running   tcp://192.168.99.102:2376           v1.12.3   worker2    -       virtualbox   Running   tcp://192.168.99.103:2376           v1.12.3   worker3    -       virtualbox   Running   tcp://192.168.99.104:2376           v1.12.3

然后我们把剩余的虚拟机也加到集群中。

  • 添加 worker2 到集群中:
    $ docker-machine ssh worker2 docker swarm join \  --token SWMTKN-1-3z5rzoey0u6onkvvm58f7vgkser5d7z8sfshlu7s4oz2gztlvj-c036gwrakjejql06klrfc585r \  192.168.99.100:2377This node joined a swarm as a worker.
  • 添加 worker3 到集群中:
    $ docker-machine ssh worker3 docker swarm join \  --token SWMTKN-1-3z5rzoey0u6onkvvm58f7vgkser5d7z8sfshlu7s4oz2gztlvj-c036gwrakjejql06klrfc585r \  192.168.99.100:2377This node joined a swarm as a worker.
  • 添加 manager2 到集群中:
    先从 manager1 中获取 manager 的 token:

    $ docker-machine ssh manager1 docker swarm join-token managerTo add a manager to this swarm, run the following command:  docker swarm join \  --token SWMTKN-1-3z5rzoey0u6onkvvm58f7vgkser5d7z8sfshlu7s4oz2gztlvj-8tn855hkjdb6usrblo9iu700o \192.168.99.100:2377

    然后添加 manager2 到集群中:

    $ docker-machine ssh manager2 docker swarm join \  --token SWMTKN-1-3z5rzoey0u6onkvvm58f7vgkser5d7z8sfshlu7s4oz2gztlvj-8tn855hkjdb6usrblo9iu700o \  192.168.99.100:2377This node joined a swarm as a manager.

现在再来查看集群信息:

$ docker-machine ssh manager2 docker node lsID                            HOSTNAME   STATUS   AVAILABILITY   MANAGER STATUS16w80jnqy2k30yez4wbbaz1l8     worker1     Ready     Active        2gkwhzakejj72n5xoxruet71z     worker2     Ready     Active        35kutfyn1ratch55fn7j3fs4x     worker3     Ready     Active        a9r21g5iq1u6h31myprfwl8ln *   manager2    Ready     Active        Reachabledpo7snxbz2a0dxvx6mf19p35z     manager1    Ready     Active        Leader

3. 建立跨主机网络

为了演示更清晰,下面我们把宿主机也加入到集群之中,这样我们使用 Docker 命令操作会清晰很多。
直接在本地执行加入集群命令:

$ docker swarm join \               --token SWMTKN-1-3z5rzoey0u6onkvvm58f7vgkser5d7z8sfshlu7s4oz2gztlvj-8tn855hkjdb6usrblo9iu700o \    192.168.99.100:2377This node joined a swarm as a manager.

现在我们有三台 manager,三台 worker。其中一台是宿主机,五台虚拟机。

$ docker node lsID                          HOSTNAME    STATUS    AVAILABILITY  MANAGER STATUS6z2rpk1t4xucffzlr2rpqb8u3    worker3     Ready     Active        7qbr0xd747qena4awx8bx101s *  user-pc     Ready     Active         Reachable9v93sav79jqrg0c7051rcxxev    manager2    Ready     Active         Reachablea1ner3zxj3ubsiw4l3p28wrkj    worker1     Ready     Active        a5w7h8j83i11qqi4vlu948mad    worker2     Ready     Active        d4h7vuekklpd6189fcudpfy18    manager1    Ready     Active          Leader

查看网络状态:

$ docker network lsNETWORK ID         NAME            DRIVER          SCOPE764ff31881e5        bridge          bridge          local                  fbd9a977aa03        host            host            local               6p6xlousvsy2        ingress         overlay         swarm            e81af24d643d        none            null            local

可以看到在 swarm 上默认已有一个名为 ingress 的 overlay 网络, 默认在 swarm 里使用,本例子中会创建一个新的 overlay 网络。

$ docker network create --driver overlay swarm_test4dm8cy9y5delvs5vd0ghdd89s$ docker network lsNETWORK ID         NAME                DRIVER              SCOPE764ff31881e5        bridge              bridge              localfbd9a977aa03        host                host                local6p6xlousvsy2        ingress             overlay             swarme81af24d643d        none                null                local4dm8cy9y5del        swarm_test          overlay             swarm

这样一个跨主机网络就搭建好了,但是现在这个网络只是处于待机状态,下一小节我们会在这个网络上部署应用。

4. 在跨主机网络上部署应用

首先我们上面创建的节点都是没有镜像的,因此我们要逐一 pull 镜像到节点中,这里我们使用前面搭建的私有仓库。

$ docker-machine ssh manager1 docker pull reg.example.com/library/nginx:alpine     alpine: Pulling from library/nginxe110a4a17941: Pulling fs layer... ...7648f5d87006: Pull completeDigest: sha256:65063cb82bf508fd5a731318e795b2abbfb0c22222f02ff5c6b30df7f23292feStatus: Downloaded newer image for reg.example.com/library/nginx:alpine$ docker-machine ssh manager2 docker pull reg.example.com/library/nginx:alpinealpine: Pulling from library/nginxe110a4a17941: Pulling fs layer... ...7648f5d87006: Pull completeDigest: sha256:65063cb82bf508fd5a731318e795b2abbfb0c22222f02ff5c6b30df7f23292feStatus: Downloaded newer image for reg.example.com/library/nginx:alpine$ docker-machine ssh worker1 docker pull reg.example.com/library/nginx:alpine alpine: Pulling from library/nginxe110a4a17941: Pulling fs layer... ...7648f5d87006: Pull completeDigest: sha256:65063cb82bf508fd5a731318e795b2abbfb0c22222f02ff5c6b30df7f23292feStatus: Downloaded newer image for reg.example.com/library/nginx:alpine$ docker-machine ssh worker2 docker pull reg.example.com/library/nginx:alpinealpine: Pulling from library/nginxe110a4a17941: Pulling fs layer... ...7648f5d87006: Pull completeDigest: sha256:65063cb82bf508fd5a731318e795b2abbfb0c22222f02ff5c6b30df7f23292feStatus: Downloaded newer image for reg.example.com/library/nginx:alpine$ docker-machine ssh worker3 docker pull reg.example.com/library/nginx:alpinealpine: Pulling from library/nginxe110a4a17941: Pulling fs layer... ...7648f5d87006: Pull completeDigest: sha256:65063cb82bf508fd5a731318e795b2abbfb0c22222f02ff5c6b30df7f23292feStatus: Downloaded newer image for reg.example.com/library/nginx:alpine

上面使用 docker pull 分别在五个虚拟机节点拉取 nginx:alpine 镜像。接下来我们要在五个节点部署一组 Nginx 服务。

部署的服务使用 swarm_test 跨主机网络。

$ docker service create --replicas 2 --name helloworld --network=swarm_test nginx:alpine5gz0h2s5agh2d2libvzq6bhgs

查看服务状态:

$ docker service lsID            NAME        REPLICAS  IMAGE         COMMAND5gz0h2s5agh2  helloworld  0/2       nginx:alpine

查看 helloworld 服务详情(为了方便阅读,已调整输出内容):

$ docker service ps helloworldID          NAME          IMAGE         NODE      DESIRED STATE   CURRENT STATE              ERRORay081uome3   helloworld.1  nginx:alpine  manager1  Running         Preparing 2 seconds ago  16cvore0c96  helloworld.2  nginx:alpine  worker2   Running         Preparing 2 seconds ago

可以看到两个实例分别运行在两个节点上。

进入两个节点,查看服务状态(为了方便阅读,已调整输出内容):

$ docker-machine ssh manager1 docker ps -aCONTAINER ID   IMAGE         COMMAND         CREATED        STATUS         PORTS            NAMES119f787622c2   nginx:alpine  "nginx -g ..."   4 minutes ago  Up 4 minutes   80/tcp, 443/tcp  hello ...$ docker-machine ssh worker2 docker ps -aCONTAINER ID   IMAGE         COMMAND         CREATED         STATUS        PORTS             NAMES5db707401a06   nginx:alpine  "nginx -g ..."   4 minutes ago   Up 4 minutes  80/tcp, 443/tcp   hello ...

上面输出做了调整,实际的 NAMES 值为:

helloworld.1.ay081uome3eejeg4mspa8pdlxhelloworld.2.16cvore0c96rby1vp0sny3mvt

记住上面这两个实例的名称。现在我们来看这两个跨主机的容器是否能互通:
首先使用 Machine 进入 manager1 节点,然后使用 docker exec -i 命令进入 helloworld.1 容器中 ping 运行在 worker2 节点的 helloworld.2 容器。

$ docker-machine ssh manager1 docker exec -i helloworld.1.ay081uome3eejeg4mspa8pdlx \    ping helloworld.2.16cvore0c96rby1vp0sny3mvtPING helloworld.2.16cvore0c96rby1vp0sny3mvt (10.0.0.4): 56 data bytes64 bytes from 10.0.0.4: seq=0 ttl=64 time=0.591 ms64 bytes from 10.0.0.4: seq=1 ttl=64 time=0.594 ms64 bytes from 10.0.0.4: seq=2 ttl=64 time=0.624 ms64 bytes from 10.0.0.4: seq=3 ttl=64 time=0.612 ms^C

然后使用 Machine 进入 worker2 节点,然后使用 docker exec -i 命令进入 helloworld.2 容器中 ping 运行在 manager1 节点的 helloworld.1 容器。

$ docker-machine ssh worker2 docker exec -i helloworld.2.16cvore0c96rby1vp0sny3mvt \    ping helloworld.1.ay081uome3eejeg4mspa8pdlx PING helloworld.1.ay081uome3eejeg4mspa8pdlx (10.0.0.3): 56 data bytes64 bytes from 10.0.0.3: seq=0 ttl=64 time=0.466 ms64 bytes from 10.0.0.3: seq=1 ttl=64 time=0.465 ms64 bytes from 10.0.0.3: seq=2 ttl=64 time=0.548 ms64 bytes from 10.0.0.3: seq=3 ttl=64 time=0.689 ms^C

可以看到这两个跨主机的服务集群里面各个容器是可以互相连接的。

为了体现 Swarm 集群的优势,我们可以使用虚拟机的 ping 命令来测试对方虚拟机内的容器。

$ docker-machine ssh worker2 ping helloworld.1.ay081uome3eejeg4mspa8pdlxPING helloworld.1.ay081uome3eejeg4mspa8pdlx (221.179.46.190): 56 data bytes64 bytes from 221.179.46.190: seq=0 ttl=63 time=48.651 ms64 bytes from 221.179.46.190: seq=1 ttl=63 time=63.239 ms64 bytes from 221.179.46.190: seq=2 ttl=63 time=47.686 ms64 bytes from 221.179.46.190: seq=3 ttl=63 time=61.232 ms^C$ docker-machine ssh manager1 ping helloworld.2.16cvore0c96rby1vp0sny3mvtPING helloworld.2.16cvore0c96rby1vp0sny3mvt (221.179.46.194): 56 data bytes64 bytes from 221.179.46.194: seq=0 ttl=63 time=30.150 ms64 bytes from 221.179.46.194: seq=1 ttl=63 time=54.455 ms64 bytes from 221.179.46.194: seq=2 ttl=63 time=73.862 ms64 bytes from 221.179.46.194: seq=3 ttl=63 time=53.171 ms^C

上面我们使用了虚拟机内部的 ping 去测试容器的延迟,可以看到延迟明显比集群内部的 ping 值要高。

5. Swarm 集群负载

现在我们已经学会了 Swarm 集群的部署方法,现在来搭建一个可访问的 Nginx 集群吧。体验最新版的 Swarm 所提供的自动服务发现与集群负载功能。
首先删掉上一节我们启动的 helloworld 服务:

$ docker service rm helloworld                                 helloworld

然后在新建一个服务,提供端口映射参数,使得外界可以访问这些 Nginx 服务:

$ docker service create --replicas 2 --name helloworld -p 7080:80 --network=swarm_test nginx:alpine9gfziifbii7a6zdqt56kocyun

查看服务运行状态:

$ docker service ls                                                                                ID           NAME         REPLICAS     IMAGE           COMMAND9gfziifbii7a  helloworld     2/2        nginx:alpine

不知你有没有发现,虽然我们使用 --replicas 参数的值都是一样的,但是上一节中获取服务状态时,REPLICAS 返回的是 0/2,现在的 REPLICAS 返回的是 2/2。
同样使用 docker service ps 查看服务详细状态时(下面输出已经手动调整为更易读的格式),可以看到实例的 CURRENT STATE 中是 Running 状态的,而上一节中的 CURRENT STATE 中全部是处于 Preparing 状态。

$ docker service ps helloworldID          NAME      IMAGE     NODE    DESIRED STATE   CURRENT STATE    ERROR9ikr3agyi...   helloworld.1  nginx:alpine  user-pc    Running         Running 13 seconds ago  7acmhj0u...   helloworld.2  nginx:alpine  worker2    Running         Running 6 seconds ago

这就涉及到 Swarm 内置的发现机制了,目前 Docker 1.12 中 Swarm 已经内置了服务发现工具,我们不再需要像以前使用 Etcd 或者 Consul 这些工具来配置服务发现。对于一个容器来说如果没有外部通信但又是运行中的状态会被服务发现工具认为是 Preparing 状态,本小节例子中因为映射了端口,因此有了 Running 状态。
现在我们来看 Swarm 另一个有趣的功能,当我们杀死其中一个节点时,会发生什么。
首先 kill 掉 worker2 的实例:

$ docker-machine ssh worker2 docker kill helloworld.2.7acmhj0udzusv1d7lu2tbuhu4helloworld.2.7acmhj0udzusv1d7lu2tbuhu4

稍等几秒,再来看服务状态:

$ docker service ps helloworldID         NAME          IMAGE     NODE   DESIRED STATE  CURRENT STATE   ERROR9ikr3agyi...  helloworld.1     nginx:alpine  zuolan-pc  Running       Running 19 minutes ago  8f866igpl...  helloworld.2     nginx:alpine  manager1  Running       Running 4 seconds ago   7acmhj0u...   \_ helloworld.2  nginx:alpine  worker2   Shutdown       Failed 11 seconds ago  ...exit...$ docker service ls           ID            NAME        REPLICAS  IMAGE         COMMAND9gfziifbii7a  helloworld  2/2       nginx:alpine

可以看到即使我们 kill 掉其中一个实例,Swarm 也会迅速把停止的容器撤下来,同时在节点中启动一个新的实例顶上来。这样服务依旧还是两个实例在运行。
此时如果你想添加更多实例可以使用 scale 命令:

$ docker service scale helloworld=3helloworld scaled to 3

查看服务详情,可以看到有三个实例启动了:

$ docker service ps helloworldID         NAME        IMAGE      NODE   DESIRED STATE  CURRENT STATE    ERROR9ikr3agyi...  helloworld.1    nginx:alpine  user-pc   Running        Running 30 minutes ago  8f866igpl...  helloworld.2    nginx:alpine  manager1  Running        Running 11 minutes ago  7acmhj0u...  \_ helloworld.2  nginx:alpine  worker2   Shutdown       Failed 11 minutes ago   exit1371vexr1jm...  helloworld.3    nginx:alpine   worker2   Running       Running 4 seconds ago

现在如果想减少实例数量,一样可以使用 scale 命令:

$ docker service scale helloworld=2helloworld scaled to 2

至此,Swarm的主要用法都已经介绍完了,主要讲述了 Swarm 集群网络的创建与部署。介绍了 Swarm 的常规应用,包括 Swarm 的服务发现、负载均衡等,然后使用 Swarm 来配置跨主机容器网络,并在上面部署应用。

关于Swarm的更多实战例子,以后有机会还会写的,就这样啦。