确保 PodDisruptionBudget 的前提下安全地清空一个{{< glossary_tooltip text=”节点” term_id=”node” >}}
本页展示了如何在确保 PodDisruptionBudget 的前提下,安全地清空一个节点。
准备开始
要获知版本信息,请输入 kubectl version
.
此任务假设您已经满足以下先决条件:
- 使用的 Kubernetes 版本 >= 1.5。
- 以下两项,具备其一:
- 在节点清空期间,不要求应用程序具有高可用性
- 你已经了解了 PodDisruptionBudget 的概念,并为需要它的应用程序配置了 PodDisruptionBudget。
使用 kubectl drain
从服务中删除一个节点
在对节点执行维护(例如内核升级、硬件维护等)之前, 可以使用 kubectl drain
从节点安全地逐出所有 Pods。 安全的驱逐过程允许 Pod 的容器 体面地终止, 并确保满足指定的 PodDisruptionBudgets。
说明: 默认情况下,
kubectl drain
将忽略节点上不能杀死的特定系统 Pod; 有关更多细节,请参阅 kubectl drain 文档。
kubectl drain
的成功返回,表明所有的 Pods(除了上一段中描述的被排除的那些), 已经被安全地逐出(考虑到期望的终止宽限期和你定义的 PodDisruptionBudget)。 然后就可以安全地关闭节点, 比如关闭物理机器的电源,如果它运行在云平台上,则删除它的虚拟机。
kubectl get nodes
接下来,告诉 Kubernetes 清空节点:
kubectl drain <node name>
一旦它返回(没有报错), 你就可以下电此节点(或者等价地,如果在云平台上,删除支持该节点的虚拟机)。 如果要在维护操作期间将节点留在集群中,则需要运行:
kubectl uncordon <node name>
然后告诉 Kubernetes,它可以继续在此节点上调度新的 Pods。
并行清空多个节点
kubectl drain
命令一次只能发送给一个节点。 但是,你可以在不同的终端或后台为不同的节点并行地运行多个 kubectl drain
命令。 同时运行的多个 drain 命令仍然遵循你指定的 PodDisruptionBudget 。
例如,如果你有一个三副本的 StatefulSet, 并设置了一个 PodDisruptionBudget
,指定 minAvailable: 2
。 如果所有的三个 Pod 均就绪,并且你并行地发出多个 drain 命令, 那么 kubectl drain
只会从 StatefulSet 中逐出一个 Pod, 因为 Kubernetes 会遵守 PodDisruptionBudget 并确保在任何时候只有一个 Pod 不可用(最多不可用 Pod 个数的计算方法:replicas - minAvailable
)。 任何会导致就绪副本数量低于指定预算的清空操作都将被阻止。
驱逐 API
如果你不喜欢使用 kubectl drain (比如避免调用外部命令,或者更细化地控制 pod 驱逐过程), 你也可以用驱逐 API 通过编程的方式达到驱逐的效果。
首先应该熟悉使用 Kubernetes 语言客户端。
Pod 的 Eviction 子资源可以看作是一种策略控制的 DELETE 操作,作用于 Pod 本身。 要尝试驱逐(更准确地说,尝试 创建 一个 Eviction),需要用 POST 发出所尝试的操作。这里有一个例子:
{
"apiVersion": "policy/v1beta1",
"kind": "Eviction",
"metadata": {
"name": "quux",
"namespace": "default"
}
}
你可以使用 curl
尝试驱逐:
curl -v -H 'Content-type: application/json' http://127.0.0.1:8080/api/v1/namespaces/default/pods/quux/eviction -d @eviction.json
API可以通过以下三种方式之一进行响应:
- 如果驱逐被授权,那么 Pod 将被删掉,并且你会收到
200 OK
, 就像你向 Pod 的 URL 发送了DELETE
请求一样。 - 如果按照预算中规定,目前的情况不允许的驱逐,你会收到
429 Too Many Requests
。 这通常用于对 一些 请求进行通用速率限制, 但这里我们的意思是:此请求 现在 不允许,但以后可能会允许。 目前,调用者不会得到任何Retry-After
的提示,但在将来的版本中可能会得到。 - 如果有一些错误的配置,比如多个预算指向同一个 Pod,你将得到
500 Internal Server Error
。
对于一个给定的驱逐请求,有两种情况:
- 没有匹配这个 Pod 的预算。这种情况,服务器总是返回
200 OK
。 - 至少匹配一个预算。在这种情况下,上述三种回答中的任何一种都可能适用。
驱逐阻塞
在某些情况下,应用程序可能会到达一个中断状态,除了 429 或 500 之外,它将永远不会返回任何内容。 例如 ReplicaSet 创建的替换 Pod 没有变成就绪状态,或者被驱逐的最后一个 Pod 有很长的终止宽限期,就会发生这种情况。
在这种情况下,有两种可能的解决方案:
- 中止或暂停自动操作。调查应用程序卡住的原因,并重新启动自动化。
- 经过适当的长时间等待后, 从集群中删除 Pod 而不是使用驱逐 API。
Kubernetes 并没有具体说明在这种情况下应该采取什么行为, 这应该由应用程序所有者和集群所有者紧密沟通,并达成对行动一致意见。
接下来
- 跟随以下步骤保护应用程序:配置 Pod 中断预算。
- 进一步了解节点维护。