本教程将介绍 Docker Engine Swarm 模式。先介绍 swarm 模式几个关键的概念,然后通过动手实践带你体验一下 swarm 模式。
Docker Engline 中集成的集群管理和编排功能都是基于 SwarmKit 实现。参与到集群中的 Docker Engine 会进入 swarm 模式。比如初始化一个 swarm 或加入已有的 swarm。
一个 swarm 就是个一个 Docker Engine 集群,你可以在上面部署服务。Docker Engine CLI 提供了用于 swarm 管理的命令,比如添加或移除一个节点。同样还提供了用于部署服务到 swarm 和管理服务编排的命令。
当 Docker Engine 运行在 swarm 模式时,你管理容器。当 Docker Engine 运行在 swarm 模式时,你编排服务。
每个参与到 swarm 中的 Docker Engine 都称之为一个节点。
将服务的定义提交到管理节点即可将应用部署到 swarm。然后管理节点将叫作任务的工作单元分发到工作节点。
为了维持 swarm 的目标状态,管理节点还将承当编排和集群管理的功能。一般有多个管理节点,它们之间会选出一个领导来进行编排任务。
工作节点接收并执行来自管理节点分发的任务。默认情况下,管理节点也是工作节点,你可以把它配置成只当管理节点。代理通知管理节点已分配任务的当前状态,以便管理节点维护所需的状态。
服务定义了需要在工作节点上执行的任务。它是 swarm 系统的中心结构,也是用户和 swarm 交互的主要根源。
服务包括要使用的容器镜像,以及在容器中执行的指令。
对于复制服务,管理节点根据服务的规模和目标状态将一定数量的任务副本分发到各节点上。
对于全局服务,每个节点上都将分发一个任务副本。
任务包含一个容器和需要在容器中执行的指令。它是 swarm 原子调度单位。管理节点根据服务规模中定义的副本数量将任务分配给工作节点。一旦某个任务被分配到某个节点,就不能再移动到其他节点。它只能在分配的节点上运行或者失败。
swarm 管理节点使用 入口负载均衡 的方式暴露你想要让外部访问的服务。Swarm 管理节点可以自动将一个服务分配到某个 发布端口,或者你可以为服务指定一个发布端口。你可以指定任意未使用的端口。如果你没指定端口,swarm 管理节点将为服务指定一个 30000-32757 之间的端口。
外部组件,比如云负载均衡器,可以通过集群中的任意节点访问发布端口上的服务,不管当前节点上是否有服务对应的任务在运行,swarm 中的所有节点都会将进入连接路由到正在运行任务的实例上。
Swarm 模式有一个内置的 DNS 组件,它会自动给 swarm 中的每个服务分配一个 DNS 条目。Swarm 管理器使用internal load balancing 基于服务对应的 DNS 名称在服务之间分发请求。
本教程将指导你完成以下任务:
在 Docker Engline swarm 模式下初始化一个集群
添加节点到 swarm
部署服务到 swarm
在一切就绪后管理 swarm
在开始本教程之前,你需要准备一下几样东西:
三台通过网络连接的主机
每台主机安装 Docker Engine 1.12 或更新版本
充当管理节点的主机 IP
主机之间开放下面提到的端口
主机之间的以下端口必须是开放。某些环境下,这些端口默认是允许的:
TCP 端口 2377 用于集群管理通信(管理节点)
TCP 和 UDP 端口 7946 用于节点间通信(所有节点)
TCP 和 UDP 端口 4789 用于 overlay 网络流量(所有节点)
如果你的这些端口没有打开,可以用iptables
命令打开它们:
iptables -A INPUT -p tcp --dport 2377 -j ACCEPT iptables -A INPUT -p tcp --dport 7946 -j ACCEPT iptables -A INPUT -p udp --dport 7946 -j ACCEPT iptables -A INPUT -p tcp --dport 4789 -j ACCEPT iptables -A INPUT -p udp --dport 4789 -j ACCEPT
192.168.33.160 swarm_manager
192.168.33.161 node1
192.168.33.162 node2
随意选择一个主机作为管理节点,在上面初始化一个 swarm:
[root@swarm_manager ~]# docker swarm init --advertise-addr 192.168.33.160 Swarm initialized: current node (7ik7wqhe5wcag8k5tp816c7ck) is now a manager. To add a worker to this swarm, run the following command: docker swarm join \ --token SWMTKN-1-0p0p5f96e1w4xblhw2eeookrv46spwf4yx7qmve2srxe9wec5g-ellbnyt4cwwvvdkssaj0cbtus 192.168.33.160:2377
--advertise-addr
标志配置了管理节点的 IP 地址。如果你的机器只有一个 IP 地址,可以省略--adbertise-addr
选项,docker 会自动选择正确的 IP。上输出信息说明了怎样加入新的工作节点。也说明了执行docker swarm join-token manager
可以查询怎样加入新的管理节点。
docker info
命令查看swarm
的当前状态[root@swarm_manager ~]# docker info ... Swarm: active NodeID: 7ik7wqhe5wcag8k5tp816c7ck Is Manager: true ClusterID: 2scd04fv8c9mua1jiaq6n0370 Managers: 1 Nodes: 1 ... 执行 docker node ls 命令查看节点信息 [root@swarm_manager ~]# docker node ls ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS 9e21bk67ey1abzje69lmpvbe1 * swarm_manager Ready Active Leader
节点 id 后面的*
表示你当前连接到了该节点。
swarm
在第二台主机上,执行前面创建 swarm
时 docker swarm init
输出信息中命令创建工作节点并加入到 swarm
[root@node1 ~]# docker swarm join \ --token SWMTKN-1-0p0p5f96e1w4xblhw2eeookrv46spwf4yx7qmve2srxe9wec5g-ellbnyt4cwwvvdkssaj0cbtus 192.168.33.160:2377 This node joined a swarm as a worker.
输出信息表示当前节点已是 swarm
中的一个工作节点了。如果你忘记了该命令,可以在管理节点上执行 docker swarm join-token worker
查询怎么加入。
[root@swarm_manager ~]# docker swarm join-token worker To add a worker to this swarm, run the following command: docker swarm join \ --token SWMTKN-1-3wi7tszkolocsbc7vopv1tfx2r2h1owtqegwevdqqdk3fj195u-ejpeq0afjvfmujlvzboux9zjs 192.168.33.160:2377
到第三台主机上,继续讲第三台主机加入到 swarm
中
[root@node1 ~]# docker swarm join \ --token SWMTKN-1-0p0p5f96e1w4xblhw2eeookrv46spwf4yx7qmve2srxe9wec5g-ellbnyt4cwwvvdkssaj0cbtus 192.168.59.128:2377 This node joined a swarm as a worker.
在管理节点上
[root@swarm_manager ~]# docker node ls
ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS
622ih8ji5t428lazjx233pvks node2 Ready Active
9e21bk67ey1abzje69lmpvbe1 * swarm_manager Ready Active Leader
f3wzagmtgsn8qyqzidxtw98d3 node1 Ready Active
输出信息第二行 id 后面的*
表示当前连接到了该节点。HOSTNAME
栏输出节点的 hostname。MANAGER
用于指示 swarm
中的管理节点,该栏值为 Leader
表示为管理节点,空值表示为工作节点。
swarm
在管理节点上创建一个服务,每隔三秒输出一个 “hello world”:
[root@swarm_manager ~]# docker service create --replicas 1 --name helloworld busybox:1.25.1-musl /bin/sh -c "while true; do echo hello world; sleep 3; done" 04a3iqg8zlhba84kpi2tatssf
docker service create
命令创建服务。
--name
标志将服务命名为helloworld
。
--replicas
标志指定了期望状态为 1 个运行示例。
参数 busybox:1.25.1-musl /bin/sh -c "while true; do echo hello world; sleep 3; done
将服务定义为使用镜像busybox:1.25.1-musl
创建容器,并在里面执行 /bin/sh -c "while true; do echo hello world; sleep 3; done
。
还是在管理节点上
[root@swarm_manager ~]# docker service ls ID NAME REPLICAS IMAGE COMMAND c3hvgwhyim4n helloworld 1/1 busybox:1.25.1-musl /bin/sh -c while true; do echo hello world; sleep 3; done
在管理节点上。
[root@swarm_manager ~]# docker service inspect --pretty helloworld ID: c3hvgwhyim4nllg1qqix7kli6 Name: helloworld Mode: Replicated Replicas: 1 Placement: UpdateConfig: Parallelism: 1 On failure: pause ContainerSpec: Image: busybox:1.25.1-musl Args: /bin/sh -c while true; do echo hello world; sleep 3; done Resources:
参数--pretty
表示以可读性良好的格式输出。如果想输出详细的 json 格式信息,去掉--pretty
参数即可。
还是在管理节点上:
[root@swarm_manager ~]# docker service ps helloworld ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR 556c2lpvr4489yrclo52cjlo5 helloworld.1 busybox:1.25.1-musl node2 Running Running 3 minutes ago
输出信息表明,helloworld
服务的一个实例在 node2 节点上执行。这是因为,默认情况下管理节点是工作节点。
DESIRED STATE
和CURRENT STATE
表示服务的期望状态和当前状态,你可以对比它们,判断服务是否想期望的那样运行。这里的Running
和Running 3 minutes ago
说明服务运行正常。
docker ps
命令查看相关容器的详细信息[root@node2 ~]# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 964ddb3220b6 busybox:1.25.1-musl "/bin/sh -c ‘while tr" 5 minutes ago Up 5 minutes helloworld.1.556c2lpvr4489yrclo52cjlo5
在管理节点上
[root@node2 ~]# docker service scale helloworld=5 helloworld scaled to 5 我们将服务的数量伸缩到5。
在管理节点上:
[root@swarm_manager ~]# docker service ps helloworld ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR 556c2lpvr4489yrclo52cjlo5 helloworld.1 busybox:1.25.1-musl node2 Running Running 10 minutes ago e2tw7i9bkjb32jrr3sdztskwe helloworld.2 busybox:1.25.1-musl swarm_manager Running Running 24 seconds ago d5plppbjvtr1rany4tzb88czc helloworld.3 busybox:1.25.1-musl node2 Running Running 28 seconds ago a0hs8ik837jl7mlgeaowws1i3 helloworld.4 busybox:1.25.1-musl node1 Running Running 18 seconds ago bo27jnf7n59hqzl9m9jnpwbks helloworld.5 busybox:1.25.1-musl swarm_manager Running Running 24 seconds ago
首先是管理节点:
[root@swarm_manager ~]# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 46aa83031ad7 busybox:1.25.1-musl "/bin/sh -c ‘while tr" About a minute ago Up About a minute helloworld.2.e2tw7i9bkjb32jrr3sdztskwe e1cb3bd1bfb0 busybox:1.25.1-musl "/bin/sh -c ‘while tr" About a minute ago Up About a minute helloworld.5.bo27jnf7n59hqzl9m9jnpwbks
再是工作节点1
[root@node1 ~]# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 1c200722ace5 busybox:1.25.1-musl "/bin/sh -c ‘while tr" About a minute ago Up About a minute helloworld.4.a0hs8ik837jl7mlgeaowws1i3
再是工作节点2
[root@node2 ~]# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 2dba702ccd68 busybox:1.25.1-musl "/bin/sh -c ‘while tr" About a minute ago Up About a minute helloworld.3.d5plppbjvtr1rany4tzb88czc 964ddb3220b6 busybox:1.25.1-musl "/bin/sh -c ‘while tr" 11 minutes ago Up 11 minutes helloworld.1.556c2lpvr4489yrclo52cjlo5
可以看到:管理节点上运行了两个任务,工作节点1运行了两个任务,工作节点2运行了1个任务。
swarm
上运行的服务在管理节点上
[root@swarm_manager ~]# docker service rm helloworld
helloworld
在管理节点上
[root@swarm_manager ~]# docker service ls
ID NAME REPLICAS IMAGE COMMAND
[root@swarm_manager ~]#
看不到任何服务了。
在这部分,我们将部署一个基于 Rddis 3.07 镜像的服务。然后使用滚动更新将服务更新到使用 Redis 3.2.5 镜像。
swarm
中部署 Redis 3.0.7,并配置 10 秒更新延迟[root@swarm_manager ~]# docker service create --replicas 3 --name redis --update-delay 10s redis:3.0.7-alpine 6vw26iief1y2nxmi6a01tzco6
我们在部署服务指定滚动更新策略。--update-delay
表示更新服务对应的任务或一组任务之间的时间间隔。时间间隔用数字和时间单位表示,m 表示分,h 表示时,所以 10m30s 表示 10 分 30 秒的延时。
默认情况下,调度器一次更新一个任务。你可以使用 --update-parallelism
标志配置调度器每次同时更新的最大任务数量。
默认情况下,如果更新某个任务返回了RUNNING
状态,调度器会转去更新另一个任务,直到所有任务都更新完成。如果在更新某个任务的任意时刻返回了FAILED
,调度器暂停更新。我们可以在执行 docker service create
命令和 docker service update
命令时使用 --update-failure-action
标志来覆盖这种默认行为。
redis
服务[root@swarm_manager ~]# docker service inspect --pretty redis ID: 6vw26iief1y2nxmi6a01tzco6 Name: redis Mode: Replicated Replicas: 3 Placement: UpdateConfig: Parallelism: 1 Delay: 10s On failure: pause ContainerSpec: Image: redis:3.0.7-alpine Resources:
redis
服务使用的容器镜像swarm
管理节点会根据UpdateConfig
策略来更新节点
[root@swarm_manager ~]# docker service update --image redis:3.2.5-alpine redis redis
调度器根据下面默认的策略来应用滚动更新:
停止第一个任务。
为停止的任务应用更新。
为更新的任务启动容器。
如果更新任务时返回RUNNING
,等待一个指定的延时后停止下一个任务。
如果,在更新的任意时刻,某个任务返回FAILED
,暂停更新。
[root@swarm_manager ~]# docker service update --image redis:3.2.5-alpine redis redis [root@swarm_manager ~]# docker service inspect --pretty redis ID: 6vw26iief1y2nxmi6a01tzco6 Name: redis Mode: Replicated Replicas: 3 Update status: State: updating Started: 46 seconds ago Message: update in progress Placement: UpdateConfig: Parallelism: 1 Delay: 10s On failure: pause ContainerSpec: Image: redis:3.2.5-alpine Resources:
可以看到 redis 服务的镜像已经变成了redis:3.2.5-alpine
。不过状态还在更新中。过一会再查看:
[root@swarm_manager ~]# docker service inspect --pretty redis ID: 6vw26iief1y2nxmi6a01tzco6 Name: redis Mode: Replicated Replicas: 3 Update status: State: completed Started: 2 minutes ago Completed: about a minute ago Message: update completed Placement: UpdateConfig: Parallelism: 1 Delay: 10s On failure: pause ContainerSpec: Image: redis:3.2.5-alpine Resources:
可以看到更新完成。
[root@swarm_manager ~]# docker service ps redis ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR e69zhhxz66jmlm0h15gj89s2x redis.1 redis:3.2.5-alpine swarm_manager Running Running 2 minutes ago 63h5wy36474k01vmr5jppbbxs \_ redis.1 redis:3.0.7-alpine node1 Shutdown Shutdown 2 minutes ago 1h9e8m9v3rx3hgx5x2bn71kim redis.2 redis:3.2.5-alpine node2 Running Running 3 minutes ago 39jitd0mzztl0mpy6k6rppkx5 \_ redis.2 redis:3.0.7-alpine swarm_manager Shutdown Shutdown 3 minutes ago 8pwrkq6558fwp8oiiu0uq484h redis.3 redis:3.2.5-alpine node1 Running Running about a minute ago 6usd4p2mj7p597ilgs490ou7a \_ redis.3 redis:3.0.7-alpine node2 Shutdown Shutdown 2 minutes ago
可以看到有三个镜像为redis:3.0.7-alpine
的任务状态为Shutdown
,三个镜像为redis:3.2.5-alpine
的任务状态为Running
。说明滚动更新已完成。
再看看容器信息
[root@swarm_manager ~]# docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES f7c5ebb8678b redis:3.2.5-alpine "docker-entrypoint.sh" 4 minutes ago Up 4 minutes 6379/tcp redis.1.e69zhhxz66jmlm0h15gj89s2x 524aadad84b8 redis:3.0.7-alpine "docker-entrypoint.sh" 7 minutes ago Exited (0) 5 minutes ago redis.2.39jitd0mzztl0mpy6k6rppkx5
可以看出更新后,swarm
并没有删除旧的容器。
在前面的步骤中,所有的节点都处于运行状态且可用性为ACTIVE
。swarm 管理器可以将任务分配给任何可用性为 ACTIVE
的节点,所以到目前为止,所有节点都可以接收任务。
有时候,比如到了计划的维护时间,你需要将节点的可用性设为DRAIN
。可用性为DRAIN
的节点不会从 swarm 接收任何新任务。同时,管理器将停止运行在该节点上的任务,并在另外可用性为 ACTIVE
的节点上启动相应的任务副本。
[root@swarm_manager ~]# docker node ls ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS 622ih8ji5t428lazjx233pvks node2 Ready Active 9e21bk67ey1abzje69lmpvbe1 * swarm_manager Ready Active Leader f3wzagmtgsn8qyqzidxtw98d3 node1 Ready Active
将分配了任务的工作节点node2
下线:
[root@swarm_manager ~]# docker node update --availability drain node2 node2
[root@swarm_manager ~]# docker node ls ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS 622ih8ji5t428lazjx233pvks node2 Ready Drain 9e21bk67ey1abzje69lmpvbe1 * swarm_manager Ready Active Leader f3wzagmtgsn8qyqzidxtw98d3 node1 Ready Active [root@swarm_manager ~]# docker node inspect --pretty node2 ID: 622ih8ji5t428lazjx233pvks Hostname: node2 Joined at: 2017-10-25 06:45:04.369968305 +0000 utc Status: State: Ready Availability: Drain Platform: Operating System: linux Architecture: x86_64 Resources: CPUs: 1 Memory: 985.6 MiB Plugins: Network: bridge, host, null, overlay Volume: local Engine Version: 1.12.6
可以看到该节点的状态为Ready
,但可用性为Drain
。
[root@swarm_manager ~]# docker service ps redis ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR e69zhhxz66jmlm0h15gj89s2x redis.1 redis:3.2.5-alpine swarm_manager Running Running 8 minutes ago 63h5wy36474k01vmr5jppbbxs \_ redis.1 redis:3.0.7-alpine node1 Shutdown Shutdown 9 minutes ago 6q046y1camb43b146kj2jaxe4 redis.2 redis:3.2.5-alpine node1 Running Running about a minute ago 1h9e8m9v3rx3hgx5x2bn71kim \_ redis.2 redis:3.2.5-alpine node2 Shutdown Shutdown about a minute ago 39jitd0mzztl0mpy6k6rppkx5 \_ redis.2 redis:3.0.7-alpine swarm_manager Shutdown Shutdown 9 minutes ago 8pwrkq6558fwp8oiiu0uq484h redis.3 redis:3.2.5-alpine node1 Running Running 8 minutes ago 6usd4p2mj7p597ilgs490ou7a \_ redis.3 redis:3.0.7-alpine node2 Shutdown Shutdown 8 minutes ago
[root@swarm_manager ~]# docker node update --availability active node2 node2
[root@swarm_manager ~]# docker node ls ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS 622ih8ji5t428lazjx233pvks node2 Ready Active 9e21bk67ey1abzje69lmpvbe1 * swarm_manager Ready Active Leader f3wzagmtgsn8qyqzidxtw98d3 node1 Ready Active
说明现在该节点又可以重新接收任务了。
再看看 node2
节点上是否被分配了任务:
[root@swarm_manager ~]# docker service ps -f desired-state=running redis ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR e69zhhxz66jmlm0h15gj89s2x redis.1 redis:3.2.5-alpine swarm_manager Running Running 10 minutes ago 6q046y1camb43b146kj2jaxe4 redis.2 redis:3.2.5-alpine node1 Running Running 2 minutes ago 8pwrkq6558fwp8oiiu0uq484h redis.3 redis:3.2.5-alpine node1 Running Running 9 minutes ago
desired-state
表示只列出处于活动状态的任务。说明 node2虽然可用,但没被分配任务。
一个可用性为Active
的节点在以下情况下可以接收到新任务:
当一个服务在伸缩规模时
滚动更新时
当你把其他某个节点的可用性设为 Drain
时
当某个任务在另外某个 Active
节点上启动失败时
原文:http://chentianwang.blog.51cto.com/9250930/1976021