一、Docker Swarm——简介

Docker Swarm包含两方面:

        一个企业级的Docker安全集群,以及一个微服务应用编排引擎。

  1.         集群方面,Swarm将一个或多个Docker节点组织起来,使得用户能够以集群方式管理它们。Swarm默认内置有加密的分布式集群存储(encrypted distributed cluster store)、加密网络(Encrypted Network)、公用TLS(Mutual TLS)、安全集群接入令牌Secure Cluster Join Token)以及一套简化数字证书管理的PKI(Public Key Infrastructure)。用户可以自如地添加或删除节点,这非常棒!
  2.         编排方面,Swarm提供了一套丰富的API使得部署和管理复杂的微服务应用变得易如反掌。通过将应用定义在声明式配置文件中,就可以使用原生的Docker命令完成部署。此外,甚至还可以执行滚动升级、回滚以及扩缩容操作,同样基于简单的命令即可完成。
  3.         以往,Docker Swarm是一个基于Docker引擎之上的独立产品。自Docker 1.12版本之后,它已经完全集成在Docker引擎中,执行一条命令即可启用。到2018年,除了原生Swarm应用,它还可以部署和管理Kubernetes应用。即便在本书撰写时,对Kubernetes应用的支持也是新特性。

二、Docker Swarm——详解

  1. Swarm的初步介绍。
  2. 搭建一个安全的Swarm集群。
  3. 部署Swarm服务。
  4. 问题定位。

1.  Swarm的初步介绍

        从集群角度来说,一个Swarm由一个或多个Docker节点组成。这些节点可以是物理服务器、虚拟机、树莓派(Raspberry Pi)或云实例。唯一的前提就是要求所有节点通过可靠的网络相连。
        节点会被配置为管理节点(Manager)或工作节点(Worker)。管理节点负责集群控制面(Control Plane),进行诸如监控集群状态、分发任务至工作节点等操作。工作节点接收来自管理节点的任务并执行。
         Swarm的配置和状态信息保存在一套位于所有管理节点上的分布式etcd数据库中。该数据库运行于内存中,并保持数据的最新状态。关于该数据库最棒的是,它几乎不需要任何配置——作为Swarm的一部分被安装,无须管理。
        关于集群管理,最大的挑战在于保证其安全性。搭建Swarm集群时将不可避免地使用TLS,因为它被Swarm紧密集成。在安全意识日盛的今天,这样的工具值得大力推广。Swarm使用TLS进行通信加密、节点认证和角色授权。自动密钥轮换(Automatic Key Rotation)更是锦上添花!其在后台默默进行,用户甚至感知不到这一功能的存在!
        关于应用编排,Swarm中的最小调度单元是服务。它是随Swarm引入的,在API中是一个新的对象元素,它基于容器封装了一些高级特性,是一个更高层次的概念。
当容器被封装在一个服务中时,我们称之为一个任务或一个副本,服务中增加了诸如扩缩容、滚动升级以及简单回滚等特性。


docker yaml 启动程序 docker swarm yaml_运维

从概括性的视角看Swarm

2.  搭建安全Swarm集群

        本节会搭建一套安全Swarm集群,其中包含3个管理节点和3个工作节点。读者也可以自行调整管理节点和工作节点的数量、名称和IP


docker yaml 启动程序 docker swarm yaml_docker_02

图 2.3

         每个节点都需要安装Docker,并且能够与Swarm的其他节点通信。如果配置有域名解析就更好了——这样在命令的输出中更容易识别出节点,也更有利于排除故障。

        在网络方面,需要在路由器和防火墙中开放如下端口。

        2377/tcp:用于客户端与Swarm进行安全通信。

        7946/tcp与7946/udp:用于控制面gossip分发。

        4789/udp:用于基于VXLAN的覆盖网络。

        如果满足以上前提,就可以着手开始搭建Swarm集群了。
搭建Swarm的过程有时也被称为初始化Swarm,大体流程包括初始化第一个管理节点>加入额外的管理节点>加入工作节点>完成。

2.1.初始化一个全新的Swarm

        不包含在任何Swarm中的Docker节点,称为运行于单引擎(Single-Engine)模式。一旦被加入Swarm集群,则切换为Swarm模式,如下图:


docker yaml 启动程序 docker swarm yaml_docker yaml 启动程序_03

Docker节点加入Swarm集群

 
        在单引擎模式下的Docker主机上运行docker swarm init会将其切换到Swarm模式,并创建一个新的Swarm,将自身设置为Swarm的第一个管理节点。
        更多的节点可以作为管理节点或工作节点加入进来。这一操作也会将新加入的节点切换为 Swarm模式。
        以下的步骤会将mgr1切换为Swarm模式,并初始化一个新的Swarm。接下来将wrk1、wrk2和wrk3作为工作节点接入——自动将它们切换为Swarm模式。然后将mgr2和mgr3作为额外的管理节点接入,并同样切换为Swarm模式。最终有6个节点切换到Swarm模式,并运行于同一个Swarm中。

本示例会使用 图 2.3 中所示的各节点的IP地址和DNS名称。读者的可以与其不同。
        (1)登录到mgr1并初始化一个新的Swarm(如果在Windows的PowerShell终端执行如下命令的话,不要忘了将反斜杠替换为反引号)。

docker swarm init \
   --advertise-addr 10.0.0.1:2377 \
   --listen-addr 10.0.0.1:2377Swarm initialized: current node (d21lyz...c79qzkx) is now a manager.

将这条命令拆开分析如下。

docker swarm init        会通知Docker来初始化一个新的Swarm,并将自身设置为第一个管理节点。同时也会使该节点开启Swarm模式。

--advertise-addr        指定其他节点用来连接到当前管理节点的IP和端口。这一属性是可选的,当节点上有多个IP时,可以用于指定使用哪个IP。此外,还可以用于指定一个节点上没有的IP,比如一个负载均衡的IP。

--listen-addr        指定用于承载Swarm流量的IP和端口。其设置通常与--advertise-addr相匹配,但是当节点上有多个IP的时候,可用于指定具体某个IP。并且,如果--advertise-addr设置了一个远程IP地址(如负载均衡的IP地址),该属性也是需要设置的。建议执行命令时总是使用这两个属性来指定具体IP和端口。

        Swarm模式下的操作默认运行于2337端口。虽然它是可配置的,但2377/tcp是用于客户端与Swarm进行安全(HTTPS)通信的约定俗成的端口配置。

(2)列出Swarm中的节点。

docker node ls
 ID            HOSTNAME  STATUS  AVAILABILITY  MANAGER STATUS
 d21...qzkx *  mgr1      Ready   Active        Leader

注意到 mgr1是Swarm中唯一的节点,并且作为Leader列出,稍后再探讨这一点。

(3)在mgr1上执行docker swarm join-token命令来获取添加新的工作节点和管理节点到Swarm的命令和Token。

docker swarm join-token worker
 To add a manager to this swarm, run the following command:
    docker swarm join \
    --token SWMTKN-1-0uahebax...c87tu8dx2c \
    10.0.0.1:2377

$ docker swarm join-token manager
 To add a manager to this swarm, run the following command:
    docker swarm join \
    --token SWMTKN-1-0uahebax...ue4hv6ps3p \
    10.0.0.1:2377

请注意,工作节点和管理节点的接入命令中使用的接入Token(SWMTKN...)是不同的。因此,一个节点是作为工作节点还是管理节点接入,完全依赖于使用了哪个Token。接入Token应该被妥善保管,因为这是将一个节点加入Swarm的唯一所需!

(4)登录到wrk1,并使用包含工作节点接入Token的docker swarm join命令将其接入Swarm。

$ docker swarm join \
     --token SWMTKN-1-0uahebax...c87tu8dx2c \
     10.0.0.1:2377 \
     --advertise-addr 10.0.0.4:2377 \
     --listen-addr 10.0.0.4:2377
This node joined a swarm as a worker.

--advertise-addr 与 --listen-addr属性是可选的。在网络配置方面,请尽量明确指定相关参数,这是一种好的实践。

(5)在wrk2和wrk3上重复上一步骤来将这两个节点作为工作节点加入Swarm。确保使用 --advertise-addr与 --listen-addr属性来指定各自的IP地址。

(6)登录到mgr2,然后使用含有管理节点接入Token的docker swarm join命令,将该节点作为工作节点接入Swarm。

$ docker swarm join \
     --token SWMTKN-1-0uahebax...ue4hv6ps3p \
     10.0.0.1:2377 \
     --advertise-addr 10.0.0.2:2377 \
     --listen-addr 10.0.0.1:2377
This node joined a swarm as a manager.

(7)在mgr3上重复以上步骤,记得在 --advertise-addr与 --listen-addr属性中指定mgr3的IP地址。

(8)在任意一个管理节点上执行docker node ls命令来列出Swarm节点。

$ docker node ls
 ID                HOSTNAME  STATUS  AVAILABILITY  MANAGER STATUS
 0g4rl...babl8 *   mgr2      Ready   Active        Reachable
 2xlti...l0nyp     mgr3      Ready   Active        Reachable
 8yv0b...wmr67     wrk1      Ready   Active
 9mzwf...e4m4n     wrk3      Ready   Active
 d21ly...9qzkx     mgr1      Ready   Active        Leader
 e62gf...l5wt6     wrk2      Ready   Active

恭喜!想必读者也已经创建了6个节点的Swarm,其中包含3个管理节点和3个工作节点。在这个过程中,每个节点的Docker引擎都被切换到Swarm模式下。贴心的是,Swarm已经自动启用了TLS以策安全。

观察MANAGER STATUS一列会发现,3个节点分别显示为“Reachable”或“Leader”。关于主节点稍后很快会介绍到。MANAGER STATUS一列无任何显示的节点是工作节点。注意,mgr2的 ID 列还显示了一个星号(*),这个星号会告知用户执行docker node ls命令所在的节点。本例中,命令是在mgr2节点执行的。

2.2.  Swarm管理器高可用性(HA)

至此在Swarm中已经加入了3个管理节点。为什么添加3个,以及它们如何协同工作? 本节将就此以及更多问题展开介绍。

        Swarm的管理节点内置有对 HA 的支持。这意味着,即使一个或多个节点发生故障,剩余管理节点也会继续保证Swarm的运转。
        从技术上来说,Swarm实现了一种主从方式的多管理节点的HA。这意味着,即使你可能——并且应该——有多个管理节点,也总是仅有一个节点处于活动状态。通常处于活动状态的管理节点被称为“主节点”(leader),而主节点也是唯一 一个会对Swarm发送控制命令的节点。也就是说,只有主节点才会变更配置,或发送任务到工作节点。如果一个备用(非活动)管理节点接收到了Swarm命令,则它会将其转发给主节点。
        这一过程如图 2.2.2 所示。步骤 ① 指命令从一个远程的Docker客户端发送给一个管理节点;步骤 ②指非主节点将命令转发给主节点;步骤 ③ 指主节点对Swarm执行命令。


docker yaml 启动程序 docker swarm yaml_docker_04

图 2.2.2 10.2.3 Swarm的高可用(HA)管理

仔细观察 图2.2.2 的读者会发现,管理节点或者是Leader或者是Follower。这是Raft的术语,因为Swarm使用了Raft共识算法的一种具体实现来支持管理节点的HA。关于HA,以下是两条最佳实践原则。

部署奇数个管理节点。
不要部署太多管理节点(建议3个或5个)。

        部署奇数个管理节点有利于减少脑裂(Split-Brain)情况的出现机会。假如有4个管理节点,当网络发生分区时,可能会在每个分区有两个管理节点。这种情况被称为脑裂——每个分区都知道曾经有4个节点,但是当前网络中仅有两个节点。糟糕的是,每个分区都无法知道其余两个节点是否运行,也无从得知本分区是否掌握大多数(Quorum)。虽然在脑裂情况下集群依然在运行,但是已经无法变更配置,或增加和管理应用负载了。

        不过,如果部署有3个或5个管理节点,并且也发生了网络分区,就不会出现每个分区拥有同样数量的管理节点的情况。这意味着掌握多数管理节点的分区能够继续对集群进行管理。图 2.2.3 中,阐释了这种情况,左侧的分区知道自己掌握了多数的管理节点。

        对于所有的共识算法来说,更多的参与节点就意味着需要花费更多的时间来达成共识。这就像决定去哪吃饭——只有3个人的时候总是比有33个人的时候能更快确定。考虑到这一点,最佳的实践原则是部署3个或5个节点用于HA。7个节点可以工作,但是通常认为3个或5个是更优的选择。当然绝对不要多于7个,因为需要花费更长的时间来达成共识。


docker yaml 启动程序 docker swarm yaml_docker_05

图 2.2.3  多数管理节点的分区继续对集群进行管理

 关于管理节点的HA再补充一点。显然将管理节点分布到不同的可用域(Availability Zone)中是一种不错的实践方式,但是一定要确保它们之间的网络连接是可靠的,否则由于底层网络分区导致的问题将是令人痛苦的!这意味着,在本书撰写时,将生产环境的应用和基础设置部署在多个不同的公有云(例如AWS和Azure)上的想法仍然是天方夜谭。请一定要确保管理节点之间是有高速可靠的网络连接的!

2.3. 内置的Swarm安全机制

        Swarm集群内置有繁多的安全机制,并提供了开箱即用的合理的默认配置——如CA设置、接入Token、公用TLS、加密集群存储、加密网络、加密节点ID等。更多细节请阅读第15章。