文章目录
- 问题现象
- 问题分析
- 问题解决
- 拓展
- 总结
问题现象
在一次测试ConfigMap的过程中,我想起一个单容器的pod,简单的打印出容器内所有的环境变量,以验证ConfigMap的传递。结果pod起来以后一直出现CrashLoopBackOff的状态。
这里为了抽离出问题的本质,去掉干扰项,将pod的生成yaml文件简化如下
apiVersion: v1
kind: Pod
metadata:
name: configmap-pod-1
spec:
containers:
- name: cm-container-1
image: alpine
imagePullPolicy: IfNotPresent
command: [ "/bin/sh", "-c", "env" ]
创建pod
[root@k8s-master ~]# kubectl apply -f test.yaml
pod/configmap-pod-1 created
但是pod却一直是如下状态
[root@k8s-master ~]# kubectl get pod configmap-pod-1 -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
configmap-pod-1 0/1 CrashLoopBackOff 3 68s 10.244.1.90 k8s-node1 <none> <none>
不仅显示CrashLoopBackOff
状态,还一直重启
问题分析
通常pod出现这种出错并不停重启的现象,归纳起来有以下几种可能:
- 容器内应用一直在崩溃
- yaml文件中对pod的一些字段配置有误
- k8s集群的部署有问题
但是我这里一条都不满足。这个集群一直运行着很多应用都平安无事,说明集群本身没事。这个容器的镜像只是官方的alpine,除了额外运行了一条shell命令,所以不可能崩溃。至于yaml文件就更不可能了,寥寥无几的几个字段反复检查了好几遍。
确实神奇。
后来经过Google,发现还有另一种情况也会出现这种现象。就是容器本身没有问题,出在容器运行的命令上,也就是这一行
command: [ "/bin/sh", "-c", "env" ]
容器正常启动,然后运行配置的主命令,这个主命令要么是image的entrypoint,要么是这里的command。此时pod处于running状态(是的,pod在一个短暂的时间处于running中)。但是这个shell命令很快运行完毕,成功退出。一旦主命令退出,pod就会重启,然后循环这一过程。如果用-w
方式去观察pod的状态,就可以看到pod在Running与CrashLoopBackOff之间不停变化。
总结起来,如果没有指定容器的存活探针(LivenessProbe),pod会以主命令的运行状态来判断容器是否存活。如果容器主命令一直正常运行没有退出,则pod处于running状态;如果容器主命令执行完毕或者报错,根据配置的restartPolicy策略决定pod是否重启;如果根本就没有配置主命令,pod会直接根据restartPolicy决定是否重启。而因为默认情况restartPolicy是Always,也就是一直重启,所以会看到上面的现象。
问题解决
那么这个其实就是符合逻辑的正常现象。如果想要pod不用一直重启,可以给pod改一个restartPolicy
apiVersion: v1
kind: Pod
metadata:
name: configmap-pod-1
spec:
containers:
- name: cm-container-1
image: alpine
imagePullPolicy: IfNotPresent
command: [ "/bin/sh", "-c", "env" ]
restartPolicy: Never
之后再启动pod,会发现pod不重启了,而是显示Completed
状态
[root@k8s-master ~]# kubectl apply -f test.yaml
pod/configmap-pod-1 created
[root@k8s-master ~]# kubectl get pod configmap-pod-1 -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
configmap-pod-1 0/1 Completed 0 15s 10.244.1.91 k8s-node1 <none> <none>
拓展
为了验证下上面的说法,我又做了如下几个实验。
- 改一个一直运行不会退出的主命令
将上面的yaml文件修改如下
apiVersion: v1
kind: Pod
metadata:
name: configmap-pod-1
spec:
containers:
- name: cm-container-1
image: alpine
imagePullPolicy: IfNotPresent
command: [ "ping", "8.8.8.8" ]
如果你的机器因为科学上网原因访问不到 8.8.8.8,请换别的地址测试
再启动pod就不会重启了
[root@k8s-master ~]# kubectl apply -f test.yaml
pod/configmap-pod-1 created
[root@k8s-master ~]# kubectl get pod configmap-pod-1 -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
configmap-pod-1 1/1 Running 0 7s 10.244.1.92 k8s-node1 <none> <none>
同时还可以在log中看到ping的结果
[root@k8s-master ~]# kubectl logs configmap-pod-1
PING 8.8.8.8 (8.8.8.8): 56 data bytes
64 bytes from 8.8.8.8: seq=0 ttl=47 time=2.664 ms
64 bytes from 8.8.8.8: seq=1 ttl=47 time=2.320 ms
64 bytes from 8.8.8.8: seq=2 ttl=47 time=2.315 ms
64 bytes from 8.8.8.8: seq=3 ttl=47 time=2.317 ms
64 bytes from 8.8.8.8: seq=4 ttl=47 time=2.376 ms
64 bytes from 8.8.8.8: seq=5 ttl=47 time=2.395 ms
64 bytes from 8.8.8.8: seq=6 ttl=47 time=2.447 ms
64 bytes from 8.8.8.8: seq=7 ttl=47 time=2.431 ms
64 bytes from 8.8.8.8: seq=8 ttl=47 time=2.264 ms
64 bytes from 8.8.8.8: seq=9 ttl=47 time=2.268 ms
64 bytes from 8.8.8.8: seq=10 ttl=47 time=2.302 ms
64 bytes from 8.8.8.8: seq=11 ttl=47 time=2.384 ms
64 bytes from 8.8.8.8: seq=12 ttl=47 time=2.443 ms
64 bytes from 8.8.8.8: seq=13 ttl=47 time=2.439 ms
64 bytes from 8.8.8.8: seq=14 ttl=47 time=2.236 ms
64 bytes from 8.8.8.8: seq=15 ttl=47 time=2.250 ms
64 bytes from 8.8.8.8: seq=16 ttl=47 time=2.330 ms
64 bytes from 8.8.8.8: seq=17 ttl=47 time=4.658 ms
64 bytes from 8.8.8.8: seq=18 ttl=47 time=2.438 ms
64 bytes from 8.8.8.8: seq=19 ttl=47 time=2.483 ms
64 bytes from 8.8.8.8: seq=20 ttl=47 time=2.403 ms
64 bytes from 8.8.8.8: seq=21 ttl=47 time=2.416 ms
64 bytes from 8.8.8.8: seq=22 ttl=47 time=2.437 ms
64 bytes from 8.8.8.8: seq=23 ttl=47 time=3.502 ms
- 不配置主命令
修改yaml文件如下
apiVersion: v1
kind: Pod
metadata:
name: configmap-pod-1
spec:
containers:
- name: cm-container-1
image: alpine
imagePullPolicy: IfNotPresent
restartPolicy: Never
创建pod以后,也是没有重启,并显示Completed
状态
[root@k8s-master ~]# kubectl apply -f test.yaml
pod/configmap-pod-1 created
[root@k8s-master ~]# kubectl get pod configmap-pod-1 -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
configmap-pod-1 0/1 Completed 0 5s 10.244.1.93 k8s-node1 <none> <none>
总结
总结一下出现CrashLoopBackOff这个现象的排查思路:
- 首先确保集群本身部署没有问题
- 确保pod创建时候的yaml文件字段信息无误
- 如果是自己制作的镜像,可以先用docker试试能不能起的来,确保镜像无误
- 最后检查下容器的主命令是否有配置,如果配置了是否很快就结束或者是执行错误退出,导致pod不断重启
如果是因为主命令原因导致不停重启,可以修改restartPolicy为Never只执行一次。或者修改下主命令使得命令能连续运行。