<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>排空 · XB 现场笔记</title><link>https://www.xbcatm.com/zh/tags/%E6%8E%92%E7%A9%BA/</link><description>基于 HTTP、DNS、TLS、Caddy、SSH、发布与恢复的可复现运维现场笔记。</description><generator>Hugo</generator><language>zh-CN</language><atom:link href="https://www.xbcatm.com/zh/tags/%E6%8E%92%E7%A9%BA/index.xml" rel="self" type="application/rss+xml"/><item><title>Cordon 与 drain 协调节点维护</title><link>https://www.xbcatm.com/zh/posts/kubernetes-cordon-drain-node/</link><pubDate>Thu, 03 Feb 2028 00:00:00 +0000</pubDate><guid>https://www.xbcatm.com/zh/posts/kubernetes-cordon-drain-node/</guid><description>区分调度排除、驱逐过滤、中断预算与工作负载真实终止。</description><content:encoded>&lt;p&gt;Cordon 改变调度资格，drain 协调驱逐并等待 Pod 终止。两条命令都不保证维护期间工作一定保留；应用关闭逻辑、替代容量、存储和中断预算共同决定结果。应把排空视为需要观察的状态，并记录明确例外，而不是从命令名称推导节点已经可以安全关机。&lt;/p&gt;
&lt;h2 id="cordon-改变未来放置"&gt;Cordon 改变未来放置&lt;/h2&gt;
&lt;p&gt;Cordon 设置节点的不可调度字段，已有 Pod 继续运行，普通的新调度会避开它。Drain 自己也会执行 cordon，因此单独先做一次可以留下观察窗口，但不是必需步骤。Uncordon 重新允许调度，不保证立即出现新副本，也不会修好不健康的 kubelet；恢复前仍应核对节点状态与应用准备情况。&lt;/p&gt;
&lt;p&gt;这项调度限制存在例外。DaemonSet Pod 容忍不可调度条件，直接填写 nodeName 的 Pod 则绕过普通调度选择。具有相应容忍度的其他 Pod 也可能符合放置条件。因此，需要检查真实剩余负载，不能把 cordon 说成阻止所有 Pod 到来的防火墙，更不能只凭不可调度字段就判断节点已经清空。&lt;/p&gt;
&lt;h2 id="drain-具有过滤检查和独立操作"&gt;Drain 具有过滤检查和独立操作&lt;/h2&gt;
&lt;p&gt;Kubectl 先列出 Pod 并检查删除条件。独立 Pod 或管理控制器已经不存在的 Pod 可能需要 force；emptyDir 需要确认丢弃内容；DaemonSet 需要 ignore 选项。镜像 Pod 会被跳过，因为删除 API 表示不能停止 kubelet 根据静态清单管理的底层工作负载，静态程序需要单独规划维护。&lt;/p&gt;
&lt;p&gt;预检查不等于原子事务。真正开始驱逐后，一部分可以成功，另一部分仍在等待或失败；失败时节点也可能已经被 cordon。再次尝试前应重新读取节点与 Pod 状态，不能认为命令非零退出就表示所有东西都保持原样。维护记录要区分哪些请求被接受、哪些进程已经退出，以及哪些副本仍未恢复。&lt;/p&gt;
&lt;p&gt;Ignore-daemonsets 会留下 DaemonSet Pod。Delete-emptydir-data 允许丢失临时卷内容，不负责迁移。Force 允许处理无管理控制器的 Pod，却不会绕过 PodDisruptionBudget。选择参数前要核对归属、数据用途与重建方式；即使一个进程无状态，删除唯一实例也可能影响服务，因此无状态不是足够的安全证明。&lt;/p&gt;
&lt;h2 id="预算约束主动驱逐"&gt;预算约束主动驱逐&lt;/h2&gt;
&lt;p&gt;服务端支持时，drain 使用 Eviction API，并检查适用的中断预算。Disable-eviction 则改为直接删除，绕过这种保护。这个区别非常重要：添加 force 不能解决预算拒绝，而绕过驱逐可能删除维持法定多数或业务可用性所需的副本。不能把几个名字带有强制含义的参数视为同一个开关。&lt;/p&gt;
&lt;p&gt;健康 Pod 可能因为预算没有可中断数量而被阻塞。默认 IfHealthyBudget 还限制已经运行但不健康的 Pod：当所保护应用已经低于健康要求时，驱逐可能等待；这并不表示每个不健康 Pod 都必须先变 Ready。AlwaysAllow 改变这类不健康 Pod 的判定，应结合应用恢复行为选择，而不是为了让终端尽快返回随意启用。&lt;/p&gt;
&lt;p&gt;Drain 会等待终止，并重试部分被拒绝的驱逐。超时默认无限，但认证失败、服务端错误等仍可能结束命令。优雅终止只给应用一个停止窗口，不能证明写入完成或替代副本可用。设置合理的操作期限，有助于把受阻维护暴露出来，而不是让值班人员无限等待没有说明的进度。&lt;/p&gt;
&lt;h2 id="坏掉的样子"&gt;坏掉的样子&lt;/h2&gt;
&lt;p&gt;可中断数量为零是重要线索，不是立即削弱预算的许可。应检查选择到的 Pod、当前和期望健康数、替代容量与存储拓扑。先恢复不健康副本或增加安全容量，可能比降低保护更合理。多节点并行排空会竞争同一预算，还可能加重恢复压力；增加并发不能凭空获得更多可用副本。&lt;/p&gt;
&lt;p&gt;维护不能继续时，应找出具体剩余 Pod 和原因，不要为了看到成功退出而直接换成 disable-eviction。关闭节点之前，仍需验证应用健康，以及静态 Pod、DaemonSet 等剩余类别。普通 drain 成功本来就会留下部分工作负载，操作手册必须解释这些例外如何处理，而不是把它们当作遗漏。&lt;/p&gt;
&lt;h2 id="快速验证"&gt;快速验证&lt;/h2&gt;
&lt;p&gt;以下保留命令本轮没有执行。应明确选择临时集群与目标命名空间。客户端干跑仍读取集群，但不真正提交驱逐，也不验证服务端是否准许驱逐。示例中的 ignore 与 emptyDir 参数会压下对应预检查拒绝，所以不能把这份输出当成未忽略任何问题的完整安全报告。&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;kubectl get node node-1 -o jsonpath=&amp;#39;{.spec.unschedulable}{&amp;#34;\n&amp;#34;}&amp;#39;
kubectl drain node-1 --dry-run=client --ignore-daemonsets --delete-emptydir-data
kubectl get pods --field-selector spec.nodeName=node-1 -o custom-columns=NAME:.metadata.name,OWNER:.metadata.ownerReferences[0].kind
kubectl get pdb -A -o custom-columns=NAME:.metadata.name,MIN:.spec.minAvailable,MAX:.spec.maxUnavailable,ALLOWED:.status.disruptionsAllowed
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;节点字段显示 cordon 状态。Pod 列表只涵盖当前命名空间，而且只显示第一个 owner reference；空列或非空列都不能证明完整控制器关系。实际操作前应比较所有命名空间和控制引用。预算列表虽然跨命名空间，却未显示命名空间与选择器，需要逐个匹配实际负载。真实排空仍须在获准环境单独验证，这些检查不能认证其成功。&lt;/p&gt;
&lt;h2 id="来源"&gt;来源&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href="https://kubernetes.io/docs/tasks/administer-cluster/safely-drain-node/"&gt;安全地排空节点&lt;/a&gt;，drain 流程及其与 PodDisruptionBudget 的交互，已核验 2026-10-15。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href="https://kubernetes.io/docs/reference/kubectl/generated/kubectl_drain/"&gt;kubectl drain 参考&lt;/a&gt;，精确的拒绝条件与参数说明，已核验 2026-10-15。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href="https://kubernetes.io/docs/concepts/workloads/pods/disruptions/"&gt;Pod 中断&lt;/a&gt;，主动与被动中断的区别以及驱逐重试，已核验 2026-10-15。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href="https://kubernetes.io/docs/tasks/run-application/configure-pdb/"&gt;Primary reference&lt;/a&gt;，不健康 Pod 驱逐策略，已核验 2026-10-15。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;</content:encoded></item></channel></rss>