1. Docker Swarm

本文主要记录docker Swarm的基本信息,具体的使用(比如使用Docker Stack部署集群服务在后面的文章再记录)

  1. Docker Swarm包含:安全集群 和 微服务应用编排引擎。
  2. 自Docker 1.12版本后,已集成Docker Swarm,开箱即用。2018年后,除了原生Swarm应用,还可以部署和管理Kubernetes应用。
  3. 集群方面,Swarm 将一个或多个 Docker 节点组织起来,使得用户能够以集群方式管理它们。Swarm 默认内置有加密的分布式集群存储(encrypted distributed cluster store)、加密网络(Encrypted Network)、公用TLS(Mutual TLS)、安全集群接入令牌 Secure Cluster Join Token)以及一套简化数字证书管理的 PKI(Public Key Infrastructure)。
  4. 编排方面,Swarm 提供了一套丰富的 API 使得部署和管理复杂的微服务应用变得易如反掌。通过将应用定义在声明式配置文件中,就可以使用原生的 Docker 命令完成部署。还支持滚动升级、回滚以及扩缩容操作。

2. 集群与应用编排

2.1 集群与应用编排

2.1.1 集群

  1. 一个Swarm由一个或多个Docker节点组成,无论节点是物理服务器、虚拟机、树莓派或云实例,只要所有节点间通过可靠网络连接,并安装Docker。
  2. 节点会被分配为管理节点(Manager)和工作节点(Worker)。管理节点负责集群控制面(Control Plane)(可以运行监控集群、分发任务等操作),工作节点执行来自管理节点分发的任务。
  3. Swarm的配置和状态信息保存在一套位于所有管理节点上的分布式etcd数据库(运行于内存)中(该数据库已集成到Swarm中)。
  4. Swarm集成TLS,在通信、节点认证和角色授权等情况会使用。(Swarm的TLS有自动秘钥轮换功能)

    2.1.2 应用编排

  5. 服务是Swarm中的最小调度单元,在API中是一个新的对象元素,它基于容器封装了一些高级特性,是一个更高层的概念。服务中增加了如扩缩容、滚动升级以及简单回滚等特性。

  6. 封装在服务中的容器称为一个任务或一个副本。

Docker Swarm - 图1

2.2 搭建集群示例

2.2.1 集群搭建准备工作

  • 首先需要确保每个节点都安装上Docker,且能够与Swarm其他节点通信(最好有域名解析)。
  • 网络,需要在路由器和防火墙中开放端口:
    • 2377/tcp:用于客户端与 Swarm 进行安全通信。
    • 7946/tcp 与 7946/udp:用于控制面 gossip 分发。
    • 4789/udp:用于基于 VXLAN 的覆盖网络。

      2.2.2 开始搭建集群

      • 搭建 Swarm 的过程也被称为初始化 Swarm,大体流程:初始化第一个管理节点 -> 加入额外的管理节点 -> 加入工作节点 -> 完成。
  • 以下以创建3个管理节点和3个工作节点为例。
  • 不包含在任何 Swarm 中的 Docker 节点,称为运行于单引擎(Single-Engine)模式。一旦被加入 Swarm 集群,则切换为 Swarm 模式:

Docker Swarm - 图2

  • Swarm 自动启用了 TLS 以策安全。


  1. 登录到 mgr1 并初始化一个新的 Swarm

    1. $ docker swarm init \
    2. --advertise-addr 10.0.0.1:2377 \
    3. --listen-addr 10.0.0.1:2377
    • 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 和端口)
  2. 列出 Swarm 中的节点

    1. $ docker node ls
  3. 其他节点加入到集群中

    docker swarm join-token 命令用来获取添加新的工作节点和管理节点到 Swarm 的命令和 Token。

(1)在 mgr1 上执行命令:

  1. # 工作节点加入集群需要使用的token
  2. $ docker swarm join-token worker
  3. # 管理节点加入集群需要使用的token
  4. $ docker swarm join-token manager

(2)将 wrk1 接入集群

  1. # token来自步骤(1)
  2. $ docker swarm join \
  3. --token SWMTKN-1-0uahebax...c87tu8dx2c \
  4. 10.0.0.1:2377 \
  5. --advertise-addr 10.0.0.4:2377 \
  6. --listen-addr 10.0.0.4:2377

(3)重复步骤(2)来完成节点加入集群

  1. 在任意一个管理节点上执行 docker node ls 命令来列出 Swarm 节点。
    1. $ docker node ls
    2. ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS
    3. 0g4rl...babl8 * mgr2 Ready Active Reachable
    4. 2xlti...l0nyp mgr3 Ready Active Reachable
    5. 8yv0b...wmr67 wrk1 Ready Active
    6. 9mzwf...e4m4n wrk3 Ready Active
    7. d21ly...9qzkx mgr1 Ready Active Leader
    8. e62gf...l5wt6 wrk2 Ready Active
  • mgr2 的 ID 列还显示了一个星号(*),表明当前所在节点在mgr2。

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

  • Swarm 的管理节点内置有对 HA 的支持。这意味着,即使一个或多个节点发生故障,剩余管理节点也会继续保证 Swarm 的运转。

  • Swarm 实现了一种主从方式的多管理节点的 HA。这意味着,即使你可能有多个管理节点,也总是仅有一个节点处于活动状态。处于活动状态的管理节点被称为“主节点”(leader),主节点是唯一一个会对 Swarm 发送控制命令的节点。

Docker Swarm - 图3
上图管理节点是 Leader 或者是 Follower,这是 Raft 的术语,因为 Swarm 使用了 Raft 共识算法的一种具体实现来支持管理节点的HA。

  1. 关于 HA,有以下两条实践原则:
    • 部署奇数个管理节点。
    • 不要部署太多管理节点(建议 3 个或 5 个)。

部署奇数个管理节点有利于减少脑裂(Split-Brain)情况的出现机会,虽然在脑裂情况下集群依然在运行,但是已经无法变更配置,或增加和管理应用负载了。(脑裂简单讲:分区时出现每个分区拥有同样数量的管理节点的情况)

4. 内置的 Swarm 安全机制

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

    5. 锁定 Swarm

    问题1:重启一个旧的管理节点或进行备份恢复仍有可能对集群造成影响(一个旧的管理节点重新接入 Swarm 会自动解密并获得 Raft 数据库中长时间序列的访问权,这会带来安全隐患)

    问题2:进行备份恢复可能会抹掉最新的 Swarm 配置。

  • Docker 提供了自动锁机制来锁定 Swarm,这会强制要求重启的管理节点在提供一个集群解锁码之后才有权从新接入集群。( docker swarm init 命令传入 —autolock 参数可以直接启用锁,或用 docker swarm update 命令来启用锁。设置加锁时,会产生一个解锁码要保管好)

    6. Docker Swarm服务

  • Docker 1.12 后才可以使用Docker Swarm服务。

  1. 创建服务

所有的服务都会被 Swarm 持续监控,在后台进行轮训检查(Reconciliation Loop),并维持实际状况与期望状况一致。

  1. # 创建web-fe服务,映射端口8080到外部8080,且总是有 5 个此服务的副本,使用镜像nigelpoulton
  2. $ docker service create --name web-fe \
  3. -p 8080:8080 \
  4. --replicas 5 \
  5. nigelpoulton/pluralsight-docker-ci
  1. 查看服务 ```bash

    查看 Swarm 中所有运行中的服务

    $ docker service ls

查看服务副本列表及各副本的状态

$ docker service ps web-fe

查看服务副本详细情况

$ docker service inspect (—pretty) web-fe

  1. 3. 副本服务 vs 全局服务
  2. 服务的默认复制模式(Replication Mode)是副本模式。
  3. 副本模式(replicated):会部署期望数量的服务副本,并尽可能均匀地将各个副本分布在整个集群中。
  4. 全局模式(global):每个节点上仅运行一个副本。可以通过给 `docker service create` 命令传递 `--mode global` 参数来指定使用全局服务。
  5. 4. 服务扩缩容
  6. ```bash
  7. # 副本数由 5 个增加到 10 个
  8. $ docker service scale web-fe=10
  1. 服务删除

    1. $ docker service rm web-fe
  2. 滚动升级

    对部署的应用进行滚动升级是常见的操作,也就是升级副本的镜像,因为镜像是应用的主题,可以解耦升级,在swarm中可以通过简单的命令就可以完成这个操作。

  • 例如,有以下swarm,要进行滚动升级: ```bash

    创建网络

    $ docker network create -d overlay uber-net

入站模式创建服务

$ docker service create —name uber-svc \ —network uber-net \ -p 80:80 —replicas 12 \ nigelpoulton/tu-demo:v1

  1. 默认的模式,是在Swarm中的所有节点开放端口——即使节点上没有服务的副本——称为入站模式(Ingress)。还有主机模式(Host),仅在运行有副本的节点上开放端口:
  2. ```bash
  3. # 主机模式创建服务
  4. # 需要较长格式的声明语法
  5. $ docker service create --name uber-svc \
  6. --network uber-net \
  7. --publish published=80,target=80,mode=host \
  8. --replicas 12 \
  9. nigelpoulton/tu-demo:v1

使用浏览器,打开 Swarm 中任何一个节点的 IP,进入 80 端口的界面,查看服务运行情况。Ingress模式,即使某个节点上并未运行服务的副本,依然可以进入该页面,所有节点都配置有映射,因此会将请求转发给运行有服务副本的节点

  • 现在要对应用进行升级,新镜像的 tag 由 v1 变更为 v2。本次升级任务在将新镜像更新到 Swarm 中时采用一种阶段性的方式,每次更新两个副本,并且中间间隔 20s。
    1. $ docker service update \
    2. --image nigelpoulton/tu-demo:v2 \
    3. --update-parallelism 2 \
    4. --update-delay 20s uber-svc
    如果对该服务执行 docker service ps 命令会发现,有些副本的版本号是 v2 而有些依然是 v1。如果给予该操作足够的时间(4min),则所有的副本最终都会达到新的期望状态,即基于 v2 版本的镜像。

如果在更新操作完成前打开浏览器,使用 Swarm 中任一节点的 IP 进入页面,并多次单击刷新按钮,就会看到滚动更新的效果。有些请求会被旧版本的副本处理,而有些请求会被新版本的副本处理。

执行 docker inspect --pretty 命令,会发现更新时对并行和延迟的设置已经成为服务定义的一部分了。这意味着,之后的更新操作将会自动使用这些设置,直到再次使用 docker service update 命令覆盖它们。

7. 故障排查

Docker Swarm 服务的日志可以通过执行 docker service logs 命令来查看,然而并非所有的日志驱动(Logging Driver)都支持该命令。

7.1 日志驱动

  1. Docker 节点默认的配置是,服务使用 json-file 日志驱动,其他的驱动还有 journald(仅用于运行有 systemd 的 Linux 主机)、syslog、splunk 和 gelf。
  2. json-file 和 journald 是较容易配置的,二者都可用于 docker service logs 命令。若使用第三方日志驱动,那么就需要用相应日志平台的原生工具来查看日志。
  3. 在 daemon.json 配置文件中定义使用 syslog 作为日志驱动的示例:
    1. {
    2. "log-driver": "syslog"
    3. }
    在执行 docker service create 命令时传入 —logdriver 和 —log-opts 参数可以强制某服务使用一个不同的日志驱动,这会覆盖 daemon.json 中的配置。服务日志能够正常工作的前提是,容器内的应用程序运行于 PID 为 1 的进程,并且将日志发送给 STDOUT,错误信息发送给 STDERR。日志驱动会将这些日志转发到其配置指定的位置。

    8. 常用命令

  • docker swarm init 创建一个新的Swarm。该节点会切换到Swarm模式,且执行这个命令的节点会成为第一个管理节点。
  • docker swarm join-token 查询加入管理节点和工作节点到现有Swarm时所使用的命令和Token。获取新增管理节点和工作节点分别执行 docker swarm join-token manager 和 docker swarm join-token worker。
  • docker node ls 列出群集(swarm)中的节点相关信息。
  • docker service create 创建一个新服务。
  • docker service ls 列出集群中运行的服务相关信息。
  • docker service ps 显示更多某个服务副本信息。
  • docker service inspect 获取关于服务的详情。
  • docker service scale 增减服务副本个数。
  • docker service update 更新运行中服务的属性。
  • docker service logs 获取服务的日志
  • docker service rm 从swarm中删除某服务的所有副本(不做二次确认,要小心)。