管理和维护 Docker Engine 集群

当你运行一个 Docker Engine 集群时,管理器节点是管理集群和存储集群状态的关键组件。了解管理器节点的一些关键特性对于正确部署和维护集群至关重要。

请参阅节点工作原理,简要了解 Docker Swarm 模式以及管理器节点和工作节点之间的区别。

在集群中操作管理器节点

Swarm 管理器节点使用Raft 共识算法来管理集群状态。你只需了解 Raft 的一些通用概念即可管理集群。

管理器节点的数量没有限制。实施多少管理器节点的决定是在性能和容错能力之间权衡的结果。向集群添加管理器节点会提高集群的容错能力。但是,额外的管理器节点会降低写性能,因为更多的节点必须确认更新集群状态的提案。这意味着更多的网络往返流量。

Raft 要求多数管理器节点(也称为法定人数,quorum)就集群的提议更新达成一致,例如节点添加或移除。成员操作受与状态复制相同的约束。

维护管理器法定人数 (quorum)

如果集群失去管理器节点的法定人数,集群将无法执行管理任务。如果你的集群有多个管理器,始终保持三个以上。为了维护法定人数,必须有多数管理器可用。建议使用奇数个管理器,因为下一个偶数并不会更容易保持法定人数。例如,无论你有 3 个还是 4 个管理器,你都只能损失 1 个管理器并保持法定人数。如果你有 5 个或 6 个管理器,你仍然只能损失两个。

即使集群失去管理器节点的法定人数,现有工作节点上的集群任务仍会继续运行。但是,无法添加、更新或移除集群节点,也无法启动、停止、移动或更新新的或现有任务。

如果你确实丢失了管理器节点的法定人数,请参阅从法定人数丢失中恢复以获取故障排除步骤。

配置管理器在静态 IP 地址上进行广告

初始化集群时,你必须指定 --advertise-addr 标志以向集群中的其他管理器节点通告你的地址。有关详细信息,请参阅在 Swarm 模式下运行 Docker Engine。由于管理器节点是基础设施的稳定组件,你应该使用固定 IP 地址作为通告地址,以防止集群在机器重启时变得不稳定。

如果整个集群重启,并且每个管理器节点随后都获得一个新的 IP 地址,则任何节点都无法联系到现有的管理器。因此,当节点尝试通过其旧 IP 地址相互联系时,集群将停滞不前。

动态 IP 地址对于工作节点来说是可以接受的。

添加管理器节点以实现容错

你应该在集群中保持奇数个管理器,以支持管理器节点故障。奇数个管理器可以确保在网络分区期间,如果网络被分成两组,法定人数更有可能仍然可用以处理请求。如果你遇到两次以上的网络分区,则无法保证保持法定人数。

集群大小多数容错能力
110
220
321
431
532
642
743
853
954

例如,在一个拥有 5 个节点的集群中,如果你失去 3 个节点,你就失去了法定人数。因此,在恢复其中一个不可用的管理器节点或使用灾难恢复命令恢复集群之前,你无法添加或移除节点。请参阅从灾难中恢复

虽然可以将集群缩减到单个管理器节点,但无法降级最后一个管理器节点。这确保你可以继续访问集群,并且集群仍然可以处理请求。缩减到单个管理器是一种不安全的操作,不建议这样做。如果在降级操作期间最后一个节点意外离开集群,则集群将不可用,直到你重新启动该节点或使用 --force-new-cluster 重新启动。

你可以使用 docker swarmdocker node 子系统管理集群成员。有关如何添加工作节点以及将工作节点提升为管理器的详细信息,请参阅向集群添加节点

分布式管理器节点

除了保持奇数个管理器节点外,在放置管理器时还应注意数据中心拓扑结构。为了获得最佳容错能力,请将管理器节点分布在至少 3 个可用区域中,以支持整个机器组的故障或常见维护场景。如果在这些区域中的任何一个发生故障,集群应保持法定数量的管理器节点可用,以处理请求并重新平衡工作负载。

Swarm 管理器节点重新分区(在 3 个可用区域)
31-1-1
52-2-1
73-2-2
93-3-3

运行仅作为管理器的节点

默认情况下,管理器节点也充当工作节点。这意味着调度器可以将任务分配给管理器节点。对于小型和非关键集群,只要你使用 CPU 和内存的资源约束来调度服务,将任务分配给管理器就是相对低风险的。

但是,由于管理器节点使用 Raft 共识算法以一致的方式复制数据,它们对资源不足很敏感。你应该将集群中的管理器与可能阻塞集群操作(如集群心跳或领导者选举)的进程隔离。

为了避免干扰管理器节点操作,你可以排空管理器节点,使其不再作为工作节点可用

$ docker node update --availability drain <NODE>

当你排空节点时,调度器会将该节点上运行的所有任务重新分配给集群中其他可用的工作节点。它还会阻止调度器将任务分配给该节点。

添加工作节点以实现负载均衡

向集群添加节点以平衡集群的负载。复制服务任务会随着时间的推移尽可能均匀地分布在集群中,前提是工作节点符合服务的需求。当限制服务仅在特定类型的节点上运行时,例如具有特定 CPU 数量或内存量的节点,请记住不满足这些要求的工作节点无法运行这些任务。

监控集群健康状况

你可以通过 /nodes HTTP 端点查询 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 从管理器节点获取集群健康状况的概览

$ 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 加入集群一次。节点 ID 空间应该是全局唯一的。

要干净地将管理器节点重新加入集群

  1. 使用 docker node demote <NODE> 将节点降级为工作节点。
  2. 使用 docker node rm <NODE> 从集群中移除节点。
  3. 使用 docker swarm join 以全新状态重新加入集群。

有关将管理器节点加入集群的更多信息,请参阅将节点加入集群

强制移除节点

在大多数情况下,在使用 docker node rm 命令从集群中移除节点之前,你应该先关闭节点。如果节点变得不可达、无响应或受损,你可以通过传递 --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

在强制移除管理器节点之前,你必须先将其降级为工作节点角色。如果你降级或移除管理器,请确保始终保持奇数个管理器节点。

备份集群

Docker 管理器节点将集群状态和管理器日志存储在 /var/lib/docker/swarm/ 目录中。这些数据包含用于加密 Raft 日志的密钥。没有这些密钥,你将无法恢复集群。

你可以使用任何管理器备份集群。请按照以下步骤操作。

  1. 如果集群启用了自动锁定,你需要解锁密钥才能从备份中恢复集群。如果需要,请检索解锁密钥并将其存储在安全位置。如果不确定,请阅读锁定集群以保护其加密密钥

  2. 在备份数据之前停止管理器上的 Docker,这样备份期间就不会更改数据。可以在管理器运行时进行备份(“热”备份),但不建议这样做,恢复时的结果也较难预测。在管理器关闭期间,其他节点会继续生成不属于此备份的集群数据。

    注意

    请务必维护集群管理器的法定人数。在管理器关闭期间,如果进一步损失节点,你的集群更容易失去法定人数。你运行的管理器数量是一个权衡。如果你定期停下管理器进行备份,请考虑运行一个包含五个管理器的集群,这样在备份运行时即使再损失一个管理器,也不会中断你的服务。

  3. 备份整个 /var/lib/docker/swarm 目录。

  4. 重新启动管理器。

要恢复,请参阅从备份恢复

从灾难中恢复

从备份恢复

按照备份集群中描述的方法备份集群后,请使用以下步骤将数据恢复到新的集群。

  1. 在用于恢复集群的目标主机上关闭 Docker。

  2. 移除新集群上 /var/lib/docker/swarm 目录的内容。

  3. 使用备份内容恢复 /var/lib/docker/swarm 目录。

    注意

    新节点使用与旧节点相同的磁盘存储加密密钥。目前无法更改磁盘存储加密密钥。

    对于启用了自动锁定的集群,解锁密钥也与旧集群上的相同,并且需要解锁密钥才能恢复集群。

  4. 在新节点上启动 Docker。如果需要,解锁集群。使用以下命令重新初始化集群,以便该节点不会尝试连接到属于旧集群且可能不再存在的节点。

    $ docker swarm init --force-new-cluster
    
  5. 验证集群状态是否符合预期。这可能包括特定于应用程序的测试,或者只是检查 docker service ls 的输出以确保所有预期服务都存在。

  6. 如果你使用自动锁定,请轮换解锁密钥

  7. 添加管理器和工作节点,使新集群达到运行容量。

  8. 在新集群上恢复先前的备份方案。

从法定人数丢失中恢复

Swarm 具有容错能力,可以从任意数量的临时节点故障(机器重启或崩溃并重启)或其他瞬时错误中恢复。但是,如果集群失去法定人数,则无法自动恢复。现有工作节点上的任务会继续运行,但无法执行管理任务,包括扩展或更新服务以及向集群添加或移除节点。恢复的最佳方法是使缺失的管理器节点重新在线。如果无法做到,请继续阅读有关恢复集群的一些选项。

在一个包含 N 个管理器的集群中,必须始终有法定人数(多数)的管理器节点可用。例如,在一个包含五个管理器的集群中,至少有三个必须正常运行并相互通信。换句话说,集群可以容忍最多 (N-1)/2 个永久性故障,超过此数量后,涉及集群管理的请求将无法处理。这些类型的故障包括数据损坏或硬件故障。

如果你失去了管理节点的法定人数(quorum),你就无法管理 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

当你在运行 docker swarm init 命令时加上 --force-new-cluster 标志,运行该命令的 Docker Engine 将成为单节点 swarm 的管理节点,该节点能够管理和运行服务。该管理节点拥有关于服务和任务的所有先前信息,工作节点仍然是 swarm 的一部分,并且服务仍在运行。你需要添加或重新添加管理节点,以恢复你之前的任务分布,并确保有足够的管理节点来维护高可用性并防止失去法定人数。

强制集群重新平衡

通常情况下,你不需要强制 swarm 重新平衡其任务。当你向 swarm 添加新节点,或者节点在一段不可用时间后重新连接到 swarm 时,swarm 不会自动将工作负载分配给空闲节点。这是一个设计决策。如果 swarm 为了平衡而周期性地将任务转移到不同的节点,使用这些任务的客户端就会受到干扰。其目标是避免为了 swarm 整体的平衡而干扰正在运行的服务。当新的任务启动时,或者当一个有运行任务的节点变得不可用时,这些任务会被分配给负载较低的节点。目标是最终达到平衡,同时对最终用户造成最小的干扰。

你可以使用 docker service update 命令配合 --force-f 标志来强制服务重新将其任务分布到可用的工作节点上。这会导致服务任务重启。客户端应用程序可能会受到干扰。如果你已配置,你的服务将使用 滚动更新(rolling update)

如果你使用的是早期版本,并且想要在工作节点之间实现负载的均衡分配,同时不介意中断正在运行的任务,你可以通过暂时向上扩展服务来强制你的 swarm 重新平衡。使用 docker service inspect --pretty <servicename> 查看服务的配置规模。当你使用 docker service scale 时,任务数量最少的节点将被指定接收新的工作负载。你的 swarm 中可能存在多个负载较低的节点。你可能需要以适度的增量多次向上扩展服务,以便在所有节点之间达到所需的平衡。

当负载平衡到你满意时,你可以将服务规模缩减回原始规模。你可以使用 docker service ps 来评估服务在节点间的当前平衡状况。

另请参阅 docker service scaledocker service ps

页面选项