Kubernetes 节点上删除 Pod 完全指南:kubectl delete、drain 与 cordon 实战解析(refine 技术博客)
【免费下载链接】refineA React Framework for building internal tools, admin panels, dashboards & B2B apps with unmatched flexibility.项目地址: https://gitcode.com/GitHub_Trending/re/refine
本篇技术指南以 refine 官方技术博客的《A Guide for Delete Pods from Kubernetes Nodes》为核心,系统讲解如何通过kubectl delete、kubectl drain、kubectl cordon/uncordon在 Kubernetes 节点上安全删除 Pod。你将从 Pod 的基础概念出发,掌握批量排空节点、逐个删除 Pod、处理 Deployment/ReplicaSet/StatefulSet/DaemonSet 各类控制器差异的完整操作流程,并学会在删除前后验证服务不受影响。
本文涵盖的操作路径
- 什么是 Kubernetes 中的 Pod
- 为什么需要删除 Pod
- 删除 Pod 前的必要检查
- 从节点批量删除全部 Pod:kubectl drain
- 验证 drain 前后的 Pod 状态
- 从节点逐个删除 Pod:受控删除
- 处理 Deployment 与 ReplicaSet 管理的 Pod
- 处理 StatefulSet Pod
- 让 Pod 重新回到节点:kubectl uncordon
- 仓库实践:refine 文档站的 Kubernetes 部署
- 总结与安全建议
什么是 Kubernetes 中的 Pod
Pod 是 Kubernetes 中最小的执行单元(smallest execution unit),一个 Pod 内可以包含一个或多个应用容器。Pod 天然是**临时性(ephemeral)**的:如果某个 Pod 发生故障,或者它所在的节点发生故障,Kubernetes 会自动创建该 Pod 的新副本,以维持业务持续运行。在同一 Pod 内的容器(例如 Docker 容器)会共享相同的计算资源、网络命名空间与存储卷,这使得 Pod 成为调度、伸缩和副本管理的基本粒度。
理解这一点是后续所有删除操作的前提:Pod 本身可以被任意删除,但真正决定"删除后会发生什么"的,是管理它的控制器(Controller)类型——Deployment、ReplicaSet、StatefulSet、DaemonSet、Job 等控制器各自定义了不同的重建与调度行为,这也是本文后续分场景讨论的根源。
为什么需要删除 Pod
在实际运维中,你可能需要从一个或多个工作节点删除 Pod,常见场景包括:
- 调试节点问题:节点出现异常(CPU、内存、网络、磁盘故障)时,需要将 Pod 迁移走以便检修;
- 节点升级与缩容:对节点做系统升级,或主动将节点从集群中移除(例如使用容器方式部署应用时的节点下线);
- 手动缩容测试:为测试目的手动缩小集群规模;
- 节点维护:由于维护需求,需要清空特定节点上的所有 Pod。
无论哪种场景,删除动作本身并不复杂,复杂的是"如何在删除的同时保证业务不中断、数据不丢失、故障不扩散"。
删除 Pod 前的必要检查
应用弹性的重要性
持续提供一致、可靠的服务是满足用户期望、提升用户留存的基础。服务越是稳定可用,用户流失与投诉的概率就越低;而故障与中断的频率和影响范围降低,也能直接削减运维成本与业务风险。反之,一次失败的删除可能带来收入损失、数据丢失、安全漏洞乃至声誉损害。具备弹性(resilience)的应用能够在故障发生后快速恢复、迅速回到正常状态,从而避免或缓解上述后果——在动手删除任何 Pod 之前,请先确认你的应用具备这样的自愈能力。
草率删除 Pod 的风险
在未做任何检查的情况下匆忙删除 Pod,至少存在三类典型风险:
- 服务中断或性能劣化:如果一次删除过多 Pod,或误删了没有副本的关键 Pod,可能导致服务整体不可用或响应能力明显下降;
- 数据丢失或损坏:在没有备份或数据复制机制的前提下删除 Pod,Pod 内存储和处理的数据可能随之丢失或受损;
- 故障级联扩散:被删除的 Pod 如果处于通信网络或依赖链的关键节点上,问题可能沿依赖关系在整个系统中传播放大。
因此,删除前应至少确认:应用是否有足够的副本数、是否由控制器管理、数据是否有持久化与备份、删除后是否有自动重建机制。
从节点批量删除全部 Pod:kubectl drain
drain 命令的工作原理
kubectl drain用于优雅地将节点移出服务(gracefully remove a node from service):它会驱逐(evict)该节点上运行的所有 Pod,并将它们调度到其他可用节点,同时阻止新的 Pod 继续调度到该节点。为了尽可能避免数据丢失或对运行中应用的干扰,drain 不会粗暴地强制终止 Pod,而是遵循 Pod 的优雅终止流程(先执行 preStop 钩子、再等待优雅终止宽限期)。这使得节点维护与故障排查可以在不影响应用可用性的前提下提前规划。
实践:drain minikube 节点
假设我们要排空名为minikube的节点,该节点上存在由DaemonSet控制器管理的 Pod(因此需要--ignore-daemonsets标志跳过它们),也包含不受任何控制器管理的裸 Pod(因此需要--force标志强制处理),可以执行:
kubectl drain minikube --ignore-daemonsets --force命令执行后,kubectl 会逐个驱逐该节点上的 Pod,输出每个被驱逐 Pod 的名称与结果,例如pod/xxx evicted。--ignore-daemonsets让 drain 跳过 DaemonSet 管理的 Pod 并继续执行;--force则允许删除那些没有对应控制器、删除后无法自动重建的裸 Pod(见下文"--force标志及其影响")。
补充说明:drain 过程是幂等且可重复的。如果排空过程中发现节点上仍有无法驱逐的 Pod,drain 会报告错误并停在原地,便于你先处理特殊情况(例如无容忍的裸 Pod、本地卷 Pod 等)后再继续。
验证 drain 前后的 Pod 状态
在 drain 前后验证节点上的 Pod 分布至关重要,它能确保 Pod 被正确迁移到其他节点、服务未被扰动。推荐使用以下命令列出所有命名空间下每个 Pod 及其节点归属:
kubectl get pods --all-namespaces -o wide该命令会返回每个 Pod 的名称(NAME)、命名空间(NAMESPACE)、状态(STATUS)、重启次数(RESTARTS)、存活时间(AGE)、IP、所在节点(NODE)以及提名节点(NOMINATED NODE)。通过对比 drain 前后的两次输出,你可以清楚看到:哪些 Pod 已从被排空的节点上驱逐、它们被重新调度到了哪些节点、是否有 Pod 处于异常状态需要人工介入。
特殊场景:NoExecute 与 DaemonSet Pod
- NoExecute 容忍 Pod:带有
node.kubernetes.io/...这类 NoExecute 污点容忍(toleration)的 Pod,如果没有设置tolerationsSeconds(容忍时间上限),就可能无限期留在节点上,drain 无法将其驱逐。此时必须使用--force标志强制执行删除,放弃等待优雅终止。 - DaemonSet 管理的 Pod:DaemonSet 控制器会确保集群中每个节点上都运行该 Pod 的一个副本。默认情况下
kubectl drain不会驱逐 DaemonSet Pod,除非你显式指定--ignore-daemonsets标志——该标志表示"跳过这些 Pod,继续执行排空"。
--force标志及其影响
当你排空的节点上存在由ReplicationController、ReplicaSet、Job、DaemonSet 或 StatefulSet管理的 Pod 时,对应的控制器会在删除后自动重建这些 Pod。因此,drain 在遇到这类 Pod 时会给出警告性质的错误信息(提醒你删除后它们会被重新创建)。若你确认要继续执行排空,就需要加上--force选项来忽略这些警告、强制推进 drain 流程。
需要强调的是:--force关闭的是"拒绝删除有控制器管理的 Pod"这一保护逻辑,它不会关闭优雅终止机制,但配合 NoExecute 场景时可能意味着 Pod 被直接删除而不再等待。
从集群中移除节点
当节点已被完全排空、不再运行任何 Deployment、Pod、StatefulSet 或 DaemonSet 之后,可以使用下面的语法将该节点从集群中删除:
kubectl delete node [NAME_OF_NODE]例如我们有一个名为minikube的节点且已完成排空,则执行:
kubectl delete node minikube命令执行成功后,kubectl 会输出node "minikube" deleted,该节点即从集群对象中移除。
从节点逐个删除 Pod:受控删除
为什么需要受控删除
与批量排空相比,逐个删除 Pod 的受控方式具备明显优势:一是更好的故障容忍度——将节点问题对服务可用性的影响降到最低;二是资源利用优化——只释放特定节点上选定 Pod 占用的资源,避免资源浪费,同时防止服务整体劣化。当你只想调整个别 Pod 而不想影响整个节点时,这是更精准的手段。
使用 kubectl cordon 命令
kubectl cordon是一种可靠且受控地从节点移除 Pod 的方法:它将节点标记为不可调度(unschedulable),确保不会有新的 Pod 被分配到这个节点;与此同时,节点上已有的 Pod 仍然保持运行并正常处理请求。这样你就获得了"先封住入口、再从容清理存量"的操作窗口,既不会影响集群的可访问性,又能安全地逐个删除 Pod。
例如,将我们的minikube节点标记为不可调度:
kubectl cordon minikube命令执行后输出类似node/minikube cordoned,节点状态中会出现SchedulingDisabled标记。
删除单个 Pod
节点被 cordon 之后,就可以通过kubectl delete pod命令删除该节点上的单个 Pod(可按 Pod 名称删除,也可按需指定命名空间)。首先,用kubectl get pods配合--field-selector列出位于特定节点上的 Pod:
kubectl get pods --all-namespaces --field-selector spec.nodeName=minikube--field-selector spec.nodeName=minikube会筛选出spec.nodeName字段等于minikube的所有 Pod,输出包含 Pod 所在命名空间、名称与状态等信息。
假设在上面的列表中我们想删除名为my-demo-pod的 Pod,执行:
kubectl delete pod my-demo-pod命令执行后输出pod "my-demo-pod" deleted,该 Pod 即从minikube节点上被删除。
处理 Deployment 与 ReplicaSet 管理的 Pod
如果被删除的 Pod 属于Deployment 或 ReplicaSet,删除后控制器会自动在其他节点上重新创建该 Pod,从而维持声明式副本数(desired replicas)不变。也就是说,直接删除这类 Pod 并不能"真正移除"它——它马上会以新名字重新出现。
因此,要把 Deployment/ReplicaSet 的所有 Pod 从某个节点上彻底清除,正确做法是:先调大副本数(scale up),再删除 Pod,最后调回副本数(scale down)。这样新创建的 Pod 会被调度到其他可用节点,且最终副本数回到预期值,而目标节点上的 Pod 则被清空且不会重新调度回来。
例如,我们有一个名为example-deployment的 Deployment,先将其副本数扩到 4:
kubectl scale deployment example-deployment --replicas=4输出会确认deployment.apps/example-deployment scaled。接着,列出example-namespace命名空间中、标签为app=nginx、且位于minikube节点上的 Pod:
kubectl get pods -l app=nginx -n example-namespace --field-selector spec.nodeName=minikube然后删除列表中名为my-demo-deployment-cbdccf466-p8zjf的 Pod,再确认它是否被重建:
kubectl get pods -l app=nginx输出会显示该 Pod 已被自动重新创建(在单节点 Kubernetes 环境中会重建在同一个minikube节点上)。最后将example-deployment的副本数从 4 缩回 3:
kubectl scale deployment example-deployment --replicas=3输出确认副本数已缩回 3,节点上的多余 Pod 被回收,副本数与删除前保持一致。
处理 StatefulSet Pod
StatefulSet 的 Pod 删除行为与 Deployment 截然不同:删除 StatefulSet 的 Pod 并不会自动触发其被重新调度到其他节点,而是会以相同的名称和序号(ordinal index)在同一个节点上被重建。原因在于 StatefulSet Pod 拥有集群内唯一且持久的标识(例如demo-statefulset-0、demo-statefulset-1),其存储卷、网络身份都与这个序号强绑定,不允许随意"换个地方重生"。
因此,若想从节点上移除 StatefulSet 的 Pod,正确做法是:先通过缩容(scale down)降低 StatefulSet 的副本数,再删除对应 Pod,这样 Pod 才不会在同节点以同名重建。
例如,假设有一个名为demo-statefulset的 StatefulSet,当前有 3 个 Pod,将其缩容到 2:
kubectl scale statefulset demo-statefulset --replicas=2输出确认demo-statefulset已缩容为 2 个副本。列出节点上的 StatefulSet Pod 后,可以看到demo-statefulset-0与demo-statefulset-1两个 Pod。删除demo-statefulset-0:
kubectl delete pod demo-statefulset-0最后用以下命令验证demo-statefulset-0已被删除且不会在minikube节点上被重建:
kubectl get pods -l app=web-app让 Pod 重新回到节点:kubectl uncordon
uncordon 命令
kubectl uncordon与kubectl cordon相反,它把节点重新标记为可调度(schedulable),使其准备好接收新的 Pod。之前被 cordon(状态为SchedulingDisabled)或被 drain 的节点,都可以通过 uncordon 恢复调度能力。
例如,之前 cordon 了minikube节点且其状态为SchedulingDisabled,现在执行:
kubectl uncordon minikube命令执行后输出node/minikube uncordoned,节点恢复可调度状态。
验证 Pod 重新调度回节点
uncordon 之后,可以运行以下命令查看节点上正在运行的 Pod,验证 Pod 是否重新被调度回来:
kubectl get pods在输出中可以看到:之前 cordonminikube节点时被删除的demo-deploymentPod,在节点 uncordon 之后已被重新调度并在minikube节点上重新创建。
仓库实践:refine 文档站的 Kubernetes 部署
上述 Pod 管理知识在 refine 仓库中并非纸上谈兵——refine 的官方文档站本身就是以 Kubernetes 工作负载的形式部署的,其 Helm Chart 位于 documentation/k8s/refine-documentation。对照本文内容,可以在该 Chart 中找到一手的 Pod 管理配置:
- Deployment 与副本声明:在 Deployment 模板 中,
replicas: {{ .Values.replicaCount }}直接对应 values.yaml 里的replicaCount: 1。这正是本文所述"Deployment 由 ReplicaSet 控制器维持副本数、删除单个 Pod 会被自动重建"的配置体现——文档站的所有 Pod 都由 Deployment 管理,直接kubectl delete pod只会触发重建。 - 调度约束与本文场景的关联:模板中的
nodeSelector、affinity、tolerations(deployment.yaml)与 values.yaml 中的tolerations: [],正是决定 Pod 会被调度到哪些节点的机制,也是 drain/cordon 操作之所以能影响 Pod 分布的根本原因——带有 NoExecute 污点容忍的 Pod(对应本文特殊场景)就可能因此留在被 drain 的节点上。 - 副本伸缩配置:values.yaml 中的
autoscaling段(minReplicas、maxReplicas、targetCPUUtilizationPercentage)展示了副本数声明与水平伸缩的配置方式,配合kubectl scale命令即可在运行时手动调整副本数。 - 环境契合:值得一提的是,values.yaml 的注释中明确提到"不指定默认资源限额有助于 Chart 在 Minikube 这类小资源环境运行"——这与本文示例使用的
minikube节点环境完全一致,说明在 Minikube 上实践这些删除命令是官方认可的验证路径。
总结与安全建议
理解 Kubernetes 环境中 Pod 删除的复杂性,是保证应用弹性和可靠性的关键。虽然 Kubernetes 本身已为 Pod 终止设计了较为平滑的处理机制,但盲目或草率的 Pod 删除仍可能造成服务中断、数据丢失乃至级联故障。删除行为的后果取决于 Pod 所属的控制器类型:
- Deployment / ReplicaSet:删除即重建,需通过先扩容、再删除、后缩容的方式才能真正清空节点;
- StatefulSet:同名同节点重建,必须先缩容再删除;
- DaemonSet:每个节点一份,drain 默认跳过,需用
--ignore-daemonsets; - 无控制器管理的裸 Pod / NoExecute 容忍 Pod:需用
--force强制处理。
为避免删除后 Pod 重新调度回原节点,务必采用"删除前先调整副本数"等技巧。最后强烈建议:在生产集群中实施任何删除方案之前,先在安全的非生产环境(如开发或预发集群)中反复演练,熟悉各类 Pod 的删除行为差异,检验你对 Pod 生命周期的理解,并在受控环境中打磨你的删除流程。充分的准备工作,是 Kubernetes Pod 管理成功的前提。
【免费下载链接】refineA React Framework for building internal tools, admin panels, dashboards & B2B apps with unmatched flexibility.项目地址: https://gitcode.com/GitHub_Trending/re/refine
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考