安全排空节点
本页面介绍如何安全地腾空(drain)节点,并可选择性地遵循你所定义的 PodDisruptionBudget。
在你开始之前
本任务假设你满足以下先决条件
- 在节点腾空期间,你的应用程序不要求具备高可用性;或者
- 你已经了解了PodDisruptionBudget 概念,并已为需要它的应用程序配置了 PodDisruptionBudget。
(可选)配置中断预算
为了确保你的工作负载在维护期间保持可用,你可以配置一个PodDisruptionBudget。
如果可用性对于运行在你正在腾空的节点上或可能运行在其上的任何应用程序都很重要,请先配置 PodDisruptionBudget,然后再继续遵循本指南。
建议将 PodDisruptionBudget 的不健康 Pod 驱逐策略(Unhealthy Pod Eviction Policy)设置为 AlwaysAllow
,以便在节点腾空期间支持驱逐行为异常的应用程序。默认行为是在腾空继续之前等待应用程序 Pod 变为健康。
使用 kubectl drain
将节点从服务中移除
你可以在对节点执行维护(例如,内核升级、硬件维护等)之前使用 kubectl drain
安全地驱逐节点上的所有 Pod。安全的驱逐允许 Pod 的容器优雅地终止,并且会遵循你所指定的 PodDisruptionBudget。
当 kubectl drain
成功返回时,表明所有 Pod(除了上一段中描述的被排除的 Pod)已安全地被驱逐(遵循了预期的优雅终止期限,并遵循你所定义的 PodDisruptionBudget)。此时,你可以安全地关闭物理机或(如果在云平台上运行)删除其虚拟机来停用节点。
说明
如果任何新的 Pod 容忍了 node.kubernetes.io/unschedulable
污点,那么这些 Pod 可能被调度到你已腾空的节点上。除了 DaemonSet 之外,应避免容忍此污点。
如果你或另一个 API 用户直接为 Pod 设置了nodeName
字段(绕过了调度器),那么该 Pod 将被绑定到指定的节点并在那里运行,即使你已经腾空该节点并将其标记为不可调度。
首先,确定要腾空的节点的名称。你可以使用以下命令列出集群中的所有节点
kubectl get nodes
接下来,告诉 Kubernetes 腾空该节点
kubectl drain --ignore-daemonsets <node name>
如果存在由 DaemonSet 管理的 Pod,你需要使用 kubectl
指定 --ignore-daemonsets
才能成功腾空节点。仅使用 kubectl drain
子命令并不能真正腾空节点上的 DaemonSet Pod:DaemonSet 控制器(控制平面的一部分)会立即用新的等效 Pod 替换丢失的 Pod。DaemonSet 控制器还会创建忽略不可调度污点的 Pod,这使得新的 Pod 可以启动到你正在腾空的节点上。
一旦命令返回(没有出错),你可以关闭节点(或者,如果在云平台上,删除支持该节点的虚拟机)。如果在维护操作期间将节点留在集群中,你需要在之后运行
kubectl uncordon <node name>
以告知 Kubernetes 可以恢复在该节点上调度新的 Pod。
并行腾空多个节点
kubectl drain
命令每次只能对一个节点执行。但是,你可以在不同的终端或后台并行运行多个 kubectl drain
命令来处理不同的节点。同时运行的多个腾空命令仍然会遵循你指定的 PodDisruptionBudget。
例如,如果你有一个包含三个副本的 StatefulSet,并且为其设置了一个 PodDisruptionBudget,指定 minAvailable: 2
,那么只有当所有三个副本 Pod 都健康时,kubectl drain
才会从 StatefulSet 中驱逐一个 Pod;如果你并行发出多个腾空命令,Kubernetes 将遵循 PodDisruptionBudget,并确保在任何给定时间只有 1 个 Pod 不可用(计算方法为 replicas - minAvailable
)。任何会导致健康副本数量低于指定预算的腾空操作都将被阻止。
驱逐 API
如果你不想使用kubectl drain(例如为了避免调用外部命令,或者为了更精细地控制 Pod 驱逐过程),你也可以使用驱逐 API 以编程方式触发驱逐。
更多信息,请参阅API 发起的驱逐。
下一步
- 按照步骤通过配置 Pod 中断预算来保护你的应用程序。