Lazy loaded image
docker
Lazy loaded imagedocker swarm
字数 9418阅读时长 24 分钟
2026-3-26
2026-3-26
type
Post
status
Published
date
Mar 26, 2026
slug
docker/swarm
summary
tags
docker
category
docker
icon
password

docker swarm

Docker Swarm 是 Docker 官方提供的容器编排工具,用于管理多主机上的 Docker 集群。从 Docker 1.12 开始,Swarm mode 已内置在 Docker 引擎中,用户可以通过 docker swarm 命令直接启用集群功能。Swarm 的核心作用是将多个 Docker 主机组成一个集群,对外表现为一个统一的资源池,用户可以像操作单机一样管理整个集群。Swarm 提供以下核心能力: 集群管理:支持多节点(manager / worker)架构,manager 负责调度和集群状态管理 服务编排:以 service 为单位部署应用,支持副本(replicas)和滚动更新 服务发现与负载均衡:内置 DNS 服务发现,自动实现容器间负载均衡 跨主机网络:支持 overlay 网络,实现跨主机通信
swarm 集群由管理节点(manager)和工作节点(work node)构成。 Manager 节点用于维护 swarm 集群状态、调试 servcie、处理 swarm 集群管理任务。为了防止单点故障问题,一个 Swarm 集群一般都会包含多个 manager。这些 manager 间通过Raft 算法维护着一致性。 Worker 节点用于在其 Contiainer 中运行 task 任务,即对外提供 service 服务。默认情况下,manager 节点同时也充当着 worker 角色,可以运行 task 任务。
notion image
在 Docker Swarm 中,有几个核心概念: Service(服务):Service 是 Swarm 中的核心抽象,用于定义应用的期望状态。包括:使用的镜像、副本数量(replicas)、端口等,用户通过 Service 对外提供服务。 Task(任务):Task 是 Service 的最小调度单元,每个 Task 对应一个容器实例。Task 一旦创建,其生命周期不可变。失败后不会重用,而是创建新的 Task。可以理解为:Service 定义要多少个实例,Task 实际运行的容器实例。 调度与编排(Scheduler / Orchestrator):由 manager 节点负责,根据 Service 的定义(如 replicas=3),创建对应数量的 Task,将 Task 调度到合适的 worker 节点运行。 期望状态维护(自愈机制):Swarm 会持续对比期望状态和实际状态,如果某个 Task(容器)异常退出:旧 Task 标记为失败,创建新的 Task 替代,调度到新的节点运行。 服务发现与负载均衡:每个 Service 会分配一个虚拟 IP(VIP),内置 DNS 会将 Service 名解析为 VIP。请求访问 VIP 时,通过内置负载均衡分发到后端多个 Task

swarm 集群搭建

现要搭建一个 docker swarm 集群,包含 5 个 swarm 节点。这 5 个 swarm 节点的 IP 与暂时的角色分配如下(注意,是暂时的):
hostname
IP
role
docker
192.168.192.101
manager
docker2
192.168.192.102
manager
docker3
192.168.192.103
manager
docker4
192.168.192.104
worker
docker5
192.168.192.105
worker
在创建集群之前,使用 docker node ls 查看下集群中节点的信息,反馈目前没有节点信息,并且当前节点并不是manager
也可以在任意 docker 主机上通过 docker info 命令可以查看到当前 docker 引擎 Server 端对于 swarm 的激活状态。由于尚未初始化 swarm 集群,所以这些 docker 主机间没有任何关系,且 swarm 均未被激活

初始化 Swarm 集群

在主机名为 docker 的主机上运行 docker swarm init 命令,创建并初始化一个 swarm

加入Swarm

加入节点,复制初始化集群时提示的加入工作节点命令,分别在工作节点上执行。也可以在master节点执行docker swarm join-token命令来查看如何加入管理节点和工作节点。查看如何加入管理节点
查看如何加入工作节点
本案例使用的是3个manager节点,2个woker节点。分别在worker节点执行以下命令加入集群
复制 docker swarm join-token 命令生成的 manager 添加命令,然后在 docker2 与 docker3 节点上运行,将这两个节点添加为 manager 节点
在manager查看当前节点的状态,在 worker 节点上是不能运行 docker node ls 命令的,manager 是管理集群的入口。当前集群包含 3 个管理节点,2 个工作节点
notion image
在任意 docker 主机上通过 docker info 命令可以查看到当前 swarm 的状态
Manager Node 必须是单数(Raft),生产环境推荐3台或5台作为 Manager Node
notion image

禁用节点

在生产环境 Manager Node 不推荐运行任何容器实例,但是 Swarm 调度器会分配给Manager Node,可以通过禁用节点,告诉 Swarm 调度器不要分配给 Manager Node 任何容器实例。

启用节点

禁用节点后使用以下命令即可启用节点

更新节点

给节点添加标签,可以用来控制服务放置

删除节点

manager 节点通过 docker node rm 命令可以删除一个 Down 状态的、指定的 worker 节点。注意,该命令只能删除 worker 节点,不能删除 manager 节点。对于 Ready 状态的 worker 节点是无法直接删除的
notion image
对于 manager 节点也是无法删除的
notion image
若要删除一个 worker 节点,首先要将该节点的 Docker 关闭,使该节点变为 Down 状态,然后再进行删除。下面我们来关闭 docker2 节点的 Docker 引擎
删除节点
notion image
如果觉得前面的删除方式有些麻烦,其实也可以通过添加-f 选项来实现强制删除
notion image
但对于 manager 节点,强制删除也不能删除
notion image
docker node rm –f 命令会使一个节点强制退群,而 docker swarm leave 命令是使当前的docker 主机关闭 swarm 模式

swarm集群维护

当一个节点想从 swarm 集群中退出时,可以通过 docker swarm leave 命令。不过 worker 节点与 manager 节点的退群方式是不同的

worker退群

worker退群,在要退群的工作节点执行docker swarm leave命令即可
此时在 manager 节点中可以看到 docker5 已经 Down 了
notion image
Down状态的节点是完全可以将其删除的,在manager节点运行docker node rm命令删除 Down 状态节点
notion image

worker重新加入

如果 worker 想要重新加入集群,首先在 manager 节点上运行 docker swarm join-token worker 命令,生成加入 worker 节点的命令。在 worker 节点上运行复制生成的命令,将此节点添加到 swarm 集群
此时在 manager 节点中查看节点情况,可以看到又新增了一个新的 docker5 节点,其状态为 Ready
notion image

manager退群

对于 manager 节点,原则上是不推荐直接退群的,这样会导致 swarm 集群的一致性受到损坏。如果 manager 执意要退群,可在 docker swarm leave 命令后添加-f--force 选项进行强制退群。

角色转换

Swarm 集群中节点的角色只有 manager 与 worker,所以其角色也只是在 manager 与worker 间的转换。即 worker 升级为 manager,或 manager 降级为 worker。
通过 docker node promote 命令可以将 worker 升级为 manager。例如,下面的命令是将 docker4 与 docker5 两个节点升级为了 manager,即当前集群中全部为 manager
notion image
通过 docker node demote 命令可以将 manager 降级为 worker。例如,下面的命令是将docker2 与 docker3 两个节点降级为了 worker
notion image
除了通过 docker node demote|promote 可以变更节点角色外,通过 docker node update --role [manager|worker] [node] 也可变更指定节点的角色。如以下命令将 docker2 与 docker3 两个节点又变为了 manager
notion image
将 docker4 与 docker5 两个节点又变为了 worker
notion image

节点标签

swarm 可以通过命令为其节点添加描述性标签,以方便管理员去了解该节点的更多信息。通过 docker node update --label-add 命令可以为指定 node 添加指定的 key=value 的标签。若该标签的 key 已经存在,则会使用新的 value 替换掉该 key 的原 value。不过需要注意的是,若要添加或修改多个标签,则需要通过多个--label-add 选项指定
notion image
通过 docker node inspect 在查看该节点详情时可看到添加的标签
notion image
docker node inspect --pretty 可以 key:value 的形式显示信息
notion image
通过 docker node update --label-rm 命令可以为指定的 node 删除指定 key 的标签。同样,若要删除多个标签,则需要通过多个 --label-rm 选项指定要删除 key 的标签
notion image
查看节点详情,发现这两个标签已经消失
notion image

swarm自动锁定

在 manager 集群中,swarm 通过 Raft 日志方式维护了 manager 集群中数据的一致性。即在 manager 集群中每个节点通过 manager 间通信方式维护着自己的 Raft 日志。但在通信过程中存在有一种风险:Raft 日志攻击者会通过 Raft 日志数据的传递来访问、篡改 manager 节点中的配置或数据。为了防止被攻击,swarm 开启了一种集群自动锁定功能,为 manager 间的通信启用了 TLS 加密。用于加密和解密的公钥与私钥,全部都维护在各个节点的 Docker 内存中。一旦节点的 Docker 重启,则密钥丢失。
swarm 中通过 autolock 标志来设置集群的自动锁定功能:为 true 则开启自动锁定,为false 则关闭自动锁定。查看是否设置自动锁定
在 manager 节点通过 docker swarm update --autolock=true 命令可以开启当前 swarm 集群的自动锁定功能
此时查看 manager 的 docker info 可以看到,autolock 已经为 true 了。
如果没有保存 docker swarm update --autolock=true 命令中生成的密钥,也可通过在manager 中运行 docker swarm unlock-key 命令查看。
现在我们来关闭 docker3 的 docker 引擎,模拟一个 manager 宕机的情况,在 docker3 节点执行以下命令
启动 docker3 的 docker 引擎
此时再查看该节点的 docker info,可以看到 Swarm值为 locked,即当前节点看到的 Swarm集群的状态为锁定状态,其若要加入,必须先解锁
在 docker3 中运行 docker swarm unlock 命令,解锁 swarm
notion image
此时再查看节点信息,该 manager 已经加入
notion image
那么如果整个集群的docker都关闭了呢?

服务管理

将服务部署到 swarm 时,swarm 管理器接收服务定义作为服务的所需状态。然后,它将群中的节点上的服务调度为一个或多个副本任务。这些任务在群中的节点上彼此独立运行。例如,假设在 HTTP 侦听器的三个实例之间进行负载平衡。下图显示了具有三个副本的 HTTP 侦听器服务。侦听器的三个实例中的每一个都是群中的一个任务。
notion image

创建服务

连接到 Manager Node,使用 docker service create 命令创建服务,现在要在swarm 中创建一个运行 tomcat:8.5.49 镜像的service,服务名称为 toms,包含3 个副本task,对外映射端口号为 9000。命令下生成的一串码为 service 的ID。
-name:指定服务名称为 testnginx -replicas:指定服务运行实例数量为 3
notion image

查看服务

docker service ls 命令用于查看当前 swarm 集群中正在运行的 service 列表信息,一个swarm 中可以运行多个 service。在 Manager Node 运行此命令查看正在运行的服务列表
notion image
通过 docker service inspect [service name|service ID] 命令可以查看指定 service 的详情,在 Manager Node 运行此命令查看服务的运行详情
在 Manager Node 使用此命令查看服务都在那些节点运行,docker-swarm 中的服务实例由 swarm 调度。因此有部分服务的实例运行在 Manager Node 是正常表现。可以看到,toms 服务的 3 个 task 被分配到了 docker2、docker、docker5 三个主机。其中 ID 为 task ID,NAME 为 task 的 name。task name 是 service name 后添加从 1 开始的流水号形成的。在 docker2、docker、docker5 三个主机中执行 docker ps 查看正在运行的容器列表,可以看到相应的tomcat 容器。
notion image
当服务创建完毕后,该服务也就运行了起来。此时用户就可通过浏览器进行访问了,用户可以访问 swarm 集群中任意主机
notion image

查看服务日志

通过 docker service logs 命令可以查看指定 service 或 task 的日志,通过 docker service logs –f 命令可动态监听指定 service 或 task 的日志。这些日志实际上是所有 task 在节点容器中的运行日志。通过 docker service logs [task ID] 命令可以查看指定 task 的日志。注意,这里只能指定 taskID,不能指定 task name,这些日志实际是指定 task 在节点容器中的运行日志。
notion image

负载均衡

当一个 service 包含多个 task 时,用户对 service 的访问最终会通过负载均衡方式转发给各个 task 处理。这个负载均衡为轮询策略,且无法通过修改 service 的属性方式进行变更。但由于该负载均衡为三层负载均衡,所以其可以通过第三方实现负载均衡策略的变更,例如通过 Nginx、HAProxy 等。
为了能够展示出 service 对访问请求负载均衡的处理方式,这里使用一个镜像containous/whoami。该镜像中应用端口号为 80,通过浏览器访问,返回结果中包含很多信息,其中最重要的是处理该请求的容器 ID。为了提高 service 的创建效率,可以先将该镜像下载到所有节点主机。 下面的命令用于创建该镜像的一个 service,包含 5 个副本 task。
notion image
可以看到,每个节点上都分配了一个 task,即每个节点上都运行了一个该 task 的容器
notion image
为了体现负载均衡的效果,这里需要将各个节点主机中该 service 的 task 容器的 ID 查询并记录下来,在每个节点执行 docker ps 命令记录。在任意主机上使用 curl 命令访问 swarm 集群中的任意节点,无论是 manager 还是 worker,快速访问后,在返回结果中的 Hostname 值就是处理该请求的容器的 ID,第 2 个 IP 为该节点在 Swarm 集群局域网中的 IP。 从结果可以看出,这些请求被轮询分配给了各个 task 容器进行的处理,实现了 service 对访问请求的负载均衡。

task 伸缩

docker-swarm 支持对服务实例进行动态伸缩,根据访问量的变化,需要在不停止服务的前提下对服务的 task 进行扩容/缩容,即对服务进行伸缩变化。有两种实现方式:update 和 scale
通过 docker service scale 命令可以为指定的服务变更 task 数量
notion image
此时可以看到新增了 3 个 task 节点。由于共有 5 台主机,现有 7 个 task,所以就出现了一个主机上有多个 task 的情况。例如本例中,docker2 与 docker4 中分别有 2 个 task
notion image
当然,也可以使 task 数量减小。例如,下面的命令使 task 又变回了 3 个
notion image
这三个 task 分别在 docker2、docker 与 docker5 主机
notion image
docker service update 方式,通过 docker service update --replicas 命令可以实现对指定服务的 task 数量进行变更。
notion image
执行 docker service ps toms 此时可以看到新增了一个task节点
notion image

暂停节点的 task 分配

生产环境下,可能由于某主机性能不高,在进行 task 扩容时,不想再为该主机再分配更多的 task,此时可通过 pause 暂停该主机节点的可用性来达到此目的。 例如,当前 docker4、docker2 与 docker 三个主机上的 toms 服务的 task 情况如下
notion image
现准备将 toms 服务的 task 扩容为 10,但保持 docker2 节点中的 task 数量仍为 1 不变,此时就可通过 docker node update --availability pause 命令修改 docker2 节点的可用性
notion image
将 toms 服务的 task 扩容为 10
notion image
查看各节点分配的 task 情况会发现,原本应该平均分配到每个节点 2 个 task,但 docker2 的 task 数量并未增加,所以其它节点主机(docker3)的就多于 2 个了
notion image

清空 task

默认情况下,manager 节点同时也具备 worker 节点的功能,可以由分发器为其分配 task。但 manager 节点使用 raft 算法来达成 manager 间数据的一致性,对资源较敏感。因此,阻止 manager 节点接收 task 是比较好的选择。 或者,由于某节点出现了性能问题,需要停止服务进行维修,此时最好是将该节点上的 task 清空,以不影响 service 的整体性能。 通过 docker node update –availability drain 命令可以清空指定节点中的所有 task。例如,目前各个节点的对于 toms 服务的 task 分配情况如下:
notion image
现对 docker2 与 docker5 两个节点进行 task 清空操作
notion image
此时可以看到,toms 服务的 task 总量并没有减少,只是 docker2 与 docker5 两个节点上是没有 task 的,而全部都分配到了 docker、docker3 与 docker4 三个节点上了。这个结果就是由编排器与分发器共同维护的
notion image

task 容错

当某个 task 所在的主机或容器出现了问题时,manager 的编排器会自动再创建出新的task,然后分发器会再选择出一台 available node 可用节点,并将该节点分配给新的 task。现在通过停掉 docker2、docker 或 docker5 中某个主机容器的方式来模拟故障情况。例如停掉 docker2 的容器
notion image
此时再查看服务的 task 节点信息可以看到,原来 docker2 上的 task 已经是 Shutdown 状态了,而新增了一个新的 toms.1 的 task,其分配的是 docker4 主机
notion image

删除服务

在 Manager Node 使用以下命令删除服务。因为是集群的原因,集群中的Node将会存在延迟的情况,想确认服务是否被删除成功请使用 docker service ls 查看

滚动更新

当一个 service 的 task 较多时,为了不影响对外提供的服务,在对 service 进行更新时可采用滚动更新方式。这里要实现的更新时,将原本镜像为 tomcat:8.5.49 的 service 的镜像滚动更新为tomcat:8.5.39。
在 Manager Node 创建一个包含 10 个副本 task 的服务,该服务使用的镜像为 tomcat:8.5.49
-update-dely 表示更新服务或服务集之间的时间延迟,表示设置的延迟为 3 秒。 调度器默认一次更新一个任务,可以通过 --update-parallelism 参数配置调度器同时更新服务数量。默认情况下,当单个服务更新返回状态为 RUNNING,调度器会让另一个服务更新,直到所有服务都更新完成。如果在更新期间某个服务返回 FAILED ,调度器会暂停更新,可以通过 --update-failure-action 参数配置控制当服务更新发生错误时的行为。
这 10 个 task 被非常平均的分配到了 5 个 swarm 节点上了
notion image
将 service 使用的镜像由 tomcat:8.5.49 的 service 的镜像滚动更新为 tomcat:8.5.39,会发现这个更新的过程就是前面在创建服务时指定的那样,每次更新 2 个 task,更新间隔为 3 秒
notion image
更新完毕后再查看当前的 task 情况发现,已经将所有任务的镜像更新为了 8.5.39 版本
notion image

回滚

在更新过程中如果更新失败,则会按照设置的回滚策略进行回滚,回滚到更新前的状态。但用户也可通过命令方式手工回滚。下面的命令会按照前面设置的每次回滚 2 个 task,每次回滚间隔 3 秒进行回滚。下面的是回滚过程中的某个回滚瞬间
notion image
以下是回滚完毕后的结果
notion image
回滚完毕后再查看当前的 task 情况发现,已经将所有任务的镜像恢复为了 8.5.49 版本。但需要注意,task name 保持未变,但 task ID 与原来的 task ID 也是不同的,并不是恢复到了更新之前的 task ID。即编排器新创建了 task,并由分发器重新为其分配了 node
notion image

service 全局部署

service 以副本任务 task 的形式部署在 swarm 集群节点上。根据 task 数量与节点数量的关系,常见的 service 部署模式有两种:replicated 模式与 global 模式 replicated 模式:即副本模式,service 的默认部署模式。需要指定 task 的数量。当需要的副本任务 task 数量不等于 swarm 集群的节点数量时,就需要使用 replicated 模式。manager中的分发器会找到指定 task 个数的 available node 可用节点,然后为这些节点中的每个节点分配一个或若干个 task。 global 模式:即全局模式。分发器会为每个 swarm 集群节点分配一个 task,不能指定 task的数量。swarm 集群每增加一个节点,编排器就会创建一个 task,并通过分发器分配到新的节点上
notion image
前面创建的 service 是 replicated 模式的,下面来创建 global 模式的 service
notion image
为了后面的演示效果,这里先使 docker5 退群,让 swarm 集群的节点变为 4 个,在 docker5 节点执行
此时 docker5 的节点状态变为了 Down
notion image
将 docker5 节点再从 swarm 集群中删除
notion image
docker service create 命令中通过 --mode 选项可以指定要使用的 service 部署模式,默认为 replicated 模式
查看 service
notion image
该模式会在每个节点上分配一个 task
notion image
对于 global 模式来说,若要实现对 service 的 task 数量的变更,必须通过改变该 servicve 所依附的 swarm 集群的节点数量来改变。节点增加,则 task 会自动增加;节点减少,则 task会自动减少。下面要在这个 4 节点的 swarm 集群中增加一个节点,以使 toms 服务的 task 也增一。 首先在 manager 节点获取新增一个节点的 token
在 docker5 上运行加入命令,完成 swarm 的入群
查看 toms 服务的 task 详情,发现已经自动增加了一个 task
notion image

路由网格

docker swarm支持路由网格。路由网格让处于swarm集群中的任意一个节点都可以作为被访问的入口,即使此节点没有运行任何服务。要在 swarm 集群中使用使用路由网格,首先需要开启加入swarm集群的节点的以下端口: 7946:容器网络发现 4789:容器网络入口
其次需要将节点服务实例的端口公开,使服务可以被外部访问,例如使用nginx 做负载均衡
notion image
创建服务时公开端口
-publish 与 -p 效果相同,其中 published 值为公布的端口,target 值为容器内部监听的端口。
更新现有服务的公开端口
查看服务发布的端口

配置公开TCP或UDP端口

默认情况下公开端口都是 TCP 端口,你可以通过参数配置公开端口的类型: 仅TCP,两种写法
仅UDP,两种写法
TCP+UDP,两种写法

绕过路由网格

要绕过 swarm 集群的路由网格,需要使用 --publish 参数设置 mode 值为host。下面的命令使用 host 模式创建全局服务并绕过路由网格:
绕过路由网格后的注意事项:如果你访问未运行服务的节点,则无法访问此服务。如果你希望在每个节点运行多个服务,就不能指定静态的端口。要么就允许docker随机分配一个公开端口(通过置空 published 参数的值实现)

overlay 网络

overlay 网络,也称为重叠网络或覆盖网络,是一种构建于 underlay 网络之上的逻辑虚拟网络。即在物理网络的基础上,通过节点间的单播隧道机制将主机两两相连形成的一种虚拟的、独立的网络。 Docker Swarm 集群中的 overlay 网络主要是通过 iptables、ipvs、vxlan 等技术实现的、基于其本身通信需求的网络模型
notion image
Docker Swarm 集群的 overlay 网络模型在创建时,会创建出两个网络:docker_gwbidge 网络与 ingress 网络。这就是典型的 overlay 网络,在宿主机的物理网络之上又创建出新的网络。同时还创建出了 docker_gwbidge 网关与 br0 网关,及 ingress-sbox 容器。 当请求到达后会首先经由 docker_gwbidge 网关跳转到 ingress-sbox 容器,在其中具有当前整个service 的所有容器 IP,在其中通过轮询负载均衡方式选择一个容器IP 作为目标地址,然后再跳转到 br0 网关。在 br0 网关中会根据目标地址所在主机进行判断。若目标地址为本地容器 IP,则直接将请求转发给该容器处理即可。若目标地址非本地容器 IP,则会将请求经由 vxlan 接口,通过 vxlan 隧道技术将请求转发给目标地址容器。
分析 overlay 网络模型的通信原理之前,首先来了解一下 docker swarm 的 overlay 网络的基础信息。docker swarm 集群的 overlay 网络模型在创建时,会自动创建两个网络:docker_gwbridge 网络与 ingress 网络
notion image

docker_gwbridge

查看 docker_gwbridge 网络详情可以看到,docker_gwbridge 网络包含的子网为 172.18.0.0/16,其网关为 172.18.0.1
notion image
同时还看到,该网络中包含了 3 个容器。其中 2 个为 service 的 task 容器,另一个的容器 ID 为 ingress-sbox
notion image
从 docker_gwbridge 的网络详情中可以看到,其中 2 个为 service 的 task 容器,其 ID 由 64 位 16 进制数构成,而 ingress-sbox 容器的 ID 就是 ingress-sbox,与其它 2 个容器的 ID 构成方式完全不同。
执行 docker ps –a 命令查看当前主机中的所有容器,发现并没有 ingress-sbox 容器。为什么?因为 docker ps 命令的本质是 docker process status,查看的是当前主机中真实存在的容器进程的状态。而 ingress-sbox 容器是由 overlay 网络虚拟出的,并不是真实存在的进程,所以通过 docker ps 命令是查看不到的
notion image
docker_gwbridge 的网络详情中的网关 172.18.0.1 是谁呢?在宿主机中通过 ip a 命令查看宿主机的网络接口,可以看到 docker_gwbridge 接口的 IP 为 172.18.0.1。即 docker_gwbridge 网络中具有一个与网络名称同名的网关。同时还看到,下面的 3 个接口全部都是连接在 docker_gwbridge 上的
notion image
查看 docker_gwbridge 网络的 task 容器的接口情况,可以看到这些容器中正好有接口与 docker_gwbridge 网关中的相应接口构成 veth paire
notion image

ingress

overlay 网络除了创建了 docker_gwbridge 网络外,还创建了一个 ingress 网络。查看 ingress 网络详情可以看到,ingress 网络包含的子网为 10.0.0.0/24,其网关为 10.0.0.1
notion image
同时还看到,该网络中也包含了 3 个容器,这 3 个容器与 docker_gwbridge 网络中的 3个容器是相同的容器,虽然 Name 不同,IP 不同,但容器 ID 相同。说明这 3 个容器都同时连接在 2 个网络中
notion image
10.0.0.1 网关是谁呢? 每个容器都具有一个独立的网络空间,而每个 docker 主机中的网络命名空间,都是以文件的形式保存在/var/run/docker/netns 目录中。查看当前主机的网络空间:
notion image
查看 /var/run/docker/netns 目录中的命名空间发现,其包含的 4 个命名空间中,有 2 个命名空间是 2 个 task 容器的,它们的名称由 12 位长度的 16 进制数构成;ingress_sbox 是 ingress-sbox 容器的命名空间。那么,1-pfq75ijiz4 命名空间是谁呢?进入该命名空间,查看其接口信息
notion image
可以看到 2 号接口 br0 的 IP 为 10.0.0.1,即 ingress 网络的网关为 1-pfq75ijiz4 命名空间中的 br0。同时还看到,br0 上还连接着 4 个接口,说明 br0 就是一个网关。那么,都是谁连接在这 4 个接口上呢? 查看 ingress 网络的 task 容器的接口情况,可以看到这些容器中正好有接口与 br0 网关中的相应接口构成 veth paire
notion image
查看 ingress-sbox 容器的命名空间 ingress_sbox 的接口情况,可以看到该命名空间中正好也存在接口与 br0 网关中的相应接口构成 veth paire
notion image

swarm 安全

Docker 内置了 PKI(public key infrastructure,公钥基础设施),使得保障发布容器化的业务流程系统的安全性变得很简单。Swarm 节点之间采用 TLS 来鉴权、授权和加密通信。 具体来说是,当运行 docker swarm init 命令时,Docker 指定当前节点为一个 manager 节点。默认情况下,manager 节点会生成一个新的 swarm 的 CA 根证书以及一对密钥。同时, manager 节点还会生成两个 token,一个用于添加 worker 节点,一个用于添加 manager 节点。每个 token 包含上了 CA 根证书的 digest 和一个随机密钥。CA 根证书、一对密钥和随机密钥都将会被用在节点之间的通信上。
当有节点加入 Swarm 时,需要复制 manager 中相应的 docker swarm join 加入命令,并在该节点中运行。而这个过程主要是通过随机密钥这种对称验证方式保障通信安全的。
notion image
一旦节点加入了 Swarm 集群,那么它们间的通信全部都是通过 TLS 加密方式进行的。首先是通过 CA 证书对通信对方的身份进行验证,在验证通过后再进行数据通信。而通信的数据则是通过随机密钥加密过的。
notion image

CA 数字证书轮换

Swarm 的 CA 数字证书也是有可能被攻击、篡改的。为了保证 swarm 的数字证书的安全性,Swarm 提供了 CA 数字证书轮换机制,定期更换 CA 数字证书。默认 swarm 的 CA 数字证书 90 天轮换一次。 那么,用于轮换的新的 CA 数字证书来自于哪里呢?通过 docker swarm ca 命令可以指定外部 CA 数字证书,或生成新的 CA 数字证书。无论哪种数字证书变更方式,都需要 CA 根证书的加密/解密。而根证书也是会发生变化的,当 manager 运行了 docker swarm ca --rotate 命令后,会按顺序发生下面的事情: 1、Docker 会生成一个交叉签名(cross-signed)根证书,即新根证书是由旧的根证书签署生成的,这个交叉签名根证书将作为一个过渡性的根证书。这是为了确保节点仍然能够信任旧的根证书,也能使用新的根证书验证签名。 2、在 Docker 17.06 或者更高版本中,Docker 会通知所有节点立即更新根证书。根据 swarm中节点数量多少,这个过程可能会花费几分钟时间。 3、在所有的节点都更新了新 CA 根证书后,manager 会通知所有节点仅信任新的根证书,不再信任旧根证书及交叉签名根证书。 4、所有节点使用新根证书签发自己的数字证书。
如果直接使用外部的 CA 根证书,那么就不存在交叉签名根证书的生成过程,直接由运行 docker swarm ca 命令的节点通知所有节点立即更新根证书。后续过程与前面的就相同了。

集群容灾

Swarm 的 manager 节点集群采用的是热备方式来提升集群的容灾能力。即在 manager集群中只有一个处于 leader 状态,用于完成 swarm 节点的管理,其余 manager 处于热备状态。当 manager leader 宕机,其余 manager 就会自动发起 leader 选举,重新选举产生一个新的 manager leader。
manager 集群的 leader 选举采用的是 Raft 算法。Raft 算法是一种比较复杂的一致性算法,具体见后面“Raft 算法”。其选举 leader 的简单思路是,所有可用的 manager 全部具有选举权与被选举权。最终获得过半选票的 manager 当选新的 leader。为了保证一次性可以选举出新的 leader,官方推荐使用奇数个manager。但并不是说偶数个manager 就无法选举出leader。

容灾模拟

目前是 docker、docker2、docker3 三个 manager,其中 docker 为 leader
notion image
现在关闭 docker 主机的 docker daemon,模拟宕机
然后在 docker2 或 docker3 主机上查看当前的节点情况,可以看到 docker2 或 docker3 已经成为了新的 leader
notion image
此时如果再使某个 manager 宕机,例如使 docker2 的docker daemon 关闭,那么整个swarm 就会瘫痪。因为剩下的 manager 已经无法达成过半的选票,无法选举出新的 leader。现在关闭 docker2 主机的 docker daemon,模拟宕机
此时在 docker3 主机执行命令
notion image
上一篇
docker网络
下一篇
kubernetes