管理和维护 Docker Engine 集群

当您运行一个 Docker Engine 集群时,管理节点是管理该集群和存储集群状态的关键组件。为了正确地部署和维护集群,理解管理节点的一些关键特性非常重要。

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

在集群中操作管理节点

Swarm 管理节点使用 Raft 共识算法 来管理集群状态。您只需要了解 Raft 的一些基本概念,就可以管理一个集群。

对管理节点的数量没有限制。决定实施多少个管理节点,是在性能和容错能力之间的权衡。向集群中添加管理节点可以使集群更具容错能力。然而,额外的管理节点会降低写入性能,因为必须有更多节点确认对集群状态的更新提议。这意味着更多的网络往返流量。

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

维护管理节点的法定人数

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

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

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

配置管理节点以使用静态 IP 地址进行广播

在初始化集群时,您必须指定 --advertise-addr 标志,以便将您的地址广播给集群中的其他管理节点。有关更多信息,请参阅在 Swarm 模式下运行 Docker Engine。由于管理节点旨在成为基础设施的稳定组件,您应该为广播地址使用固定的 IP 地址,以防止集群在机器重启后变得不稳定。

如果整个集群重启,并且每个管理节点随后都获得了一个新的 IP 地址,那么任何节点都无法联系到现有的管理节点。因此,当节点尝试通过旧的 IP 地址相互联系时,集群将处于挂起状态。

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

添加管理节点以实现容错

您应该在集群中保持奇数个管理节点,以支持管理节点故障。拥有奇数个管理节点可确保在网络分区期间,如果网络被分成两个集合,法定人数仍有更高几率保持可用以处理请求。如果您遇到超过两个网络分区,则无法保证维持法定人数。

集群规模 多数(法定人数) 容错节点数
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 个节点的集群中,如果您丢失了3 个节点,您就没有法定人数了。因此,在恢复一个不可用的管理节点或使用灾难恢复命令恢复集群之前,您无法添加或移除节点。请参阅从灾难中恢复

虽然可以将集群缩减到单个管理节点,但无法降级最后一个管理节点。这确保您始终可以访问集群,并且集群仍能处理请求。缩减到单个管理节点是不安全的操作,不建议这样做。如果在降级操作期间最后一个节点意外离开集群,那么在您重启该节点或使用 --force-new-cluster 重启之前,集群将不可用。

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

分布管理节点

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

管理节点数量 分配方案(在 3 个可用区中)
3 1-1-1
5 2-2-1
7 3-2-2
9 3-3-3

运行仅管理模式节点

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

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

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

$ docker node update --availability drain <NODE>

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

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

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

监控集群健康状况

您可以通过 /nodes HTTP 端点以 JSON 格式查询 docker nodes API 来监控管理节点的健康状况。有关更多信息,请参阅 节点 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,以便在备份期间没有数据被更改。可以在管理节点运行时(“热”备份)进行备份,但不推荐这样做,并且在恢复时结果的可预测性较差。在管理节点关闭期间,其他节点会继续生成不属于此备份的集群数据。

    Note

    请务必保持集群管理者的法定人数。在管理机关闭期间,如果进一步丢失节点,您的集群更容易失去法定人数。您运行的管理者数量是一种权衡。如果您经常为进行备份而关闭管理器,请考虑运行一个五个管理器的集群,以便在备份运行期间可以额外丢失一个管理器,而不会中断您的服务。

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

  4. 重启管理器。

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

从灾难中恢复

从备份中恢复

按照备份集群中所述备份集群后,使用以下过程将数据恢复到新集群。

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

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

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

    Note

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

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

  4. 在新节点上启动 Docker。必要时解锁集群。使用以下命令重新初始化集群,以便此节点不会尝试连接到旧集群中的节点(这些节点很可能已不存在)。

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

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

  7. 添加管理节点和工作节点,使您的新集群恢复到运行能力。

  8. 在新集群上重新建立您之前的备份方案。

从法定人数丢失中恢复

Swarm 对故障具有弹性,可以从任何数量的临时节点故障(机器重启或崩溃后重启)或其他瞬时错误中恢复。但是,如果集群失去法定人数,它将无法自动恢复。现有工作节点上的任务继续运行,但管理任务无法执行,包括扩展或更新服务,以及加入或移除集群中的节点。最好的恢复方法是让丢失的管理节点重新上线。如果无法做到这一点,请继续阅读以下一些恢复集群的选项。

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

如果您失去了管理节点的法定人数,就无法管理该集群。如果您失去了法定人数并尝试对集群执行任何管理操作,则会发生错误:

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 Engine 将成为单节点集群的管理节点,该集群能够管理和运行服务。该管理器拥有关于服务和任务的所有先前信息,工作节点仍属于集群的一部分,服务也仍在运行。您需要添加或重新添加管理节点,以实现您之前的任务分配,并确保您有足够的管理器来维持高可用性并防止失去法定人数。

强制集群重新平衡

通常,您不需要强制集群重新平衡其任务。当您向集群添加新节点,或者一个节点在一段不可用后重新连接到集群时,集群不会自动将工作负载分配给空闲节点。这是一个设计决策。如果集群为了平衡而周期性地将任务转移到不同的节点,那么使用这些任务的客户端将会被中断。目标是为了避免为了集群的平衡而中断正在运行的服务。当新任务启动时,或者当运行任务的节点变得不可用时,这些任务会被分配给较不繁忙的节点。目标是最终达到平衡,并最大限度地减少对最终用户的干扰。

您可以对 docker service update 命令使用 --force-f 标志,以强制服务将其任务重新分配给可用的工作节点。这会导致服务任务重启。客户端应用程序可能会被中断。如果您已配置,您的服务将使用滚动更新

如果您使用的是较早版本,并且希望在工作节点之间实现负载的均匀分布,并且不介意中断正在运行的任务,您可以通过临时扩展服务来强制集群重新平衡。使用 docker service inspect --pretty <servicename> 查看服务的配置规模。当您使用 docker service scale 时,任务数量最少的节点将成为接收新工作负载的目标。您的集群中可能有多个负载不足的节点。您可能需要多次以较小的增量扩展服务,以在所有节点上实现您想要的平衡。

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

另请参阅 docker service scaledocker service ps