terminating状态分析及POD各种状态的分析思路
本文介绍的分析步骤和思路,也适用pod的各种状态的分析。
1 现像及分析步骤
当重启k8s容器容器服务,或者k8s运行过程中出现了node节点异常,会出现pod状态为terminating的现像,并且pod无法删除,且不会重新调度创建新的pod。
当出现terminating状态时,除了自身pod问题,一般都与node节点相关,所以需要收集和分析所在的节点异常信息。
问题查看步骤参考如下,并不一定按顺序执行。
1. 查看pod的状态:kubectl describe pod xxxx -n xxxx
2. 查看pod的日志:kubectl logs -f --tail 100 xxxx -n xxxx
3. 查看节点状态:kubectl get nodes
4. 执行:kubectl describe node xxx,进一步查看节点状态和事件。
5. 到异常node节点上,查看系统日志:/var/log/messages,查看异常信息。
rpc errors,exits with error context deadline exceeded,以及PLEG is not healthy事件,是常见的导致pod无法删除的原因之一,删除node节点,重启系统重新加入节点,是简单快速的解决方案。
6. 使用系统命令df、ls查看一下磁盘状态,以及挂载点路径,如果执行命令卡住无响应,表明磁盘或挂载点有问题,会影响到pod的回收与调度,比如挂载的NFS路径异常。
7. 如果只有某个pod处于terminating状态,进一步,我们可以删除下同一节点下的其它(非重要)pod,来确认一下是某个pod出了问题,还是该节点存在问题。
2 原因分析
1. 对象需要优雅删除,但k8s控制器不能完成删除。比如 Pod 因为 kubelet 无法下线节点上 node 容器、存储卷而无法删除。比较常见有以下原因:
kubelet 无法通过 container runtime 杀死进程。可能是挂载了外部存储,或者可能是运行时或操作内核遇到 bug 等,一般不能走正常流程让 kubelet 杀死进程,需要恢复挂载的存储,或重启操作系统才能解决。
kubelet 进程停止或者 node 失去联系。 该情况下,并没有 kubelet 运行或者运行中的 kubelet 与 apiserver 已经断开,无法收到 pod 需要删除下线的消息。所以,没有执行者来进行优雅删除。该情况下,需要恢复节点以及 kubelet 的运行即可。
2. 对象存在 finalizers,关联的控制器故障未能执行或执行 finalizer 函数卡住。该原因是k8s的删除机制,不用深究,可以通过一条命令删除terminating状态的pod来临时解决,但这也无法解决节点异常造成的问题。
3 解决办法
对于出现terminating状态的pod的情况下,主要有两种常见问题场景和应对方法。
1. 某个node节点上,只是一个pod出现terminating状态,并且无法正常通过kubelet delete pod删除。同一节点上的其它pod能正常删除,正常调度。
这种场景,只需要解决单个pod的问题。
强制删除:
kubectl delete pod xxx -n xxx --force --grace-period=0
如果强制删除还不行,设置finalizers为空:
kubectl patch pod xxx -n xxx -p '{"metadata":{"finalizers":null}}'
如果是挂载了nfs存储,则考虑挂载的存储是否正常,不正常需要先解决存储问题。
上面的方法都解决不了,则同样可使用下面第2种场景的方法解决。
2. 由于node节点异常,导致节点上的pod出现terminating状态。
这种情况下,往往可以从/var/log/messages中看到些异常和原因,比如rpc errors,exits with error context deadline exceeded,PLEG is not healthy等,是由docker或系统异常导致。另外执行docker命令响应(docker卡死),df 无响应(挂载存储卡死)等,也是导致容器运行异常的常见原因。解决的办法是删除node节点,再重启,具体步骤如下:
第一步:首先是在master上先删除异常的节点:
kubectl delete node xxxx
如果还有其它节点,并且资源足够的话,k8s会调度到其它节点,这样能够快速恢复业务pod。
第二步:在被删除的异常节点上,如果还能够执行命令docker ps,则通过docker ps查看,确保容器全部停止,再reboot重启主机。5分钟后,如果容器还一直运行,或者残留几个容器,直接reboot重启也可以。
第三步:主机节点重启后,该节点可以重新加入k8s集群,如果没有其它问题,就可以正常使用。
验证:通过重启服务或删除其它节点正常的pod,让k8s尝试调度新的pod到恢复的节点,确认集群恢复正常。
如果是因为挂载存储导致的异常,那重启后,需要确认存储挂载是否成功。
如果重启主机后,无法恢复,考虑主机的其它问题,需要进一步排查。
第四步:给刚删除的node,重新打上master或node标签。
kubectl label node [name-name] node-role.kubernetes.io/master=master
或
kubectl label node [name-name] node-role.kubernetes.io/node=node
4 其它状态
同样地,pod出现其它状态,也可以按上述的方法进行分析。
比如pod状态为ContainerCreating,那可以先确认是由单个pod引起的,还是因为节点异常造成的,再进一步排错。比如下图中,我们发现,117这个节点上的pod,大量出现ContainerCreating状态,通过kubectl describe pod命令就可以发现主要是由节点异常引起的,同时节点117也无法ssh登录。
此时,通过kubectl delete node命令把117这节点删除进行快速恢复,因为删除node节点后,pod会调度到其它节点。kubectl delete node命令后,就可以正常登录117节点,同时查看/var/log/messages就可以发现异常。
/var/log/messages日志:
Mar 22 15:23:22 v-docker-k6 dockerd: time="2023-03-22T15:23:22.849523296+08:00" level=warning msg="failed to retrieve runc version: fork/exec /usr/bin/runc: resource temporarily unavailable" Mar 22 15:23:22 v-docker-k6 dockerd: time="2023-03-22T15:23:22.849865329+08:00" level=warning msg="failed to retrieve docker-init version: fork/exec /usr/bin/docker-init: resource temporarily unavailable" Mar 22 15:23:23 v-docker-k6 dockerd: time="2023-03-22T15:23:23.925019553+08:00" level=warning msg="failed to retrieve runc version: fork/exec /usr/bin/runc: resource temporarily unavailable" Mar 22 15:23:23 v-docker-k6 dockerd: time="2023-03-22T15:23:23.925146016+08:00" level=warning msg="failed to retrieve docker-init version: fork/exec /usr/bin/docker-init: resource temporarily unavailable" Mar 22 15:23:23 v-docker-k6 systemd-udevd: fork of '/usr/lib/systemd/systemd-sysctl --prefix=/net/ipv4/conf/calico_tmp_B --prefix=/net/ipv4/neigh/calico_tmp_B --prefix=/net/ipv6/conf/calico_tmp_B --prefix=/net/ipv6/neigh/calico_tmp_B' failed: Resource temporarily unavailable Mar 22 15:23:23 v-docker-k6 systemd-udevd: fork of child failed: Resource temporarily unavailable Mar 22 15:23:25 v-docker-k6 systemd-udevd: fork of child failed: Resource temporarily unavailable Mar 22 15:23:25 v-docker-k6 systemd-udevd: fork of child failed: Resource temporarily unavailable Mar 22 15:23:25 v-docker-k6 systemd-udevd: fork of '/usr/lib/systemd/systemd-sysctl --prefix=/net/ipv4/conf/calico_tmp_B --prefix=/net/ipv4/neigh/calico_tmp_B --prefix=/net/ipv6/conf/calico_tmp_B --prefix=/net/ipv6/neigh/calico_tmp_B' failed: Resource temporarily unavailable Mar 22 15:23:25 v-docker-k6 systemd-udevd: fork of child failed: Resource temporarily unavailable Mar 22 15:23:25 v-docker-k6 systemd-udevd: fork of child failed: Resource temporarily unavailable Mar 22 15:23:27 v-docker-k6 kube-proxy: E0322 15:23:27.490837 3904 proxier.go:1520] Failed to execute iptables-save, syncing all rules: fork/exec /usr/sbin/iptables-save: resource temporarily unavailable Mar 22 15:23:27 v-docker-k6 kube-proxy: E0322 15:23:27.490977 3904 proxier.go:1520] Failed to execute iptables-save, syncing all rules: fork/exec /usr/sbin/iptables-save: resource temporarily unavailable Mar 22 15:23:27 v-docker-k6 kube-proxy: E0322 15:23:27.491093 3904 proxier.go:1469] Failed to ensure that nat chain KUBE-SERVICES exists: error creating chain "KUBE-SERVICES": fork/exec /usr/sbin/iptables: resource temporarily unavailable: Mar 22 15:23:27 v-docker-k6 kube-proxy: E0322 15:23:27.491234 3904 ipset.go:172] Failed to make sure ip set: &{{KUBE-LOAD-BALANCER-LOCAL hash:ip,port inet 1024 65536 0-65535 Kubernetes service load balancer ip + port with externalTrafficPolicy=local} map[] 0xc0002178d0} exist, error: error creating ipset KUBE-LOAD-BALANCER-LOCAL, error: fork/exec /usr/sbin/ipset: resource temporarily unavailable Mar 22 15:23:27 v-docker-k6 dockerd: time="2023-03-22T15:23:27.855087150+08:00" level=warning msg="failed to retrieve runc version: fork/exec /usr/bin/runc: resource temporarily unavailable" Mar 22 15:23:27 v-docker-k6 dockerd: time="2023-03-22T15:23:27.855308912+08:00" level=warning msg="failed to retrieve docker-init version: fork/exec /usr/bin/docker-init: resource temporarily unavailable" |
经搜查,上述日志说明是系统上的进程数量太多了,达到了命令"ulimit -u"的限制。我们可以根据日志,对系统参数进行优化,然后reboot一下主机。reboot后,117节点会重新加入k8s集群(确保kubelet进程自动启动)。
kubernetes各种状态的说明,可参考文章:服务实例状态说明,介绍了CrashLoopBackOff、Unschedulable、Evicted、CrashLoopBackOff、Pending、ImagePullBackOff/ErrImagePull等常见状态,熟悉这些状态,以及分析思路,可以快速定位和解决k8s遇到的问题。
terminating状态分析及POD各种状态的分析思路
本文2024-09-23 01:10:25发表“云苍穹知识”栏目。
本文链接:https://wenku.my7c.com/article/kingdee-cangqiong-144245.html