Versions Compared
Key
- This line was added.
- This line was removed.
- Formatting was changed.
问题描述
kubernetes
版本:v1.22.5
部分Pod
在新版本发布后一直处于ContainerCreating
状态,经过kubectl delete
命令删除后一直Terminating
状态。
排查过程
遇到问题先查日志
首先进入宿主机,查看三个日志,按照pod
名称及imageid
进行筛选。其中pod
名称为khaos-guardian-bmzsk
,imageid
为1da9e4f1-a5d4-40db-b8bc-4db1d27ca458
。
kubelet
日志:journalctl -u kubelet | grep khaos-guardian-bmzsk
docker
日志:journalctl -u docker | grep 1da9e4f1-a5d4-40db-b8bc-4db1d27ca458
- 系统日志:
cd /var/log && grep khaos-guardian-bmzsk messages
花费了不少时间检索日志,实际上没有找到任何有用的信息。
配置细节排查
我们可以看到整个集群只有这个daemonset
的pod
出现过这个问题,其他的pod
没有出现,那么可能问题出在这个daemonset
的某些配置引发的这个问题。但这个daemonset
的配置比较复杂,并且包含4
个container
,所以这块排查起来很吃力,也比较浪费时间。经过细节的梳理,以及团队内部同学的协作,我们最终发现是有两个配置项引发的问题。
hostPID
lifecycle.postStart
hostPID
官方文档:https://kubernetes.io/docs/concepts/security/pod-security-standards/
配置到pod spec
中,用于让Pod
中的所有容器感知宿主机的进程信息,并且执行进程管理。
此外,相关联的还有一个shareProcessNamespace
配置,也是配置到pod spec
中,用于单pod
多container
场景下让pod
下的container
相互感知pid
,具体介绍:https://kubernetes.io/docs/tasks/configure-pod-container/share-process-namespace/
lifecycle.postStart
用于在指定container
成功Running
后执行一些自定义脚本,具体介绍:https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle/
相关联的docker bug
这里与hostPID/shareProcessNamespace
相关的有一个docker
的bug
:https://github.com/kubernetes/kubernetes/issues/92214
当开启进程信息共享时,如果对docker
容器执行exec
命令,并且docker
容器先于exec
进程退出,那么此时exec
的执行会卡住。
docker bug复现过程
通过docker run
运行一个容器:
Code Block | ||
---|---|---|
| ||
docker run -d --pid=host --rm --name nginx nginx |
在另一个终端执行docker exec
指令:
Code Block | ||
---|---|---|
| ||
docker exec -it nginx sh |
随后kill
容器:
Code Block | ||
---|---|---|
| ||
docker kill nginx |
可以看到当kill
掉容器后,对应的exec
进程此时卡住了,无法退出,只能强行关闭终端解决。
Kubernetes Pod管理细节
如果想要了解这个docker bug
对pod
生命周期的影响,我们来看看kubernetes
源码中的pod
创建流程。首先了解一个背景,kubernetes
的每一个pod
在kubelet
中都对应有一个goroutine
一一对应来管理维护其reconcile
,即任何pod spec
的变更或者宿主机container status
的变化都由该goroutine
来保证执行和同步。
SyncPod
每当Pod Spec
变化时,例如创建时,会按照EphemeralContainers、InitContainers、Containers
依次执行容器创建。具体参考:https://github.com/kubernetes/kubernetes/blob/b722d017a34b300a2284b890448e5a605f21d01e/pkg/kubelet/kuberuntime/kuberuntime_manager.go#L1048
Image Added
Tip |
---|
这种创建虽然在 |
但是,如果容器中存在PostStart
脚本,那么将会阻塞后续容器的创建,需要等待PostStart
脚本执行完成后才会继续执行。具体参考:https://github.com/kubernetes/kubernetes/blob/b722d017a34b300a2284b890448e5a605f21d01e/pkg/kubelet/kuberuntime/kuberuntime_container.go#L297
Image Added
如果底层是docker
,那么这里使用的便正是docker exec
命令来实现的PostStart
自定义脚本执行。
解决问题
找到问题根因后,解决目前集群中Terminating
的Pod
就比较简单了。
step1:检索出Terminating
的Pod
Code Block | ||
---|---|---|
| ||
kubectl get pod -n xxx -owide | grep Terminating |
step2:进入宿主机干掉docker
容器
Code Block | ||
---|---|---|
| ||
kubectl node-shell x.x.x.x
docker ps -a | grep xxx
docker rm -f xxx
exit |
step3:退出宿主机,强删对应的Pod
Code Block | ||
---|---|---|
| ||
kubectl delete -n xxx pod/xxx --force |
操作记录:
Image Added
Image Removed
问题总结
- 尽量不要使用
docker
作为底层容器管理工具。 - 尽量不要在
pod
中使用postStart
自定义脚本。
Panel | ||
---|---|---|
| ||
|