管理和维护 Docker Engine 的 swarm
当您运行 Docker 引擎的 swarm 时,管理器节点是管理 swarm 和存储 swarm 状态的关键组件。了解管理器节点的一些关键特性对于正确部署和维护 swarm 非常重要。
有关 Docker Swarm 模式的简要概述以及管理器和工作节点之间的区别,请参阅节点如何工作。
在 swarm 中操作管理器节点
Swarm 管理器节点使用 Raft 共识算法来管理 swarm 状态。您只需要了解 Raft 的一些一般概念即可管理 swarm。
管理器节点的数量没有限制。实施多少个管理器节点的决定是性能和容错之间的权衡。向 swarm 添加管理器节点可以使 swarm 更具容错性。但是,额外的管理器节点会降低写入性能,因为更多节点必须确认更新 swarm 状态的提案。这意味着更多的网络往返流量。
Raft 需要大多数管理器(也称为法定人数)同意对 swarm 的提议更新,例如节点的添加或删除。成员资格操作受到与状态复制相同的约束。
维护管理器的法定人数
如果 swarm 失去了管理器的法定人数,swarm 就无法执行管理任务。如果您的 swarm 有多个管理器,请始终保持两个以上。为了维持法定人数,大多数管理器必须可用。建议使用奇数个管理器,因为下一个偶数并不会使法定人数更容易维持。例如,无论您有 3 个还是 4 个管理器,您仍然只能失去 1 个管理器并维持法定人数。如果您有 5 个或 6 个管理器,您仍然只能失去两个。
即使一个 swarm 失去了管理器的法定人数,现有工作节点上的 swarm 任务仍会继续运行。但是,swarm 节点不能被添加、更新或删除,新的或现有的任务不能被启动、停止、移动或更新。
如果您确实失去了管理器的法定人数,请参阅从失去法定人数中恢复以获取故障排除步骤。
配置管理器以在静态 IP 地址上进行广播
在初始化一个 swarm 时,您必须指定 --advertise-addr 标志,以便向 swarm 中的其他管理器节点广播您的地址。有关更多信息,请参阅在 swarm 模式下运行 Docker 引擎。因为管理器节点旨在成为基础设施的稳定组件,您应该为广播地址使用一个固定的 IP 地址,以防止 swarm 在机器重启时变得不稳定。
如果整个 swarm 重启,并且每个管理器节点随后都获得了一个新的 IP 地址,那么任何节点都无法联系到现有的管理器。因此,当节点尝试用旧的 IP 地址相互联系时,swarm 会挂起。
动态 IP 地址对于工作节点来说是可以的。
添加管理器节点以实现容错
您应该在 swarm 中维护奇数个管理器,以支持管理器节点故障。拥有奇数个管理器可确保在网络分区期间,如果网络被分成两组,法定人数有更高的机会保持可用以处理请求。如果您遇到两个以上的网络分区,则无法保证维持法定人数。
| Swarm 大小 | 多数 | 容错能力 |
|---|---|---|
| 1 | 1 | 0 |
| 2 | 2 | 0 |
| 3 | 2 | 1 |
| 4 | 3 | 1 |
| 5 | 3 | 2 |
| 6 | 4 | 2 |
| 7 | 4 | 3 |
| 8 | 5 | 3 |
| 9 | 5 | 4 |
例如,在一个有 5 个节点的 swarm 中,如果您失去了 3 个节点,您就没有法定人数。因此,您不能添加或删除节点,直到您恢复一个不可用的管理器节点或使用灾难恢复命令恢复 swarm。请参阅从灾难中恢复。
虽然可以将 swarm 缩减到单个管理器节点,但不可能降级最后一个管理器节点。这可以确保您保持对 swarm 的访问,并且 swarm 仍然可以处理请求。缩减到单个管理器是一个不安全的操作,不推荐使用。如果在降级操作期间最后一个节点意外离开 swarm,swarm 将变得不可用,直到您重新启动该节点或使用 --force-new-cluster 重新启动。
您可以使用 docker swarm 和 docker node 子系统管理 swarm 成员资格。有关如何添加工作节点和将工作节点提升为管理器的更多信息,请参阅向 swarm 添加节点。
分发管理器节点
除了维护奇数个管理器节点外,在放置管理器时还要注意数据中心拓扑。为了获得最佳的容错性,请将管理器节点分布在至少 3 个可用区,以支持整套机器的故障或常见的维护场景。如果您在任何一个区域遇到故障,swarm 应该保持管理器节点的法定人数可用,以处理请求和重新平衡工作负载。
| Swarm 管理器节点 | 重新分区(在 3 个可用区) |
|---|---|
| 3 | 1-1-1 |
| 5 | 2-2-1 |
| 7 | 3-2-2 |
| 9 | 3-3-3 |
运行仅管理器的节点
默认情况下,管理器节点也充当工作节点。这意味着调度程序可以将任务分配给管理器节点。对于小型和非关键的 swarm,只要您使用 CPU 和内存的资源约束来调度服务,将任务分配给管理器相对风险较低。
然而,由于管理器节点使用 Raft 共识算法以一致的方式复制数据,它们对资源匮乏很敏感。您应该将 swarm 中的管理器与可能阻塞 swarm 操作(如 swarm 心跳或领导者选举)的进程隔离开来。
为避免干扰管理器节点操作,您可以排空管理器节点,使其作为工作节点不可用
$ docker node update --availability drain <NODE>
当您排空一个节点时,调度程序会将该节点上运行的任何任务重新分配给 swarm 中其他可用的工作节点。它还会阻止调度程序向该节点分配任务。
添加工作节点以实现负载均衡
向 swarm 添加节点以平衡您的 swarm 的负载。只要工作节点符合服务的要求,复制的服务任务就会随着时间的推移尽可能均匀地分布在整个 swarm 中。当将服务限制为仅在特定类型的节点上运行时,例如具有特定数量 CPU 或内存量的节点,请记住不满足这些要求的工作节点无法运行这些任务。
监控 swarm 健康状况
您可以通过 HTTP /nodes 端点以 JSON 格式查询 docker nodes API 来监控管理器节点的健康状况。有关更多信息,请参阅nodes API 文档。
在命令行中,运行 docker node inspect <id-node> 来查询节点。例如,查询节点作为管理器的可达性
$ docker node inspect manager1 --format "{{ .ManagerStatus.Reachability }}"
reachable
查询节点作为接受任务的工作节点的状态
$ docker node inspect manager1 --format "{{ .Status.State }}"
ready
从这些命令中,我们可以看到 manager1 作为管理器处于 reachable 状态,作为工作节点处于 ready 状态。
一个 unreachable 的健康状态意味着这个特定的管理器节点无法从其他管理器节点访问。在这种情况下,您需要采取措施来恢复无法访问的管理器
- 重新启动守护进程,看看管理器是否恢复为可达状态。
- 重启机器。
- 如果重启或重启都不起作用,您应该添加另一个管理器节点或将一个工作节点提升为管理器节点。您还需要使用
docker node demote <NODE>和docker node rm <id-node>从管理器集中干净地删除失败的节点条目。
或者,您也可以从管理器节点使用 docker node ls 获取 swarm 健康状况的概览
$ docker node ls
ID HOSTNAME MEMBERSHIP STATUS AVAILABILITY MANAGER STATUS
1mhtdwhvsgr3c26xxbnzdc3yp node05 Accepted Ready Active
516pacagkqp2xc3fk9t1dhjor node02 Accepted Ready Active Reachable
9ifojw8of78kkusuc4a6c23fx * node01 Accepted Ready Active Leader
ax11wdpwrrb6db3mfjydscgk7 node04 Accepted Ready Active
bb1nrq2cswhtbg4mrsqnlx1ck node03 Accepted Ready Active Reachable
di9wxgz8dtuh9d2hn089ecqkf node06 Accepted Ready Active
对管理器节点进行故障排除
您永远不应该通过从另一个节点复制 raft 目录来重新启动管理器节点。数据目录对于一个节点 ID 是唯一的。一个节点只能使用一个节点 ID 一次加入 swarm。节点 ID 空间应该是全局唯一的。
要干净地将管理器节点重新加入集群
- 使用
docker node demote <NODE>将节点降级为工作节点。 - 使用
docker node rm <NODE>从 swarm 中删除节点。 - 使用
docker swarm join以全新状态将节点重新加入 swarm。
有关将管理器节点加入 swarm 的更多信息,请参阅将节点加入 swarm。
强制删除节点
在大多数情况下,您应该在用 docker node rm 命令从 swarm 中删除节点之前先关闭它。如果一个节点变得无法访问、无响应或被入侵,您可以通过传递 --force 标志强制删除该节点而不关闭它。例如,如果 node9 被入侵
$ docker node rm node9
Error response from daemon: rpc error: code = 9 desc = node node9 is not down and can't be removed
$ docker node rm --force node9
Node node9 removed from swarm
在强制删除管理器节点之前,必须先将其降级为工作节点角色。如果您降级或删除管理器,请确保始终有奇数个管理器节点。
备份 swarm
Docker 管理器节点将 swarm 状态和管理器日志存储在 /var/lib/docker/swarm/ 目录中。此数据包括用于加密 Raft 日志的密钥。没有这些密钥,您无法恢复 swarm。
您可以使用任何管理器来备份 swarm。请使用以下步骤。
如果 swarm 启用了自动锁定,您需要解锁密钥才能从备份中恢复 swarm。如有必要,请检索解锁密钥并将其存放在安全的位置。如果您不确定,请阅读锁定您的 swarm以保护其加密密钥。
在备份数据之前,请在管理器上停止 Docker,以便在备份期间没有数据被更改。可以在管理器运行时进行备份(“热”备份),但不推荐这样做,恢复时的结果可预测性较差。当管理器关闭时,其他节点会继续生成不属于此备份的 swarm 数据。
注意确保维护 swarm 管理器的法定人数。在管理器关闭期间,如果更多节点丢失,您的 swarm 将更容易失去法定人数。您运行的管理器数量是一种权衡。如果您定期关闭管理器进行备份,请考虑运行一个五管理器的 swarm,这样在备份运行时您可以再失去一个管理器,而不会中断您的服务。
备份整个
/var/lib/docker/swarm目录。重新启动管理器。
要恢复,请参阅从备份中恢复。
从灾难中恢复
从备份中恢复
在按照备份 swarm 中所述备份 swarm 后,使用以下步骤将数据恢复到一个新的 swarm。
在用于恢复 swarm 的目标主机上关闭 Docker。
移除新 swarm 上
/var/lib/docker/swarm目录的内容。用备份的内容恢复
/var/lib/docker/swarm目录。注意新节点使用与旧节点相同的磁盘存储加密密钥。目前无法更改磁盘存储加密密钥。
在启用了自动锁定的 swarm 中,解锁密钥也与旧 swarm 上的相同,并且需要解锁密钥来恢复 swarm。
在新节点上启动 Docker。如有必要,解锁 swarm。使用以下命令重新初始化 swarm,以便此节点不会尝试连接到属于旧 swarm 且可能已不存在的节点。
$ docker swarm init --force-new-cluster验证 swarm 的状态是否符合预期。这可能包括特定于应用程序的测试,或者简单地检查
docker service ls的输出以确保所有预期的服务都存在。如果您使用自动锁定,请轮换解锁密钥。
添加管理器和工作节点,使您的新 swarm 达到运行能力。
在新 swarm 上恢复您以前的备份方案。
从失去法定人数中恢复
Swarm 对故障具有弹性,可以从任何数量的临时节点故障(机器重启或崩溃后重启)或其他瞬时错误中恢复。但是,如果 swarm 失去法定人数,则无法自动恢复。现有工作节点上的任务会继续运行,但管理任务(包括扩展或更新服务以及从 swarm 加入或移除节点)将无法进行。最好的恢复方法是让丢失的管理器节点重新上线。如果无法做到这一点,请继续阅读以了解一些恢复 swarm 的选项。
在拥有 N 个管理器的 swarm 中,必须始终有法定人数(多数)的管理器节点可用。例如,在一个有五个管理器的 swarm 中,至少必须有三个管理器处于运行状态并相互通信。换句话说,swarm 可以容忍最多 (N-1)/2 个永久性故障,超出这个数量,涉及 swarm 管理的请求就无法处理。这些类型的故障包括数据损坏或硬件故障。
如果您失去了管理器的法定人数,您就无法管理 swarm。如果您失去了法定人数并试图对 swarm 执行任何管理操作,将会出现错误
Error response from daemon: rpc error: code = 4 desc = context deadline exceeded从失去法定人数中恢复的最佳方法是让发生故障的节点重新上线。如果您无法做到这一点,从这种状态恢复的唯一方法是从一个管理器节点使用 --force-new-cluster 操作。这将移除除运行该命令的管理器之外的所有管理器。由于现在只有一个管理器,因此达到了法定人数。将节点提升为管理器,直到您拥有所需数量的管理器。
从要恢复的节点运行
$ docker swarm init --force-new-cluster --advertise-addr node01:2377
当您使用 --force-new-cluster 标志运行 docker swarm init 命令时,您运行该命令的 Docker 引擎将成为一个单节点 swarm 的管理器节点,该 swarm 能够管理和运行服务。该管理器拥有所有关于服务和任务的先前信息,工作节点仍然是 swarm 的一部分,服务也仍在运行。您需要添加或重新添加管理器节点,以实现您之前的任务分发,并确保您有足够的管理器来维持高可用性并防止失去法定人数。
强制 swarm 重新平衡
通常,您不需要强制 swarm 重新平衡其任务。当您向 swarm 添加一个新节点,或者一个节点在一段时间不可用后重新连接到 swarm 时,swarm 不会自动将工作负载分配给空闲节点。这是一个设计决策。如果 swarm 为了平衡而定期将任务转移到不同的节点,那么使用这些任务的客户端将会中断。目标是避免为了 swarm 的平衡而中断正在运行的服务。当新任务启动时,或者当运行任务的节点变得不可用时,这些任务会被分配给较不繁忙的节点。目标是最终的平衡,对最终用户的干扰最小。
您可以使用 docker service update 命令的 --force 或 -f 标志来强制服务在可用的工作节点之间重新分配其任务。这将导致服务任务重启。客户端应用程序可能会中断。如果您已配置,您的服务将使用滚动更新。
如果您使用的是早期版本,并且希望在工作节点之间实现负载的均匀平衡,且不介意中断正在运行的任务,您可以通过临时向上扩展服务来强制您的 swarm 重新平衡。使用 docker service inspect --pretty <servicename> 来查看服务的配置规模。当您使用 docker service scale 时,任务数量最少的节点将被目标接收新的工作负载。您的 swarm 中可能存在多个负载不足的节点。您可能需要多次以适度的增量向上扩展服务,以在所有节点上实现您想要的平衡。
当负载平衡到您满意的程度时,您可以将服务缩减回原始规模。您可以使用 docker service ps 来评估您服务在各节点间的当前平衡状况。