Docker集群管理和编排的特性是经过SwarmKit进行构建的, 其中Swarm mode是Docker Engine内置支持的一种默认实现。Docker 1.12以及更新的版本,都支持Swarm mode,咱们能够基于Docker Engine来构建Swarm集群,而后就能够将咱们的应用服务(Application Service)部署到Swarm集群中。建立Swarm集群的方式很简单,先初始化一个Swarm集群,而后将其余的Node加入到该集群便可。本文主要基于Docker Swarm官网文档,学习总结。
基本特性
Docker Swarm具备以下基本特性:
集群管理集成进Docker Engine前端
使用内置的集群管理功能,咱们能够直接经过Docker CLI命令来建立Swarm集群,而后去部署应用服务,而再也不须要其它外部的软件来建立和管理一个Swarm集群。
去中心化设计node
Swarm集群中包含Manager和Worker两类Node,咱们能够直接基于Docker Engine来部署任何类型的Node。并且,在Swarm集群运行期间,咱们既能够对其做出任何改变,实现对集群的扩容和缩容等,如添加Manager Node,如删除Worker Node,而作这些操做不须要暂停或重启当前的Swarm集群服务。
声明式服务模型(Declarative Service Model)linux
在咱们实现的应用栈中,Docker Engine使用了一种声明的方式,让咱们能够定义咱们所指望的各类服务的状态,例如,咱们建立了一个应用服务栈:一个Web前端服务、一个后端数据库服务、Web前端服务又依赖于一个消息队列服务。
服务扩容缩容nginx
对于咱们部署的每个应用服务,咱们能够经过命令行的方式,设置启动多少个Docker容器去运行它。已经部署完成的应用,若是有扩容或缩容的需求,只须要经过命令行指定须要几个Docker容器便可,Swarm集群运行时便能自动地、灵活地进行调整。
协调预期状态与实际状态的一致性web
Swarm集群Manager Node会不断地监控集群的状态,协调集群状态使得咱们预期状态和实际状态保持一致。例如咱们启动了一个应用服务,指定服务副本为10,则会启动10个Docker容器去运行,若是某个Worker Node上面运行的2个Docker容器挂掉了,则Swarm Manager会选择集群中其它可用的Worker Node,并建立2个服务副本,使实际运行的Docker容器数仍然保持与预期的10个一致。
多主机网络redis
咱们能够为待部署应用服务指定一个Overlay网络,当应用服务初始化或者进行更新时,Swarm Manager在给定的Overlay网络中为Docker容器自动地分配IP地址,实际是一个虚拟IP地址(VIP)。
服务发现docker
Swarm Manager会给集群中每个服务分配一个惟一的DNS名称,对运行中的Docker容器进行负载均衡。咱们能够经过Swarm内置的DNS Server,查询Swarm集群中运行的Docker容器状态。
负载均衡数据库
在Swarm内部,能够指定如何在各个Node之间分发服务容器(Service Container),实现负载均衡。若是想要使用Swarm集群外部的负载均衡器,能够将服务容器的端口暴露到外部。
安全策略后端
在Swarm集群内部的Node,强制使用基于TLS的双向认证,而且在单个Node上以及在集群中的Node之间,都进行安全的加密通讯。咱们能够选择使用自签名的根证书,或者使用自定义的根CA(Root CA)证书。
滚动更新(Rolling Update)安全
对于服务须要更新的场景,咱们能够在多个Node上进行增量部署更新,Swarm Manager支持经过使用Docker CLI设置一个delay时间间隔,实现多个服务在多个Node上依次进行部署。这样能够很是灵活地控制,若是有一个服务更新失败,则暂停后面的更新操做,从新回滚到更新以前的版本。
基本架构
Docker Swarm提供了基本的集群能力,可以使多个Docker Engine组合成一个group,提供多容器服务。Swarm使用标准的Docker API,启动容器能够直接使用docker run命令。Swarm更核心的则是关注如何选择一个主机并在其上启动容器,最终运行服务。
Docker Swarm基本架构,以下图所示(来自网络,详见后面参考连接):
如上图所示,Swarm Node表示加入Swarm集群中的一个Docker Engine实例,基于该Docker Engine能够建立并管理多个Docker容器。其中,最开始建立Swarm集群的时候,Swarm Manager即是集群中的第一个Swarm Node。在全部的Node中,又根据其职能划分为Manager Node和Worker Node,具体分别以下所示:
Manager Node
Manager Node负责调度Task,一个Task表示要在Swarm集群中的某个Node上启动Docker容器,一个或多个Docker容器运行在Swarm集群中的某个Worker Node上。同时,Manager Node还负责编排容器和集群管理功能(或者更准确地说,是具备Manager管理职能的Node),维护集群的状态。须要注意的是,默认状况下,Manager Node也做为一个Worker Node来执行Task。Swarm支持配置Manager只做为一个专用的管理Node,后面咱们会详细说明。
Worker Node
Worker Node接收由Manager Node调度并指派的Task,启动一个Docker容器来运行指定的服务,而且Worker Node须要向Manager Node汇报被指派的Task的执行状态。
构建Swarm集群
咱们实践Swarm集群,包括三个节Node,对应的主机名和IP地址分别以下所示:
manager 192.168.1.107worker1 192.168.1.108worker2 192.168.1.109
首先,须要保证各个Node上,docker daemon进程已经正常启动,若是没有则执行以下命令启动:
systemctl start docker
接下来就能够建立Swarm集群,建立Swarm的命令,格式以下所示:
docker swarm init --advertise-addr <MANAGER-IP>
咱们在准备好的manager Node上,登陆到该Node,建立一个Swarm,执行以下命令:
docker swarm init --advertise-addr 192.168.1.107
上面–advertise-addr选项指定Manager Node会publish它的地址为192.168.1.107,后续Worker Node加入到该Swarm集群,必需要可以访问到Manager的该IP地址。能够看到,上述命令执行结果,以下所示:
Swarm initialized: current node (5pe2p4dlxku6z2a6jnvxc4ve6) is now a manager.To add a worker to this swarm, run the following command: docker swarm join \ --token SWMTKN-1-4dm09nzp3xic15uebqja69o2552b75pcg7or0g9t2eld9ehqt3-1kb79trnv6fbydvl9vif3fsch \ 192.168.1.107:2377To add a manager to this swarm, run 'docker swarm join-token manager' and follow the instructions.
该结果中给出了后续操做引导信息,告诉咱们如何将一个Worker Node加入到Swarm集群中。也能够经过以下命令,来获取该提示信息:
docker swarm join-token worker
在任什么时候候,若是咱们须要向已经建立的Swarm集群中增长Worker Node,只要新增一个主机(物理机、云主机等均可以),并在其上安装好Docker Engine并启动,而后执行上述docker swarm join命令,就能够加入到Swarm集群中。
这时,咱们也能够查看当前Manager Node的基本信息,执行docker info命令,输出信息中能够看到,包含以下关于Swarm的状态信息:
Swarm: active NodeID: qc42f6myqfpoevfkrzmx08n0r Is Manager: true ClusterID: qi4i0vh7lgb60qxy3mdygb27f Managers: 1 Nodes: 1
能够看出,目前Swarm集群只有Manager一个Node,并且状态是active。也能够在Manager Node上执行docker node ls命令查看Node状态,以下所示:
ID HOSTNAME STATUS AVAILABILITY MANAGER STATUSqc42f6myqfpoevfkrzmx08n0r manager Ready Active Leader
接下来,咱们能够根据上面提示信息,咱们分别在worker一、worker2两个Worker Node 上,执行命令将Worker Node加入到Swarm集群中,命令以下所示:
docker swarm join \ --token SWMTKN-1-4dm09nzp3xic15uebqja69o2552b75pcg7or0g9t2eld9ehqt3-1kb79trnv6fbydvl9vif3fsch \ 192.168.1.107:2377
若是成功,能够看到成功加入Swarm集群的信息。这时,也能够在Manager Node上,查看Swarm集群的信息,示例以下所示:
Swarm: active NodeID: qc42f6myqfpoevfkrzmx08n0r Is Manager: true ClusterID: qi4i0vh7lgb60qxy3mdygb27f Managers: 1 Nodes: 3
想要查看Swarm集群中所有Node的详细状态信息,能够执行以下所示命令:
docker node ls
Swarm集群Node的状态信息,以下所示:
ID HOSTNAME STATUS AVAILABILITY MANAGER STATUSoibbiiwrgwjkw0ni38ydrfsre worker1 Ready Active oocli2uzdt2hy6o50g5z6j7dq worker2 Ready Active qc42f6myqfpoevfkrzmx08n0r 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上执行以下命令:
docker node inspect self
咱们在Manager Node上执行上述命令,查看的状态信息以下所示:
[ { "ID": "qc42f6myqfpoevfkrzmx08n0r", "Version": { "Index": 9 }, "CreatedAt": "2017-03-12T15:25:51.725341879Z", "UpdatedAt": "2017-03-12T15:25:51.84308356Z", "Spec": { "Role": "manager", "Availability": "active" }, "Description": { "Hostname": "manager", "Platform": { "Architecture": "x86_64", "OS": "linux" }, "Resources": { "NanoCPUs": 1000000000, "MemoryBytes": 1912082432 }, "Engine": { "EngineVersion": "17.03.0-ce", "Plugins": [ { "Type": "Network", "Name": "bridge" }, { "Type": "Network", "Name": "host" }, { "Type": "Network", "Name": "macvlan" }, { "Type": "Network", "Name": "null" }, { "Type": "Network", "Name": "overlay" }, { "Type": "Volume", "Name": "local" } ] } }, "Status": { "State": "ready", "Addr": "127.0.0.1" }, "ManagerStatus": { "Leader": true, "Reachability": "reachable", "Addr": "192.168.1.107:2377" } }]
管理Swarm Node
Swarm支持设置一组Manager Node,经过支持多Manager Node实现HA。那么这些Manager Node之间的状态的一致性就很是重要了,多Manager Node的Warm集群架构,以下图所示(出自Docker官网):
经过上图能够看到,Swarm使用了Raft协议来保证多个Manager之间状态的一致性。基于Raft协议,Manager Node具备必定的容错功能,假设Swarm集群中有个N个Manager Node,那么整个集群能够容忍最多有(N-1)/2个节点失效。若是是一个三Manager Node的Swarm集群,则最多只能容忍一个Manager Node挂掉。
下面,咱们按照对Node的不一样操做,经过命令的方式来详细说明:
(1)Node状态变动管理
前面咱们已经提到过,Node的AVAILABILITY有三种状态:Active、Pause、Drain,对某个Node进行变动,能够将其AVAILABILITY值经过Docker CLI修改成对应的状态便可,下面是常见的变动操做:
设置Manager Node只具备管理功能
对服务进行停机维护,能够修改AVAILABILITY为Drain状态
暂停一个Node,而后该Node就再也不接收新的Task
恢复一个不可用或者暂停的Node
例如,将Manager Node的AVAILABILITY值修改成Drain状态,使其只具有管理功能,执行以下命令:
docker node update --availability drain manager
这样,Manager Node不能被指派Task,也就是不能部署实际的Docker容器来运行服务,而只是做为管理Node的角色。
(2)给Node添加标签元数据
每一个Node的主机配置状况可能不一样,好比有的适合运行CPU密集型应用,有的适合运行IO密集型应用,Swarm支持给每一个Node添加标签元数据,这样能够根据Node的标签,来选择性地调度某个服务部署到指望的一组Node上。
给SWarm集群中的某个Worker Node添加标签,执行以下命令格式以下:
docker node update --label-add 键名称=值
例如,worker1主机在名称为bjidc这个数据中心,执行以下命令添加标签:
docker node update --label-add datacenter=bjidc
(3)Node提权/降权
改变Node的角色,Worker Node能够变为Manager Node,这样实际Worker Node有工做Node变成了管理Node,对应提权操做,例如将worker1和worker2都升级为Manager Node,执行以下命令:
docker node promote worker1 worker2
对上面已提权的worker1和worker2执行降权,须要执行以下命令:
docker node demote worker1 worker2
(4)退出Swarm集群
若是Manager想要退出Swarm集群, 在Manager Node上执行以下命令:
docker swarm node leave
就能够退出集群,若是集群中还存在其它的Worker Node,还但愿Manager退出集群,则加上一个强制选项,命令行以下所示:
docker swarm node leave --force
一样,若是Worker想要退出Swarm集群,在Worker Node上,执行以下命令:
docker swarm node leave
即便Manager已经退出SWarm集群,执行上述命令也可使得Worker Node退出集群,而后又能够加入到其它新建的Swarm集群中。
管理服务
在Swarm集群上部署服务,必须在Manager Node上进行操做。先说明一下Service、Task、Container(容器)这个三个概念的关系,以下图(出自Docker官网)很是清晰地描述了这个三个概念的含义:
在Swarm mode下使用Docker,能够实现部署运行服务、服务扩容缩容、删除服务、滚动升级等功能,下面咱们详细说明。
(1)建立服务
建立Docker服务,可使用docker service create命令实现,例如,咱们要建立以下两个服务,执行以下命令:
docker service create --replicas 1 --name myapp alpine ping shiyanjun.cndocker service create --replicas 2 --name myredis redis
第一个命令行,从Docker镜像alpine建立了一个名称为myapp的服务,其中指定服务副本数为1,也就是启动一个Docker容器来运行该服务。第二个命令行, 建立一个Redis服务,服务副本数为2,那么会启动两个Docker容器来运行myredis服务。查看当前,已经部署启动的所有应用服务,执行以下命令:
docker service ls
执行结果,以下所示:
ID NAME MODE REPLICAS IMAGEkilpacb9uy4q myapp replicated 1/1 alpine:latestvf1kcgtd5byc myredis replicated 2/2 redis
也能够查询指定服务的详细信息,执行以下命令:
docker service ps myredis
查看结果信息,以下所示:
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS0p3r9zm2uxpl myredis.1 redis manager Running Running 48 seconds ago ty3undmoielo myredis.2 redis worker1 Running Running 44 seconds ago
上面信息中,在manager和worker1这两个Node上部署了myredis这个应用服务,也包含了它们对应的当前状态信息。此时,也能够经过执行docker ps命令,在Manager Node上查看当前启动的Docker容器:
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES07f93f82a407 redis:latest "docker-entrypoint..." 7 minutes ago Up 7 minutes 6379/tcp myredis.1.0p3r9zm2uxple5i1e2mqgnl3r
在Worker1上查看当前启动的Docker容器,也就是咱们的另外一个myredis实例在该Node上:
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES41c31e96cccb redis:latest "docker-entrypoint..." 8 minutes ago Up 8 minutes 6379/tcp myredis.2.ty3undmoielo18g7pnvh0nutz
建立服务时,咱们能够对运行时服务容器进行配置,例如以下命令:
docker service create --name helloworld \ --env MYVAR=myvalue \ --workdir /tmp \ --user my_user \ alpine ping docker.com
上面,经过 --env
选项来设置环境变量,经过 --workdir
选项来设置工做目录,经过 --user
选项来设置用户信息。
(2)扩容缩容服务
Docker Swarm支持服务的扩容缩容,Swarm经过 --mode
选项设置服务类型,提供了两种模式:一种是replicated,咱们能够指定服务Task的个数(也就是须要建立几个冗余副本),这也是Swarm默认使用的服务类型;另外一种是global,这样会在Swarm集群的每一个Node上都建立一个服务。以下图所示(出自Docker官网),是一个包含replicated和global模式的Swarm集群:
上图中,×××表示的replicated模式下的Service Replicas,灰色表示global模式下Service的分布。
服务扩容缩容,在Manager Node上执行命令的格式,以下所示:
docker service scale 服务ID=服务Task总数
例如,将前面咱们部署的2个副本的myredis服务,扩容到3个副本,执行以下命令:
docker service scale myredis=3
经过命令docker service ls 查看,扩容操做结果以下所示:
ID NAME MODE REPLICAS IMAGEkilpacb9uy4q myapp replicated 1/1 alpine:latestvf1kcgtd5byc myredis replicated 3/3 redis
进一步经过docker service ps myredis查看一下myredis的各个副本的状态信息,以下所示:
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS0p3r9zm2uxpl myredis.1 redis manager Running Running 14 minutes ago ty3undmoielo myredis.2 redis worker1 Running Running 14 minutes ago zxsvynsgqmpk myredis.3 redis worker2 Running Running less than a second ago
能够看到,咱们目前3个Node的Swarm集群,每一个Node上都有一个myredis应用服务的副本,可见也实现了很好的负载均衡。
缩容服务,只须要将副本数小于当前应用服务拥有的副本数便可实现,大于指定缩容副本数的副本会被删除。
(3)删除服务
删除服务,只须要在Manager Node上执行以下命令便可:
docker service rm 服务ID
例如,删除myredis应用服务,执行docker service rm myredis,则应用服务myredis的所有副本都会被删除。
(4)滚动更新
服务的滚动更新,这里我参考官网文档的例子说明。在Manager Node上执行以下命令:
docker service create \ --replicas 3 \ --name redis \ --update-delay 10s \ redis:3.0.6
上面经过指定 --update-delay
选项,表示须要进行更新的服务,每次成功部署一个,延迟10秒钟,而后再更新下一个服务。若是某个服务更新失败,则Swarm的调度器就会暂停本次服务的部署更新。
另外,也能够更新已经部署的服务所在容器中使用的Image的版本,例如执行以下命令:
docker service update --image redis:3.0.7 redis
将Redis服务对应的Image版本有3.0.6更新为3.0.7,一样,若是更新失败,则暂停本次更新。
(5)添加Overlay网络
在Swarm集群中可使用Overlay网络来链接到一个或多个服务。具体添加Overlay网络,首先,咱们须要建立在Manager Node上建立一个Overlay网络,执行以下命令:
docker network create --driver overlay my-network
建立完Overlay网络my-network之后,Swarm集群中全部的Manager Node均可以访问该网络。而后,咱们在建立服务的时候,只须要指定使用的网络为已存在的Overlay网络便可,以下命令所示:
docker service create \ --replicas 3 \ --network my-network \ --name myweb \ nginx
这样,若是Swarm集群中其余Node上的Docker容器也使用my-network这个网络,那么处于该Overlay网络中的全部容器之间,经过网络能够连通。
参考连接
https://docs.docker.com/engine/swarm/
https://docs.docker.com/engine/swarm/swarm-mode/
https://docs.docker.com/engine/swarm/key-concepts/
https://docs.docker.com/engine/swarm/swarm-tutorial/
https://docs.docker.com/engine/swarm/swarm-tutorial/create-swarm/
https://docs.docker.com/engine/swarm/swarm-tutorial/add-nodes/
https://docs.docker.com/engine/swarm/swarm-tutorial/deploy-service/
https://docs.docker.com/engine/swarm/swarm-tutorial/inspect-service/
https://docs.docker.com/engine/swarm/swarm-tutorial/scale-service/
https://docs.docker.com/engine/swarm/swarm-tutorial/rolling-update/
https://docs.docker.com/engine/swarm/manage-nodes/
https://docs.docker.com/engine/swarm/swarm_manager_locking/
https://docs.docker.com/engine/swarm/services/
https://docs.docker.com/engine/swarm/networking/
https://docs.docker.com/engine/swarm/admin_guide/
https://docs.docker.com/engine/swarm/raft/
https://docs.docker.com/engine/swarm/how-swarm-mode-works/nodes/
https://docs.docker.com/engine/swarm/ingress/
https://platform9.com/blog/compare-kubernetes-vs-docker-swarm/
本文基于 署名-非商业性使用-相同方式共享 4.0 许可协议发布,欢迎转载、使用、从新发布,但务必保留文章署名时延军(包含连接:http://shiyanjun.cn),不得用于商业目的,基于本文修改后的做品务必以相同的许可发布。