上面已经介绍了如何安装Docker、拉取镜像以及使用容器,接下来需要探讨的话题将是关于规模(Scale)方面的,这时候轮到Docker Swarm登场了。
10.1 Docker Swarm——简介
Docker Swarm包含两方面:一个企业级的Docker安全集群,以及一个微服务应用编排引擎。
集群方面,Swarm将一个或多个Docker节点组织起来,使得用户能够以集群方式管理它们。Swarm默认内置有加密的分布式集群存储、加密网络、公用TLS、安全集群介入令牌以及一套简化数字证书管理的PKI。用户可以自如地添加或删除节点,这非常棒。
编排方面,Swarm提供了一套丰富的API使得部署和管理复杂的微服务应用变得易如反掌。通过将应用定义在声明式配置文件中,就可以使用原生的Docker命令完成部署。此外,甚至还可以执行滚动升级、回滚以及扩缩容操作、同样基于简单的命令即可完成。
以往,Docker Swarm是一个基于Docker 引擎之上的独立产品。自Docker 1.12版本之后,它已经完全集成在Docker引擎中,执行一条命令即可启用。到2018年,除了原生Swarm应用,他还可以部署和管理k8S应用。即便在本书撰写时,对k8s应用的支持也是新特性。
10.2 Docker Swarm——详解
10.2.1 Swarm的初步介绍
从集群角度来说,一个Swarm由一个或多个Docker节点组成。节点会被配置为管理节点(Manager)或者工作节点(Worker)。管理节点负责集群控制面(Control Plane),进行诸如监控集群状态、分发任务至工作节点等操作。工作节点接收来自管理节点的任务并执行。
Swarm的配置和状态信息保存在一套位于所有管理节点上的分布式etcd数据库中。该数据库运行于内存中,并保持数据的最新状态。关于该数据库最棒的是,他几乎不需要任何配置——作为Swarm的一部分被安装、无需管理。
关于集群管理,最大的挑战在于保证其安全性。搭建Swarm集群时将不可避免地使用TLS,因为它被Swarm紧密集成。在安全意识日盛的今天,这样的工具值得大力推广。Swarm使用TLS进行通信通信、节点认证和角色授权。自动密钥轮换更是锦上添花!其在后台默默进行,用户甚至感知不到这一功能的存在。
关于应用编排,Swarm中的最小调度单元是服务。它是随Swarm引入的,在API中是一个新的对象元素,它基于容器封装了一些高级特征,是一个更高层次的概念。
当容器被封装在一个服务中时,我们称之为一个任务或者一个副本,服务中增加了诸如扩缩容、滚动升级以及简单回滚等特征。
10.2.2 搭建安全的Swarm集群
书本的示例一共有6个节点,包括3个管理节点和3个工作节点。我这里没有那么多的主机资源,一共3个节点,分别包括1个管理节点和2个工作节点。(实际上你可以使用docker machine 轻松搭建多套docker的运行环境)
这里的每个节点都要安装Docker,并且能够与Swarm的其他节点通信。因为都是同一个局域网内,所以我放行了内网的所有防火墙规则。运行Swarm会开启3个端口,分别是:
- 2377/tcp:用于客户端于Swarm进行安全通信
- 7946/tcp 与 7946/udp:用于控制面gossip分发
- 4789/udp:用于基于VXLAN的覆盖网络。
下面我们开始搭建Swarm吧。搭建Swarm的大体流程如下:初始化第一个管理节点——>加入额外的管理节点——>加入工作节点——>完成。
- 初始化一个全新的Swarm
不包含在任何Swarm中的Docker节点,称为运行于单引擎(Single-Engine)模式。一旦被加入Swarm集群,则切换为Swarm模式。
在单引擎模式下的Docker主机上运行 docker swarm init 会将其切换到Swarm模式,并创建一个新的Swarm,将自身设置为Swarm的第一个管理节点。然后其他的节点就可以加入进来了,新加入的节点也会切换为swarm模式。
节点 192.168.113.70 上初始化:
[pangcm@docker01 ~]$ docker swarm init --advertise-addr 192.168.113.70:2377 --listen-addr 192.168.113.70:2377
Swarm initialized: current node (liokj5021pc9ls40fj3tcebxq) is now a manager.
To add a worker to this swarm, run the following command:
docker swarm join --token SWMTKN-1-59xcha9v3tw180c64c0zg0ic2418qw69ns6ics4t6cj2t0wl6x-b5mlt9leakzj4gpo9qa9souc1 192.168.113.70:2377
To add a manager to this swarm, run 'docker swarm join-token manager' and follow the instructions.
这条命令解析如下:
docker swarm init 会通知Docker来初始化一个新的Swarm,并将自身设置为第一个管理节点。同时也会使得该节点开启Swarm模式。
后面的两个和IP相关的参数是可选的,在多IP的Docker主机上需要配置。这里还是建议在执行命令的时候加上着两个参数。
- 列出Swarm中的节点,docker node ls
[pangcm@docker01 ~]$ docker node ls
ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS ENGINE VERSION
liokj5021pc9ls40fj3tcebxq * docker01 Ready Active Leader 19.03.5
这里可以看到目前只有一个节点,该节点是一个leader的角色。
- 在 192.168.113.71和192.168.113.72节点上把这两个节点加入到上面创建的swarm。
##这个命令在我们初始化swarm的时候系统生成的,同理添加管理节点的命令也在初始化的时候给出了
docker swarm join --token SWMTKN-1-59xcha9v3tw180c64c0zg0ic2418qw69ns6ics4t6cj2t0wl6x-b5mlt9leakzj4gpo9qa9souc1 192.168.113.70:2377
- 这时候我们回到管理节点上查看swarm节点的情况。
[pangcm@docker01 ~]$ docker node ls
ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS ENGINE VERSION
liokj5021pc9ls40fj3tcebxq * docker01 Ready Active Leader 19.03.5
qg63e8vx18v1rhnv9hjmwml16 docker02 Ready Active 19.03.4
yle6i7nhhxglc2qva49i91x1v docker03 Ready Active 19.03.5
就这样,Swarm集群我们就创建好了。其中包含了1个管理节点和2个工作节点,每个节点的Docker引擎都被切换到Swarm模式下,并且自动启动了TLS安全。如果你有多个管理节点,那么有的节点会是 Reachable
状态,有一个是 Leader
状态。Leader那个就是主节点了,后面我们会介绍到。
10.2.3 Swarm 管理器的高可用(HA)。
虽然我这里只用到一个管理节点,但是官方是建议3个的,为什么是3个呢?了解集群系统的人都知道,集群工作的时候3或5个节点都是一个比较好的选择。
Swarm的管理节点内置有对HA的支持。这意味着,即使有一个或者多个节点发生了故障,剩余管理节点也会继续保证Swarm的运转。
从技术上来说,Swarm实现了一种主从方式的多管理节点的HA。也就是说,你可能有多个管理节点,但是只有一个处于活动状态。通常处于活动状态的节点被称为主节点,而主节点也是唯一一个会对Swarm发送控制命令的节点。也就是说,只有主节点才会变更配置,或发送任务到工作节点。如果一个备用管理节点接收到了Swarm命令,则它会将其转发给主节点。
Swarm使用Raft算法来实现支持管理节点的HA,Raft协议在选举Leader的时候遵循少数服从多数的原则。所以使用奇数个节点的好处就是避免脑裂现象的出现。而不建议部署太多管理节点的原因是过多的节点数据同步的效率太低了,并且选举耗时会更长,所以一般建议3个或者5个。
10.2.4 Swarm的安全
Swarm集群内置了众多的安全机制,并提供了开箱即用的合理默认配置——如CA设置、接入Token、公用TLS、加密集群存储、加密网络、加密节点ID等等。更多内容会在第15章介绍。
尽管内置有如此多的原生安全机制,重启一个旧的管理节点或者进行备份恢复仍有可能对集群造成影响。一个旧的管理节点重新接入Swarm会自动解密并获得Raft数据库中长时间序列的访问权,这回带来安装隐患。进行本非恢复可能会抹掉最新的Swarm配置。
为了避免以上问题,Docker提供了自动锁机制来锁定Swarm,这会强制要求重启的管理节点在提供一个集群解锁码之后才有权重新接入集群。
在创建Swarm集群的时候可以直接加上 --autolock 参数启用锁。我们前面并没有这么操作,那就需要使用 docker swarm update 命令来启动锁。
在管理节点上
[pangcm@docker01 ~]$ docker swarm update --autolock=true
Swarm updated.
To unlock a swarm manager after it restarts, run the `docker swarm unlock`
command and provide the following key:
SWMKEY-1-8bDcdp+PQ1IYuind8XanEVCxcdsne0OJ6rIYoqQRiPI
Please remember to store this key in a password manager, since without it you
will not be able to restart the manager.
这时候重启其他的管理节点,管理节点不会自动重新接入集群。要接入集群那就要先解锁,使用 docker swarm unlock
命令进行解锁。这里看到,这个key非常重要,请妥善保管。因为我的是测试环境,所以我会把这个锁机制给关闭,以免我自己忘了这个key.
docker swarm update --autolock=false
10.2.5 Swarm服务
本节介绍的内容可以使用Docker Stack(第14章)进一步改进。然而,本章的概念对于准备第14章的学习是非常重要的。
就像在Swarm初步介绍中提到的,服务是自Docker 1.12后新引进的概念,并且仅适用于Swarm模式。使用服务仍能够配置大多数熟悉的容器熟悉,比如容器名、端口映射、接入网络和镜像。此外还增加了额外的特性,比如可以声明应用服务的期望状态,将其告知Docker后,Docker会负责进行服务的部署和管理。
举例说明,加入某个应用的web前端服务,这个服务经过测试我们使用5个实例能够应对正常的流量。那么我们就可以把这个需求转换为一个服务,该服务声明了容器使用的镜像,并且服务应该总是有5个运行中的副本。
下面,我们来看下怎么去创建一个新的服务吧。
##镜像比较大,拉取需要一定的时间
docker service create --name web-fe -p 8080:8080 --replicas 5 nigelpoulton/pluralsight-docker-ci
该命令的参数于 docker container run 命令大致相同,这里我们使用 --name 和 -p 定义服务的方式,与单机启动容器的定义方式一样的。
使用docker service create 命令告知Docker正在声明一个新服务,并传递--name 参数将其命名为web-fe。将每个节点上的8080端口映射到服务副本内部的8080端口。接下来,使用 --replicas 参数告诉Docker应该总是有5个此服务的副本。最后,告知Docker哪个镜像用于副本——重要的是,要了解所有的服务副本使用相同的镜像和配置。
这还没有结束,所有的服务都会被Swarm持续监控——Swarm会在后台进行轮询检查,来次序比较服务的实际状态和期望状态是否一致。如果不一致,Swarm会使其一致。比如,web-fe还有某个节点宕机了,副本数量从5下降到4个,Docker会马上启动一个新的web-fe副本来使实际状态和期望状态保持一致。这一功能非常强大,使得服务在面对节点宕机等问题的时候具有自愈的能力。
- 查看服务
使用 docker service ls 命令可以查看Swarm中的所有运行中的服务。
[pangcm@docker01 ~]$ docker service ls
ID NAME MODE REPLICAS IMAGE PORTS
kiyro8y0wbj7 web-fe replicated 5/5 nigelpoulton/pluralsight-docker-ci:latest *:8080->8080/tcp
使用docker service ps 可以查看服务副本列表及各副本的状态,
[pangcm@docker01 ~]$ docker service ps web-fe
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS
rncmk0pcakm2 web-fe.1 nigelpoulton/pluralsight-docker-ci:latest docker02 Running Running 30 minutes ago
mchv3wizclfa web-fe.2 nigelpoulton/pluralsight-docker-ci:latest docker03 Running Running 18 minutes ago
xaeqa2lehef2 web-fe.3 nigelpoulton/pluralsight-docker-ci:latest docker02 Running Running 30 minutes ago
slq06rv4xuac web-fe.4 nigelpoulton/pluralsight-docker-ci:latest docker03 Running Running 18 minutes ago
j3xtrie3s8jb web-fe.5 nigelpoulton/pluralsight-docker-ci:latest docker01 Running Running 30 minutes ago
这里可以看到各个副本分别运行在Swarm的哪个节点上,以及期望的状态和实际状态。
要查看更加详细的服务信息,可以使用 docker service inspect 命令查看。
[pangcm@docker01 ~]$ docker service inspect web-fe --pretty
ID: kiyro8y0wbj7lxbtzmf3iudrc
Name: web-fe
Service Mode: Replicated
Replicas: 5
Placement:
UpdateConfig:
Parallelism: 1
On failure: pause
Monitoring Period: 5s
Max failure ratio: 0
Update order: stop-first
RollbackConfig:
Parallelism: 1
On failure: pause
Monitoring Period: 5s
Max failure ratio: 0
Rollback order: stop-first
ContainerSpec:
Image: nigelpoulton/pluralsight-docker-ci:latest@sha256:7a6b0125fe7893e70dc63b2c42ad779e5866c6d2779ceb9b12a28e2c38bd8d3d
Init: false
Resources:
Endpoint Mode: vip
Ports:
PublishedPort = 8080
Protocol = tcp
TargetPort = 8080
PublishMode = ingress
使用 --pretty 只显示我们感兴趣的信息,便于阅读。强烈建议能通读docker inspect 命令的信息,其中包含了大量的信息,是我们了解底层运行机制的一个途径。
- 副本服务 VS 全局服务
服务的默认复制方式是副本模式,这种模式会部署期望数量的服务副本,并尽可能均匀地将各个副本分布在整个集群中。另外一种模式是全局模式,这种模式下,每个节点仅运行一个副本。
可以通过 docker service create 命令传递 --mode global 参数来部署一个全局服务。
- 服务的扩缩容
服务的另外一个强大的特征就是能够方便地进行扩缩容。在业务发展的时候,我们会增加副本的数量。
docker service scale web-fe=10
在服务流量低的时候,我们可以降低副本的数量。
docker service scale web-fe=3
- 删除服务
删除一个服务的操作非常简单, 正是由于太简单了,请慎用,删除服务的时候不会进行确认的。
docker service rm web-fe
- 滚动升级
拥有多个副本的服务可以轻松实现滚动升级,这对运维和开发人员太友好了。滚动升级非常简单,只需要执行 docker service update 命令即可。
这里只是为了示例怎么使用命令滚动升级,由于书本的例子很长,这里我就使用 tomcat的镜像直接对上面我们创建的服务进行滚动升级。(书本的例子涉及到覆盖网络的创建,后面我们会有介绍)
docker service update --image tomcat --update-parallelism 2 --update-delay 20s web-fe
这里说明下这两个参数 --update-parallelism 和 --update-delay 声明名词使用新镜像更新2个副本,期间有20s的延迟。升级的过程可以通过 docker service ps web-fe 去查看。
滚动升级完成后,可以使用浏览器检查下结果,这时候页面应该是tomcat的欢迎页面。此外,如果你使用 docker service inspect 命令,还可以看到我们前面配置的两个参数也保存在里面了。
10.2.7 故障排除
日志是我们排错的好助手,docker service logs 可以查看Swarm的服务日志。然而并非所有的日志驱动都支持该命令。
Docker节点默认的配置是,服务使用json-file日志驱动,其他的驱动还有 journald(Linux特有)、syslog、splunk和gelf。
10.3 Docker Swarm——命令
- docker swarm init 命令用户创建一个新的Swarm。
- docker swarm join-token 命令用于查询加入管理节点和工作节点到现有Swarm时使用的命令和Token.
- docker node ls 命令用于列出Swarm中所有节点及相关信息。
- docker service create 命令用于创建一个新的服务
- docker service ls 命令用于列出Swarm中运行的服务,以及诸如服务状态、服务副本等基本信息。
- docker service ps 命令会给出更多关于某个服务副本的信息
- docker service scale 命令用于对服务副本个数进行增减
- docker service update 命令用于对运行中国的服务的属性进行变更
- docker service logs 命令用于查看服务的日志
- docker service rm 用于删除从Swarm中删除某服务,这会直接删除所有副本,不做确认,慎用。
10.4 本章小结
Docker Swarm 是使Docker规模化的关键方案。Docker Swarm 的核心包含一个安全集群组件和一个编排组件。
安全集群管理组件是一个企业级的安全套件,提供了丰富的安全机制以及HA特性,这些都是自动配置好的,并且非常容易调整。
编排组件允许用户以一种简单的声明式的方式来部署和管理微服务应用。它不仅支持原生的Docker Swarm应用,还支持K8s应用。
第14章会对如何使用声明式的方式部署微服务展开更加深入的讨论。