Swarm是Docker官方提供的一款集群管理工具,其主要作用是把若干台Docker主机抽象为一个整体,并且通过一个入口统一管理这些Docker主机上的各种Docker资源。Swarm和Kubernetes比较类似,具有的功能也较kubernetes更少一些。
基本特性
Docker Swarm具有如下基本特性:
Docker集群管理
使用内置的集群管理功能,可以直接通过Docker CLI命令来创建Swarm集群,然后去部署应用服务,而不再需要其它外部的软件来创建和管理一个Swarm集群。
去中心化设计
Swarm集群中包含Manager和Worker两类Node,可以直接基于Docker Engine来部署任何类型的Node。而且,在Swarm集群运行期间,既可以对其作出任何改变,实现对集群的扩容和缩容等,如添加Manager Node,如删除Worker Node,而做这些操作不需要暂停或重启当前的Swarm集群服务。
服务扩容缩容
对于部署的每一个应用服务,可以通过命令行的方式,设置启动多少个Docker容器去运行它。已经部署完成的应用,如果有扩容或缩容的需求,只需要通过命令行指定需要几个Docker容器即可,Swarm集群运行时便能自动地、灵活地进行调整。
协调预期状态与实际状态的一致性
Swarm集群Manager Node会不断地监控集群的状态,协调集群状态使得预期状态和实际状态保持一致。例如启动了一个应用服务,指定服务副本为10,则会启动10个Docker容器去运行,如果某个Worker Node上面运行的2个Docker容器挂掉了,则Swarm Manager会选择集群中其它可用的Worker Node,并创建2个服务副本,使实际运行的Docker容器数仍然保持与预期的10个一致。
多主机网络
可以为待部署应用服务指定一个Overlay网络,当应用服务初始化或者进行更新时,Swarm Manager在给定的Overlay网络中为Docker容器自动地分配IP地址,实际是一个虚拟IP地址(VIP)。
服务发现
Swarm Manager会给集群中每一个服务分配一个唯一的DNS名称,对运行中的Docker容器进行负载均衡。可以通过Swarm内置的DNS Server,查询Swarm集群中运行的Docker容器状态。
负载均衡
在Swarm内部,可以指定如何在各个Node之间分发服务容器(Service Container),实现负载均衡。如果想要使用Swarm集群外部的负载均衡器,可以将服务容器的端口暴露到外部。
swarm mode中的节点
下面是swarm node的架构图:
manager node
manager node作为整个集群的调度者,负责分配资源、编排容器、分发task、管理各种service
为了保持高可用和容错率,需要保持多个manager node,manager node使用一种Raft一致性算法来保持集群的高可用状态
manager Node也作为一个Worker Node来执行Task,Swarm支持配置Manager只作为一个专用的管理Node
Worker Node
Worker Node不负责维护集群的整体信息
Worker Node接收由Manager Node调度并指派的Task,启动一个Docker容器来运行指定的服务,并且Worker Node需要向Manager Node汇报被指派的Task的执行状态
Swarm集群搭建
搭建如下Swarm集群,包括三个Node,对应的主机名和IP地址分别如下所示,这三台机器是可以互相通信的:
Node | IP |
---|---|
manager | 192.168.33.10 |
worker1 | 192.168.33.11 |
worker2 | 192.168.33.12 |
启动manager节点
使用下面的命令可以创建一个manager节点:
ubuntu@swarm-manager:~$ docker swarm init --advertise-addr 192.168.33.10
Swarm initialized: current node (x579h1dmbuiftl3t0v1bqm5pr) is now a manager.
To add a worker to this swarm, run the following command:
docker swarm join \
--token SWMTKN-1-05k8n988php7b5yl90lz6r8kusfgli5wvm6buc8m3n2tkvsiko-bxnunif1vx4og9s9dmvy8lf0y \
192.168.33.10:2377
To add a manager to this swarm, run 'docker swarm join-token manager' and follow the instructions.
创建manager节点的时候会返回一个token,那个token是worker节点加入集群的token。
启动worker节点
使用如下的命令,可以把worker1、worker2节点加入集群中:
ubuntu@swarm-worker1:~$ docker swarm join --token SWMTKN-1-05k8n988php7b5yl90lz6r8kusfgli5wvm6buc8m3n2tkvsiko-bxnunif1vx4og9s9dmvy8lf0y 192.168.33.10:2377
This node joined a swarm as a worker.
ubuntu@swarm-worker2:~$ docker swarm join --token SWMTKN-1-05k8n988php7b5yl90lz6r8kusfgli5wvm6buc8m3n2tkvsiko-bxnunif1vx4og9s9dmvy8lf0y 192.168.33.10:2377
This node joined a swarm as a worker.
查看节点的状态
ubuntu@swarm-manager:~$ docker node ls
ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS
f9qlbs5mpalab9kj5c9iabc9z swarm-worker1 Ready Active
py76ujrlk3ib7yg475ix98lxv swarm-worker2 Ready Active
x579h1dmbuiftl3t0v1bqm5pr * swarm-manager Ready Active Leader
上面信息中,AVAILABILITY表示Swarm Scheduler是否可以向集群中的某个Node指派Task,对应有如下三种状态:
Active:集群中该Node可以被指派Task
Pause:集群中该Node不可以被指派新的Task,但是其他已经存在的Task保持运行
Drain:集群中该Node不可以被指派新的Task,Swarm Scheduler停掉已经存在的Task,并将它们调度到可用的Node上
Node状态变更管理
Node的AVAILABILITY有三种状态:Active、Pause、Drain,对某个Node进行变更,可以将其AVAILABILITY值通过Docker CLI修改为对应的状态即可,下面是常见的变更操作:
设置Manager Node只具有管理功能
对服务进行停机维护,可以修改AVAILABILITY为Drain状态
暂停一个Node,然后该Node就不再接收新的Task
恢复一个不可用或者暂停的Node
如下,将Manager Node的AVAILABILITY值修改为Drain状态,使其只具备管理功能,执行如下命令:
ubuntu@swarm-manager:~$ docker node update --availability drain x579h1dmbuiftl3t0v1bqm5pr
x579h1dmbuiftl3t0v1bqm5pr
ubuntu@swarm-manager:~$ docker node ls
ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS
f9qlbs5mpalab9kj5c9iabc9z swarm-worker1 Ready Active
py76ujrlk3ib7yg475ix98lxv swarm-worker2 Ready Active
x579h1dmbuiftl3t0v1bqm5pr * swarm-manager Ready Drain Leader
Node提权/降权
改变Node的角色,Worker Node可以变为Manager Node,这样实际Worker Node有工作Node变成了管理Node。如下,将worker1和worker2都升级为Manager Node,执行如下命令:
ubuntu@swarm-manager:~$ docker node promote swarm-worker1 swarm-worker2
Node swarm-worker1 promoted to a manager in the swarm.
Node swarm-worker2 promoted to a manager in the swarm.
ubuntu@swarm-manager:~$
ubuntu@swarm-manager:~$ docker node ls
ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS
f9qlbs5mpalab9kj5c9iabc9z swarm-worker1 Ready Active Reachable
py76ujrlk3ib7yg475ix98lxv swarm-worker2 Ready Active Reachable
x579h1dmbuiftl3t0v1bqm5pr * swarm-manager Ready Drain Leader
对上面已提权的worker1和worker2执行降权,需要执行如下命令:
ubuntu@swarm-manager:~$ docker node demote swarm-worker1 swarm-worker2
Manager swarm-worker1 demoted in the swarm.
Manager swarm-worker2 demoted in the swarm.
ubuntu@swarm-manager:~$
ubuntu@swarm-manager:~$ docker node ls
ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS
f9qlbs5mpalab9kj5c9iabc9z swarm-worker1 Ready Active
py76ujrlk3ib7yg475ix98lxv swarm-worker2 Ready Active
x579h1dmbuiftl3t0v1bqm5pr * swarm-manager Ready Drain Leader
退出Swarm集群
如果Worker想要退出Swarm集群,在Worker Node上,执行如下命令:
ubuntu@swarm-worker1:~$ docker swarm leave
Node left the swarm.
在manager节点上查看节点的信息,可以看到worker1状态为DOWN
ubuntu@swarm-manager:~$ docker node ls
ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS
f9qlbs5mpalab9kj5c9iabc9z swarm-worker1 Down Active
py76ujrlk3ib7yg475ix98lxv swarm-worker2 Ready Active
x579h1dmbuiftl3t0v1bqm5pr * swarm-manager Ready Drain Leader
如果Manager想要退出Swarm集群,但是集群中还存在其它的Worker Node,则需要加上一个强制选项:
ubuntu@swarm-manager:~$ docker swarm leave --force
Node left the swarm.
管理服务
在Swarm mode下使用Docker,可以实现部署运行服务、服务扩容缩容、删除服务、滚动更新等功能,在Swarm集群上部署服务,必须在Manager Node上进行操作。下图是Service、Task、Container(容器)这个三个概念的关系:
创建服务
首先要启动Swarm集群,使用了如下的命令创建了一个demo的service:
ubuntu@swarm-manager:~$ docker service create --name demo busybox sh -c "while true; do sleep 3600; done"
qbju4in1fqq5oa7j67ff2pp48
查看服务
可以看到当前的demo service运行在swarm-manager节点上:
ubuntu@swarm-manager:~$ docker service ls
ID NAME MODE REPLICAS IMAGE
qbju4in1fqq5 demo replicated 1/1 busybox:latest
ubuntu@swarm-manager:~$ docker service ps demo
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS
968zbp0nz05k demo.1 busybox:latest swarm-manager Running Running 2 minutes ago
ubuntu@swarm-manager:~$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
1f2d80f554ca busybox@sha256:2a03a6059f21e150ae84b0973863609494aad70f0a80eaeb64bddd8d92465812 "sh -c 'while true..." 4 minutes ago Up 4 minutes demo.1.968zbp0nz05kahew3pp2y4j4c
扩容缩容服务
Docker Swarm支持服务的扩容缩容,可以replicated模式指定服务Task的个数,如下命令将demo service水平扩容成5个:
ubuntu@swarm-manager:~$ docker service scale demo=5
demo scaled to 5
ubuntu@swarm-manager:~$
ubuntu@swarm-manager:~$ docker service ls
ID NAME MODE REPLICAS IMAGE
qbju4in1fqq5 demo replicated 5/5 busybox:latest
ubuntu@swarm-manager:~$ docker service ps demo
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS
968zbp0nz05k demo.1 busybox:latest swarm-manager Running Running 9 minutes ago
1mgc8aj4mkoy demo.2 busybox:latest swarm-worker1 Running Running 57 seconds ago
7l49mkwuhoym demo.3 busybox:latest swarm-worker2 Running Running 43 seconds ago
ho68t3g7sf2p demo.4 busybox:latest swarm-worker2 Running Running 43 seconds ago
so3ajlroy35j demo.5 busybox:latest swarm-manager Running Running 57 seconds ago
可以看到在swarm-manager和swarm-worker2有两个service、swarm-worker1有一个service。如在swarm-worker2节点上使用docker ps
,可以看到有个demo容器在运行:
ubuntu@swarm-worker2:~$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
ee77dc7037b3 busybox@sha256:2a03a6059f21e150ae84b0973863609494aad70f0a80eaeb64bddd8d92465812 "sh -c 'while true..." 2 minutes ago Up 2 minutes demo.3.7l49mkwuhoymkxq5yr72qaa8z
c036b5ad902d busybox@sha256:2a03a6059f21e150ae84b0973863609494aad70f0a80eaeb64bddd8d92465812 "sh -c 'while true..." 2 minutes ago Up 2 minutes demo.4.ho68t3g7sf2pk7cp4bt8l9q5y
如果把swarm-worker2节点上其中一个容器删除,Swarm Manager会选择集群中其它可用的节点,再创建一个服务,使实际运行的Docker容器数仍然保持与预期的5个一致:
ubuntu@swarm-manager:~$ docker service ls
ID NAME MODE REPLICAS IMAGE
qbju4in1fqq5 demo replicated 4/5 busybox:latest
ubuntu@swarm-manager:~$
ubuntu@swarm-manager:~$ docker service ls
ID NAME MODE REPLICAS IMAGE
qbju4in1fqq5 demo replicated 5/5 busybox:latest
ubuntu@swarm-manager:~$ docker service ps demo
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS
968zbp0nz05k demo.1 busybox:latest swarm-manager Running Running 19 minutes ago
1mgc8aj4mkoy demo.2 busybox:latest swarm-worker1 Running Running 11 minutes ago
7l49mkwuhoym demo.3 busybox:latest swarm-worker2 Running Running 10 minutes ago
p1a2gc7in33s demo.4 busybox:latest swarm-worker2 Running Running 52 seconds ago
ho68t3g7sf2p \_ demo.4 busybox:latest swarm-worker2 Shutdown Failed 57 seconds ago "task: non-zero exit (137)"
so3ajlroy35j demo.5 busybox:latest swarm-manager Running Running 11 minutes ago
在swarm-worker2节点上删除了一个服务后,最终在swarm-worker2节点上启动了一个新的服务。
缩容服务: 只需要将副本数小于当前应用服务拥有的副本数即可实现,大于指定缩容副本数的副本会被删除。
删除服务
使用下面的命令即可把服务删除:
ubuntu@swarm-manager:~$ docker service rm demo
demo
Swarm部署服务的例子
如下使用Swarm部署Dcoker Compose那节中使用的flask app的例子:
首先使用Dockerfile build一个flaskredis_web的image,要把image push到自己的hub里面,因为在部署的时候Swarm如果发现本机没有相应的image,就会从hub里面拉取,如果hub里面不存在,则会报错:
ubuntu@swarm-manager:~/flask-redis$ docker build -t heqingliang/flaskredis_web .
创建一个overlay网络:
ubuntu@swarm-manager:~/flask-redis$ docker network create -d overlay demo
bp3clp7ooa8bl2rpmqvd1b1um
ubuntu@swarm-manager:~/flask-redis$ docker network ls
NETWORK ID NAME DRIVER SCOPE
de6c660c5569 bridge bridge local
bp3clp7ooa8b demo overlay swarm
ff50d198b5dc docker_gwbridge bridge local
65e22acf0beb host host local
wdh4p4u1ch9w ingress overlay swarm
ba700ffa1e8f my-bridge bridge local
c305a4b53c3b none null local
创建redis服务:
ubuntu@swarm-manager:~/flask-redis$ docker service create --name redis --network demo redis
td7e95h7jhwmraziiy7f8p8u3
ubuntu@swarm-manager:~/flask-redis$ docker service ps redis
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS
6ol4i4fv1u92 redis.1 redis:latest swarm-manager Running Running 16 seconds ago
创建web服务,可以看到falsk-web服务运行在worker1节点:
ubuntu@swarm-manager:~/flask-redis$ docker service create --name flask-web -p 5000:5000 --network demo --env REDIS_HOST=redis heqingliang/flaskredis_web
ubuntu@swarm-manager:~/flask-redis$ docker service ps flask-web
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS
cjh5ku96wtj9 flask-web.1 heqingliang/flaskredis_web swarm-worker1 Running Running about a minute ago
访问flask-web服务, 虽然falsk-web服务运行在swarm-worker1节点,但是访问集群中的任意一个节点的5000端口都可以,其他节点会转发到swarm-worker1节点:
ubuntu@swarm-manager:~/flask-redis$ curl 192.168.33.11:5000
<h1>Hello Container, I have been seen b'1' times.</h1>
ubuntu@swarm-manager:~/flask-redis$ curl 192.168.33.11:5000
<h1>Hello Container, I have been seen b'2' times.
ubuntu@swarm-manager:~/flask-redis$
ubuntu@swarm-manager:~/flask-redis$ curl 192.168.33.10:5000
<h1>Hello Container, I have been seen b'3' times.</h1>
ubuntu@swarm-manager:~/flask-redis$ curl 192.168.33.10:5000
<h1>Hello Container, I have been seen b'4' times.</h1>
ubuntu@swarm-manager:~/flask-redis$
ubuntu@swarm-manager:~/flask-redis$ curl 192.168.33.12:5000
<h1>Hello Container, I have been seen b'5' times.</h1>