尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

Kubernetes Pod卡在Terminating状态:Finalizers阻塞与强制删除全解析

Kubernetes Pod卡在Terminating状态:Finalizers阻塞与强制删除全解析 1. 问题引入那个“赖着不走”的Pod在Kubernetes集群的日常运维里你肯定遇到过这种让人头疼的情况执行了kubectl delete pod pod-name命令返回成功但那个Pod却卡在了Terminating状态像一块牛皮糖一样怎么都删不掉。看着kubectl get pods列表里那个一直显示Terminating的条目集群资源被占用后续部署可能因此受阻那种感觉确实很烦人。这个问题看似简单背后却牵扯到Kubernetes资源删除的核心机制——Finalizers终结器和Owner References属主引用。简单粗暴地rm -rf在Kubernetes的世界里行不通因为它是一个声明式的、由控制器驱动的系统。Pod不会因为你的删除命令而立即消失它需要优雅地结束容器进程、清理网络和存储资源并向API Server报告完成。当这个流程卡住时Pod就会陷入永恒的“Terminating”状态。今天我们就来彻底拆解这个经典问题。我会从问题根因讲起然后给你一套从常规到“暴力”的完整解决方案并分享我在处理生产环境此类问题时积累的排查心法和避坑指南。无论你是刚接触K8s的新手还是遇到过此问题但知其然不知其所以然的同僚这篇文章都能帮你把这块硬骨头啃下来。2. 根因深度剖析为什么Pod会“卡死”在Terminating要解决问题必须先理解问题。一个Pod无法被正常删除根本原因在于Kubernetes的优雅删除Graceful Deletion流程未能完成。这个流程主要卡在以下几个环节2.1 Finalizers终结器的阻塞这是最常见的原因。Finalizer是附加在资源对象上的一个键列表其作用是告诉Kubernetes“在删除这个对象之前必须先完成一些清理工作”。只有当所有Finalizer都被执行并移除后对象才会被真正从API Server中删除。常见场景PV/PVC持久卷/声明的Protection Finalizer 当Pod使用了持久化存储PersistentVolumeClaimKubernetes可能会自动添加kubernetes.io/pvc-protection等Finalizer以防止正在被Pod使用的存储卷被意外删除。如果存储子系统如CSI驱动响应缓慢或故障移除这个Finalizer的操作就会挂起。自定义控制器添加的Finalizer 许多第三方Operator或自定义控制器例如管理数据库、消息队列的Operator会为它们管理的Pod添加自定义Finalizer以确保在Pod删除前执行一些自定义的清理逻辑如备份、状态同步。如果该控制器本身崩溃或无法访问它的Finalizer就永远无法被移除。网络插件相关的Finalizer 某些CNI容器网络接口插件可能会添加Finalizer来清理Pod的网络配置如IPAM回收IP地址。如果网络插件异常此步骤也会失败。你可以通过以下命令查看Pod的Finalizerskubectl get pod pod-name -o jsonpath{.metadata.finalizers}如果输出不为空比如显示[foregroundDeletion]或自定义的Finalizer那么这就是导致删除卡住的首要怀疑对象。2.2 容器进程未正常退出Kubernetes向Pod中的容器发送SIGTERM信号并等待一段“优雅终止宽限期”默认为30秒可通过spec.terminationGracePeriodSeconds设置。在此期间容器应用应处理完未完成的请求、保存状态并退出。导致卡住的原因应用未处理SIGTERM 应用代码没有捕获SIGTERM信号或者捕获后执行了长时间阻塞的操作如等待一个永远不会返回的外部API调用。容器进程“僵尸化” 容器内的主进程PID 1异常但子进程未回收导致进程树状态异常kubelet无法判断其是否已终止。依赖服务不可用 容器在关闭时需要调用另一个服务如注销服务发现但该服务已宕机导致关闭逻辑无限重试或挂起。此时通过kubectl describe pod pod-name查看事件可能会看到Killing事件但容器状态迟迟不变成Terminated。2.3 API Server与Node节点通信故障kubelet是运行在每个Node上的代理负责Pod的生命周期管理。删除流程是API Server标记Pod为“删除中”kubelet监听到此变化然后执行本地容器的停止和清理工作最后向API Server报告API Server才删除对象。通信故障导致的问题Node节点失联NotReady 如果Pod所在的Node节点网络断开、kubelet进程崩溃或机器宕机API Server将无法与该Node上的kubelet通信。kubelet无法上报清理完成的状态Pod就会一直卡在Terminating。API Server资源压力 在极端情况下API Server过载可能导致对kubelet状态更新的响应延迟给人造成删除卡住的错觉通常这种情况是暂时的。2.4 属主资源Owner Reference的级联删除问题Kubernetes中很多资源都有属主关系。例如一个由Deployment创建的Pod其属主ownerReference是该Deployment对应的ReplicaSet。默认情况下删除Deployment会级联删除其ReplicaSet和Pod。问题场景有时属主资源如StatefulSet、Job本身的状态异常或存在Finalizer导致其删除被卡住进而使其下属的所有Pod也卡在Terminating状态。你删Pod只是“治标”需要去处理它的“父对象”。3. 标准排查流程与诊断方法遇到Terminating Pod不要慌按照以下流程一步步诊断可以快速定位问题根源。3.1 第一步检查Pod详细信息这是获取线索最直接的方式。kubectl describe pod pod-name -n namespace重点关注以下部分Events事件 查看最近的警告或错误事件。例如是否有Failed to kill pod、Error syncing pod或与volume、网络相关的错误信息。Finalizers 在描述信息的Metadata部分找到Finalizers字段。Conditions状态 查看Ready、PodScheduled、Initialized、ContainersReady等状态是否为False及其原因。Node 确认Pod被调度到了哪个Node并记录该Node名称。3.2 第二步检查Pod所在Node节点状态如果怀疑是节点问题立即检查。kubectl get node node-name查看节点状态是否为Ready。如果不是进一步描述节点kubectl describe node node-name查看节点事件、资源压力情况以及kubelet的心跳是否正常。3.3 第三步检查关联的存储资源如果Pod使用了PVC检查PVC和PV的状态。kubectl get pvc pvc-name -n namespace kubectl describe pvc pvc-name -n namespace kubectl get pv pv-name # PVC会绑定到一个PV查看它们是否也被卡在Terminating或者其Finalizers是否包含保护性字段。3.4 第四步检查属主资源找出是谁创建了这个Pod并检查它的状态。# 查看Pod的ownerReferences kubectl get pod pod-name -n namespace -o jsonpath{.metadata.ownerReferences} | jq .常见的属主有ReplicaSet来自Deployment、StatefulSet、DaemonSet、Job等。去检查这些上级资源的状态是否正常。4. 解决方案大全从优雅到“暴力”根据不同的根因我们有不同层级的解决方案。请优先尝试前面的方法。4.1 方案一强制删除Pod绕过APIServer这是最直接、最常用的方法适用于因Finalizer阻塞或API Server与kubelet之间状态同步问题导致的卡死。此命令直接从API Server中删除资源对象不等待kubelet的确认。kubectl delete pod pod-name -n namespace --force --grace-period0--force 强制删除。--grace-period0 将优雅终止宽限期设置为0秒立即删除。重要提示 强制删除可能带来风险。如果Pod还在节点上运行此命令会从API Server移除其记录但节点上的容器进程可能仍在运行变成“孤儿进程”。后续需要手动登录节点清理。因此执行后务必检查节点上是否还有残留的容器# 登录到Pod所在节点 docker ps -a | grep pod-name # 如果使用Docker crictl ps -a | grep pod-name # 如果使用containerd4.2 方案二手动移除Finalizers治本之策如果确定是某个Finalizer尤其是自定义Finalizer导致的阻塞并且你确认相关清理工作可以忽略或已由其他方式完成可以直接编辑Pod移除Finalizer列表。方法A使用kubectl editkubectl edit pod pod-name -n namespace在打开的YAML编辑器中找到metadata.finalizers字段将其值清空改为[]保存退出。API Server会立即处理删除。方法B使用kubectl patch更推荐可脚本化kubectl patch pod pod-name -n namespace -p {metadata:{finalizers:[]}} --typemerge这条命令会直接将finalizers字段替换为空数组效果立竿见影。4.3 方案三处理失联Node上的Pod如果Pod所在的Node状态为NotReady且无法恢复这些Pod会一直处于Terminating或Unknown状态。你需要将Node从集群中移除。驱逐Node上的所有Podkubectl drain node-name --ignore-daemonsets --delete-emptydir-data --force这条命令会优雅驱逐该Node上所有可迁移的PodDaemonSet管理的Pod除外。如果驱逐卡住强制删除Nodekubectl delete node node-name从API Server删除Node对象。之后原来在该Node上卡住的Pod通常会被自动清理因为其依赖的Node对象已不存在。手动清理API残留 极少数情况下删除Node后Pod还在。此时可以对残留Pod使用方案一强制删除。4.4 方案四级联删除属主资源如果发现卡住的Pod属于某个StatefulSet或Job并且该属主资源本身也状态异常直接删除属主资源可能更有效。# 例如删除一个卡住的StatefulSet kubectl delete statefulset sts-name -n namespace --cascadeorphan--cascadeorphan参数表示“孤立”其Pod即只删除StatefulSet本身不删除Pod。然后你可以再对残留的Pod单独使用上述方法进行删除。有时删除上级控制器能解除某种死锁状态。4.5 方案五终极“外科手术”——直接操作ETCD极度危险警告此操作风险极高可能损坏集群数据。仅在所有其他方法均无效且你深刻理解后果并拥有集群备份的情况下作为最后手段使用。当API Server本身的状态出现问题甚至无法处理删除请求时根源可能在etcd中存储的数据不一致。你需要直接操作etcd。找到etcd Pod和证书kubectl get pods -n kube-system | grep etcd # 假设etcd pod名为 etcd-master通过etcdctl命令删除key# 进入etcd容器 kubectl exec -it -n kube-system etcd-master -- sh # 在容器内使用etcdctl需要指定证书路径路径因安装方式而异 export ETCDCTL_API3 etcdctl --endpointshttps://127.0.0.1:2379 \ --cacert/etc/kubernetes/pki/etcd/ca.crt \ --cert/etc/kubernetes/pki/etcd/server.crt \ --key/etc/kubernetes/pki/etcd/server.key \ del /registry/pods/namespace/pod-name执行成功后Pod将从API Server视图中彻底消失。5. 实战避坑指南与进阶技巧掌握了方法我们再来聊聊实战中容易踩的坑和一些提升效率的技巧。5.1 预防优于治疗如何减少Terminating Pod的出现优化应用优雅关闭逻辑 确保你的容器应用能正确处理SIGTERM信号。在Dockerfile的ENTRYPOINT脚本或应用启动代码中加入信号处理逻辑确保在收到信号后能快速、安全地关闭。合理设置terminationGracePeriodSeconds 对于需要较长时间关闭的应用如大型Java应用、有状态服务适当调大这个值例如60秒或120秒避免因时间不足导致强制杀死。谨慎使用Finalizers 为自定义资源添加Finalizer时确保其清理逻辑是幂等、快速且可靠的。避免在Finalizer中执行可能长时间阻塞或失败的操作。监控节点与组件健康 建立对Node节点状态、kubelet健康度以及API Server延迟的监控。及时发现并处理NotReady节点可以避免大量Pod卡住。使用PodDisruptionBudget (PDB) 对于关键应用配置PDB可以防止在节点维护或驱逐时过多副本同时进入Terminating状态给系统带来压力。5.2 排查时容易忽略的细节查看kubelet日志 如果怀疑是kubelet问题可以登录节点查看kubelet日志。对于使用systemd的系统journalctl -u kubelet -f --no-pager搜索与你的Pod名称相关的错误信息。检查容器运行时接口CRI Docker或containerd本身也可能有问题。可以检查容器运行时的日志和状态。资源泄漏 强制删除Pod后务必检查节点上是否残留了容器、镜像或网络命名空间。残留的网络命名空间可能导致新Pod无法分配IP。# 检查网络命名空间 ip netns list | grep pod-uid的一部分 # 如果发现残留可以手动删除需谨慎 ip netns delete namespace-name5.3 编写自动化处理脚本对于运维人员可以编写一个简单的Shell脚本自动检测并尝试清理Terminating状态的Pod。#!/bin/bash # cleanup_terminating_pods.sh NAMESPACE${1:-default} # 可以传入命名空间参数默认为default TERMINATING_PODS$(kubectl get pods -n $NAMESPACE --field-selectorstatus.phaseTerminating -o jsonpath{.items[*].metadata.name}) if [ -z $TERMINATING_PODS ]; then echo No terminating pods found in namespace $NAMESPACE. exit 0 fi echo Found terminating pods: $TERMINATING_PODS for POD in $TERMINATING_PODS; do echo Attempting to force delete pod: $POD # 先尝试优雅强制删除 kubectl delete pod $POD -n $NAMESPACE --force --grace-period0 2/dev/null sleep 2 # 检查是否还在 if kubectl get pod $POD -n $NAMESPACE /dev/null; then echo Pod $POD still exists, trying to remove finalizers... # 尝试移除finalizers kubectl patch pod $POD -n $NAMESPACE -p {metadata:{finalizers:[]}} --typemerge sleep 2 # 再次尝试删除 kubectl delete pod $POD -n $NAMESPACE --force --grace-period0 else echo Pod $POD deleted successfully. fi done echo Cleanup operation completed.使用脚本的注意事项 此脚本仅为示例在生产环境中使用前需充分测试。它可能会干扰那些正在进行正常优雅关闭的Pod。建议先手动确认Pod确实异常卡死后再使用或加入更复杂的判断逻辑如Terminating状态持续时间超过10分钟。6. 典型故障场景模拟与解决实录让我们通过两个我实际遇到过的场景来串联运用上面的知识。6.1 场景一自定义Operator故障导致Finalizer阻塞现象 集群中一批管理中间件的Pod卡在Terminating。kubectl describe发现它们都有一个名为cleanup.operator.example.com的Finalizer。排查检查对应的自定义资源CR和Operator Pod发现Operator Pod因为一个配置错误而处于CrashLoopBackOff状态无法处理任何Finalizer移除请求。由于该Finalizer仅用于非关键的日志上传清理业务上可以忽略。解决首先尝试修复Operator的配置并重启但问题紧急选择直接移除Pod的Finalizer。使用命令批量处理假设Pod都有共同标签appmy-middlewarefor p in $(kubectl get pod -l appmy-middleware --field-selectorstatus.phaseTerminating -o name); do kubectl patch $p -p {metadata:{finalizers:[]}} --typemerge done移除后Pod被立即删除。随后修复Operator问题彻底解决。教训 为资源添加Finalizer需非常谨慎必须确保执行Finalizer的逻辑服务Controller/Operator具有高可用性和快速故障恢复能力。6.2 场景二节点网络分区导致大量Pod卡住现象 某个工作节点因交换机故障导致网络分区状态变为NotReady。该节点上所有Pod状态变为Terminating或Unknown。修复网络后节点状态恢复Ready但大部分Pod仍卡在Terminating。排查kubectl describe pod显示事件为NodeLost。检查节点上的kubelet日志发现它在网络恢复后正在尝试清理这些旧的Pod但有些Pod的存储卷卸载遇到问题。解决对于无状态应用最安全快捷的方式是直接强制删除这些Pod。Deployment/ReplicaSet控制器会检测到Pod缺失并在当前健康的节点上立即创建新的副本。kubectl delete pod --all --force --grace-period0 -n namespace --field-selector spec.nodeName故障节点名对于有状态应用StatefulSet需要更小心。先检查StatefulSet本身是否健康然后逐个评估Pod。如果数据持久化卷可以重新挂载到新Pod也可以对旧Pod进行强制删除StatefulSet会重建序号相同的Pod。强制删除后登录原故障节点检查并清理可能残留的容器进程和存储挂载点。教训 对于节点级别的故障要有清晰的应急预案。无状态应用应通过控制器快速自愈而有状态应用则需要结合备份和恢复策略。定期测试节点故障场景下的应用恢复能力。处理Terminating Pod的过程本质上是对Kubernetes声明式API和控制器模型的一次深刻理解。从最优雅的等待到绕过API Server的强制删除再到动刀etcd的终极手段每一种方法都对应着不同层次的故障和风险。在日常运维中建立完善的监控告警如Pod Terminating时间超过5分钟并积累一套像本文这样的诊断清单和脚本工具能让你在遇到问题时从容不迫快速恢复业务。记住在动手删除之前花几分钟时间describe一下往往能省下后面几个小时的折腾时间。
返回列表