Kubernetes Pod重启策略
1、概述
在Pod的spec中有一个restartPolicy字段,如下:
apiVersion: v1 kind: Pod metadata: name: xxx spec: restartPolicy: Always ...
restartPolicy的值有三个:Always、OnFailure、Never;默认值为Always。
注意 1:虽然restartPolicy字段是Pod的配置,但是其实是作用于Pod的Container,换句话说,不应该叫Pod的重启策略,而是叫Container的重启策略;Pod中的所有Container都适用于这个策略。
注意 2:重启策略适用于Pod对象中的所有容器,首次需要重启的容器,将在其需要时立即进行重启,随后再次需要重启的操作将由Kubelet延迟一段时间后进行,且反复的重启操作的延迟时长为10s,20s,40s,80s,160s,300s,300s是最大延迟时长。
三种策略的区别在于:
- Always:只要Container退出就重启,即使它的退出码为0(即成功退出)
- OnFailure:如果Container的退出码不是0(即失败退出),就重启
- Never:Container退出后永不重启
所谓Container的退出码,就是Container中进程号为1的进程的退出码。每个进程退出时都有一个退出码,我们常见的提示exit 0表示退出码为0(即成功退出)。举个例子:shell命令cat /tmp/file,如果文件/tmp/file存在,则该命令(进程)的退出码为0。
2、Pod中的Container重启规则
2.1 Pod中Container重启命名规则
上面谈到当Container退出后,Container可能会被重启,那么Container是如何被重启的呢?是Kubelet调用类似于docker start的API拉起?还是重新创建一个docker容器(docker create && docker start)?
答案是,Kubelet会重新创建一个docker容器。
我们给一个例子,创建一个如下的Pod,这个Pod中有两个Container,其中demo1这个Container在启动后60秒就会退出(退出码为0),demo2这个Container则会一直运行。
apiVersion: v1 kind: Pod metadata: name: test-restartpolicy namespace: test-restartpolicy spec: restartPolicy: Always containers: - name: demo1 image: busybox:1.31.1 command: - /bin/sh - -c - sleep 60 - name: demo2 image: tomcat:9.0.37
接下来我们创建test-restartpolicy这个命名空间和Pod。
[root@node1 test]# kubectl get pods -n=test-restartpolicy NAME READY STATUS RESTARTS AGE test-restartpolicy 2/2 Running 0 44s
然后观察demo1这个Container的docker名字与ID,发现名字(docker name字段)为k8s_demo1_test-restartpolicy_test-restartpolicy_88d4575b-5d59-4e25-8b61-ea0e0bfef035_0,ID为f09dd4d59d76。
[root@node1 test]# docker ps|grep demo1 f09dd4d59d76 1c35c4412082 "/bin/sh -c 'sleep 6…" 32 seconds ago Up 30 seconds k8s_demo1_test-restartpolicy_test-restartpolicy_88d4575b-5d59-4e25-8b61-ea0e0bfef035_0
再过一分钟左右,我们再看这个Container的名字和ID,发现名字为k8s_demo1_test-restartpolicy_test-restartpolicy_88d4575b-5d59-4e25-8b61-ea0e0bfef035_1,ID为7ba3cc9685eb。这说明,重启后已经不是同一个docker容器了。
[root@node1 test]# docker ps|grep demo1 7ba3cc9685eb 1c35c4412082 "/bin/sh -c 'sleep 6…" 14 seconds ago Up 13 seconds k8s_demo1_test-restartpolicy_test-restartpolicy_88d4575b-5d59-4e25-8b61-ea0e0bfef035_1
同理,再过一分钟左右,我们再看这个Container的名字和ID,发现名字为k8s_demo1_test-restartpolicy_test-restartpolicy_88d4575b-5d59-4e25-8b61-ea0e0bfef035_2,ID为d71f73027239。这说明,重启后已经不是同一个docker容器了。
d71f73027239 1c35c4412082 "/bin/sh -c 'sleep 6…" 7 seconds ago Up 5 seconds k8s_demo1_test-restartpolicy_test-restartpolicy_88d4575b-5d59-4e25-8b61-ea0e0bfef035_2
如果我们细心的会发现,docker容器的名字其实是有规则的,为
k8s_<ContainerName_In_Pod>_<PodName>_<Namespace>_<PodID>_<Index>
其中最后一个<Index>一开始为0,每重启一次就会递增1。
2.2 查看Pod状态规则
在2.1查看Pod中的容器重启命名规则的时候,同时开了一个Shell窗口,一直观察Pod的状态。
[root@node1 test]# kubectl get pods -n=test-restartpolicy NAME READY STATUS RESTARTS AGE test-restartpolicy 2/2 Running 0 1s
可以看到在demo1容器第一次重启后,Pod容器状态从NotReady变成了Running。
[root@node1 test]# kubectl get pods -n=test-restartpolicy NAME READY STATUS RESTARTS AGE test-restartpolicy 2/2 Running 0 64s [root@node1 test]# kubectl get pods -n=test-restartpolicy NAME READY STATUS RESTARTS AGE test-restartpolicy 1/2 NotReady 0 65s [root@node1 test]# kubectl get pods -n=test-restartpolicy NAME READY STATUS RESTARTS AGE test-restartpolicy 2/2 Running 1 67s
可以看到在demo1容器第二次重启后,Pod容器状态从NotReady先变成了CrashLoopBackOff再变成Running。
[root@node1 test]# kubectl get pods -n=test-restartpolicy NAME READY STATUS RESTARTS AGE test-restartpolicy 2/2 Running 1 2m5s [root@node1 test]# kubectl get pods -n=test-restartpolicy NAME READY STATUS RESTARTS AGE test-restartpolicy 1/2 NotReady 1 2m6s ........ [root@node1 test]# kubectl get pods -n=test-restartpolicy NAME READY STATUS RESTARTS AGE test-restartpolicy 1/2 NotReady 1 2m20s [root@node1 test]# kubectl get pods -n=test-restartpolicy NAME READY STATUS RESTARTS AGE test-restartpolicy 1/2 CrashLoopBackOff 1 2m21s [root@node1 test]# kubectl get pods -n=test-restartpolicy NAME READY STATUS RESTARTS AGE test-restartpolicy 1/2 CrashLoopBackOff 1 2m22s [root@node1 test]# kubectl get pods -n=test-restartpolicy NAME READY STATUS RESTARTS AGE test-restartpolicy 2/2 Running 2 2m23s
过一段时间后,可以看到Pod容器状态大部分时间为CrashLoopBackOff,这是因为容器频繁重启的话会有退避延迟时间,首次需要重启的容器,将在其需要时立即进行重启,随后再次需要重启的操作将由Kubelet延迟一段时间后进行,且反复的重启操作的延迟时长为10s,20s,40s,80s,160s,300s,300s是最大延迟时长,过一段时间后demo1容器的重启延迟时间变成了300s,此时Pod状态为CrashLoopBackOff,重启延迟时间过后demo1容器状态会变成running,再过60s,demo1容器退出后,demo1的状态又会从NotReady变成CrashLoopBackOff,之后周而复始。
[root@node1 test]# kubectl get pods -n=test-restartpolicy NAME READY STATUS RESTARTS AGE test-restartpolicy 1/2 CrashLoopBackOff 7 22m [root@node1 test]# kubectl get pods -n=test-restartpolicy NAME READY STATUS RESTARTS AGE test-restartpolicy 1/2 CrashLoopBackOff 7 22m
如果我们细心的会发现,对于Always重启策略的Pod来说,Pod中容器重启时,查看Pod 状态字段值是有规则的,Pod中容器整个重启过程Pod状态会从Running -> NotReady -> CrashLoopBackOff -> Running,周而复始。
注意 1:NotReady(不可用):当容器重启或出现故障时,Pod的状态会变为NotReady。这表示其中至少一个容器无法正常工作,导致Pod无法提供服务。
注意 2:CrashLoopBackOff(崩溃循环回退):如果容器频繁重启且无法成功启动,Pod的状态将变为CrashLoopBackOff。这意味着容器在启动后不断崩溃并尝试重新启动,但仍无法正常运行。
注意 3:Pod状态为CrashLoopBackOff表示其中的一个或多个容器出现了崩溃循环回退的情况。这种状态通常是由以下情况引起的:
容器崩溃:Pod中的一个或多个容器在启动后立即崩溃。这可能是由于容器应用程序内部错误、配置问题、资源不足或依赖项问题等引起的。
容器重启循环:当容器崩溃后,Kubernetes会尝试自动重新启动容器。如果容器在启动后仍然崩溃,并且持续进行容器重启尝试,就会导致CrashLoopBackOff状态。
CrashLoopBackOff状态表示Kubernetes在一段时间内尝试重启容器,但容器仍然无法正常运行。为了避免对底层系统资源的无限消耗,Kubernetes会暂停一段时间后再次尝试重启。这种循环会持续进行,直到问题得到解决或达到重试次数的限制。
2.3 查看Pod RESTARTS字段值规则
实例一:
过一段查看2.1中创建Pod,可以看到RESTARTS字段的值为8。
[root@node1 ~]# kubectl get pods -n=test-restartpolicy NAME READY STATUS RESTARTS AGE test-restartpolicy 2/2 Running 8 24m
此时我们查看Pod的yaml文件,会发现demo1这个Container的restartCount为8,demo2这个Container的restartCount为0。
kubectl get pods -n=test-restartpolicy -o yaml ...... status: containerStatuses: - containerID: docker://75a85ae72574d5edb42486dc58d3526b3c7ed5d29c9959c898a4689f12fef7f5 ...... name: demo1 ready: true restartCount: 8 started: true ...... - containerID: docker://1d7fe0cb75d5a6aa9074f2ceb0dc7515df0aa6082b1e4bb9e77931b5724445ca ...... name: demo2 ready: true restartCount: 0 started: true ......
示例2:
此时删除test-restartpolicy这个Pod,修改Pod规格配置文件如下,让demo2这个Container在启动30秒后也退出(退出码为0)。
apiVersion: v1 kind: Pod metadata: name: test-restartpolicy namespace: test-restartpolicy spec: restartPolicy: Always containers: - name: demo1 image: busybox:1.31.1 command: - /bin/sh - -c - sleep 60 - name: demo2 image: busybox:1.31.1 command: - /bin/sh - -c - sleep 30 nodeSelector: kubernetes.io/hostname: node1
接下来我们创建test-restartpolicy这个Pod,过几分钟查看Pod。
[root@node1 test]# kubectl get pods -n=test-restartpolicy NAME READY STATUS RESTARTS AGE test-restartpolicy 1/2 CrashLoopBackOff 7 4m27s
此时我们查看Pod的yaml文件,会发现demo1这个Container的restartCount为3,demo2这个Container的restartCount为4。
[root@node1 test]# kubectl get pods -n=test-restartpolicy -o yaml ...... status: ...... containerStatuses: - containerID: docker://a34abd3d662c0d5c309f7967ccb2e3a70e25bda520a8b55b63eee8cff7892762 ...... name: demo1 ready: true restartCount: 3 started: true ...... - containerID: docker://4f97cccf338fff56f0d894cf4f89bda48b6108046d3ff6cfd8097bd2e6efe86b ...... name: demo2 ready: false restartCount: 4 started: false .......
如果我们细心的会发现,查看Pod RESTARTS字段值是有规则的,RESTARTS
字段表示整个Pod中所有容器的累计重启次数。如果任何一个容器在Pod中重启,RESTARTS
字段的值会增加。这意味着即使只有一个容器重启了,整个Pod的RESTARTS
字段值也会增加。
2.4 进入Pod容器规则
以sh方式登陆到Pod中的某个容器里(使用2.1中创建的deployment资源对象):
kubectl exec -it <pod-name> -c <container-name> /bin/sh
还是2.1创建的Pod实例,进入demo1容器内部
[root@node1 ~]# kubectl exec -it -n=test-restartpolicy test-restartpolicy -c demo1 /bin/sh kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [COMMAND] instead. / # top Mem: 194720396K used, 1279444K free, 611808K shrd, 647372K buff, 109342248K cached CPU: 10.5% usr 6.5% sys 0.0% nic 76.6% idle 5.8% io 0.0% irq 0.3% sirq Load average: 16.27 15.37 15.43 6/20460 19 PID PPID USER STAT VSZ %VSZ CPU %CPU COMMAND 13 0 root S 1296 0.0 0 0.0 /bin/sh 19 13 root R 1292 0.0 3 0.0 top 1 0 root S 1280 0.0 8 0.0 sleep 60
进入demo2容器内部
[root@node1 test]# kubectl exec -it -n=test-restartpolicy test-restartpolicy -c demo2 bash kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [COMMAND] instead. root@test-restartpolicy:/usr/local/tomcat# top top - 00:16:39 up 55 days, 19:23, 0 users, load average: 16.37, 17.25, 16.98 Tasks: 3 total, 1 running, 2 sleeping, 0 stopped, 0 zombie %Cpu(s): 7.4 us, 4.7 sy, 0.1 ni, 81.8 id, 5.9 wa, 0.0 hi, 0.1 si, 0.0 st MiB Mem : 191406.1 total, 3684.6 free, 78569.1 used, 109152.4 buff/cache MiB Swap: 0.0 total, 0.0 free, 0.0 used. 111506.1 avail Mem PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND 1 root 20 0 33.3g 98848 16712 S 0.3 0.1 0:03.01 java 38 root 20 0 5740 2172 1676 S 0.0 0.0 0:00.01 bash 46 root 20 0 9752 1804 1348 R 0.0 0.0 0:00.01 top
可以看到,同一个Pod中每个容器都有自己的进程空间, 当同一个Pod中的一个容器宕掉时,它的故障通常不会直接影响其他容器的运行。其他容器仍然可以继续运行,除非它们与宕掉容器之间存在依赖关系。
注意 1:每个容器都有自己的进程空间,因此一个容器的崩溃不会直接影响其他容器的进程。此外,Kubernetes会监控容器的运行状况,并在发现容器不再处于运行状态时采取相应的行动。它可以自动重新启动容器,使其恢复正常运行。然而,如果多个容器之间有依赖关系或紧密耦合,那么一个容器的故障可能会影响其他容器的功能。例如,如果一个容器负责提供共享服务,而其他容器依赖于该服务进行通信,那么当该容器宕掉时,其他容器可能无法正常工作。
3、Pod中Container重启策略实战
由于在第2章节已经演示了Pod默认的重启策略, 在这一节,将实战演示下Never、OnFailure重启策略。
3.1 Never重启策略
示例一:
创建一个如下的Pod,重启策略为Nerver。
apiVersion: v1 kind: Pod metadata: name: test-restartpolicy namespace: test-restartpolicy spec: containers: - name: demo1 image: nginx:1.14-alpine ports: - name: nginx-port containerPort: 80 livenessProbe: httpGet: scheme: HTTP port: 80 path: /hello restartPolicy: Never
查看Pod详情,关注下存活探针Liveness配置和状态码。
其中对于存活探针配置,容器启动后立即进行探测,如果1s内容器没有给出回应则记作探测失败。每次间隔10s进行一次探测,在探测连续失败3次后重启容器。
- delay:延迟,delay=0s,表示在容器启动后立即开始探测,没有延迟时间
- timeout:超时,timeout=1s,表示容器必须在1s内进行响应,否则这次探测记作失败
- period:周期,period=10s,表示每10s探测一次容器
- success:成功,#success=1,表示连续1次成功后记作成功
- failure:失败,#failure=3,表示连续3次失败后会重启容器
对于状态码,Pod中容器退出状态码为0,这说明存活探针是正常的使容器停止。
[root@node1 ~]# kubectl describe pods -n=test-restartpolicy test-restartpolicy ....... Status: Succeeded IP: 10.233.65.239 IPs: IP: 10.233.65.239 Containers: demo1: Container ID: docker://f401fb32538f59a2aac3850cca5145b71585645b27bc8cfea9c76112bd71bb73 Image: nginx:1.14-alpine Image ID: docker-pullable://nginx@sha256:485b610fefec7ff6c463ced9623314a04ed67e3945b9c08d7e53a47f6d108dc7 Port: 80/TCP Host Port: 0/TCP State: Terminated Reason: Completed Exit Code: 0 Started: Sun, 02 Jul 2023 05:48:38 +0800 Finished: Sun, 02 Jul 2023 05:49:07 +0800 Ready: False Restart Count: 0 Liveness: http-get http://:80/hello delay=0s timeout=1s period=10s #success=1 #failure=3 Environment: <none> Mounts: /var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-wjdbh (ro) ...... Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal Scheduled 88s default-scheduler Successfully assigned test-restartpolicy/test-restartpolicy to harbor-slave Normal Pulled <invalid> kubelet Container image "nginx:1.14-alpine" already present on machine Normal Created <invalid> kubelet Created container demo1 Normal Started <invalid> kubelet Started container demo1 Warning Unhealthy <invalid> (x3 over <invalid>) kubelet Liveness probe failed: HTTP probe failed with statuscode: 404 Normal Killing <invalid> kubelet Stopping container demo1
Pod创建30秒后再查看Pod状态,Pod中容器退出状态码为0的话,Pod状态为Completed。
[root@node1 test]# kubectl get pods -n=test-restartpolicy NAME READY STATUS RESTARTS AGE test-restartpolicy 0/1 Completed 0 4m13s
注意 1:Pod的Completed状态表示其中的所有容器已成功完成任务并终止。一旦Pod中的所有容器完成其工作并退出,Pod的状态将变为Completed。当Pod状态为Completed时,说明该Pod中的所有容器已成功完成其任务,这可以是一个批处理作业、定时任务或其他短暂的工作。一旦任务完成,Pod将进入Completed状态,并保持在该状态,直到被删除。Completed状态的Pod不会自动重启,也不会再次运行其中的容器。它们保留在集群中的历史记录中,但不会继续占用资源。
查看Pod日志,虽然Pod状态是Completed,但是是能查看Pod日志的,那么Never重启策略的Pod在某些场景下是非常有用的,比如Pod中的容器频繁重启,捕捉停止容器日志比较麻烦,这时如果Pod是默认的Always,可以通过临时将Pod的重启策略改成Never,这样可以通过describe Pod和查看Pod日志来分析Pod重启原因。
[root@node1 test]# kubectl logs -f -n=test-restartpolicy test-restartpolicy 2023/06/14 07:57:11 [error] 7#7: *1 open() "/usr/share/nginx/html/hello" failed (2: No such file or directory), client: 10.233.64.1, server: localhost, request: "GET /hello HTTP/1.1", host: "10.233.64.161:80" 10.233.64.1 - - [14/Jun/2023:07:57:11 +0000] "GET /hello HTTP/1.1" 404 169 "-" "kube-probe/1.21" "-" 2023/06/14 07:57:21 [error] 7#7: *2 open() "/usr/share/nginx/html/hello" failed (2: No such file or directory), client: 10.233.64.1, server: localhost, request: "GET /hello HTTP/1.1", host: "10.233.64.161:80" 10.233.64.1 - - [14/Jun/2023:07:57:21 +0000] "GET /hello HTTP/1.1" 404 169 "-" "kube-probe/1.21" "-" 2023/06/14 07:57:31 [error] 7#7: *3 open() "/usr/share/nginx/html/hello" failed (2: No such file or directory), client: 10.233.64.1, server: localhost, request: "GET /hello HTTP/1.1", host: "10.233.64.161:80" 10.233.64.1 - - [14/Jun/2023:07:57:31 +0000] "GET /hello HTTP/1.1" 404 169 "-" "kube-probe/1.21" "-"
示例二:
创建一个如下的Pod,重启策略为Nerver。
apiVersion: v1 kind: Pod metadata: name: test-restartpolicy namespace: test-restartpolicy spec: restartPolicy: Never containers: - name: demo1 image: busybox:1.31.1 command: ["/bin/sh","-c","sleep 60,exit 1"]
查看Pod详情,可以看到Pod中容器退出状态码是1。
[root@node1 test]# kubectl describe pod -n=test-restartpolicy test-restartpolicy ...... Containers: demo1: Container ID: docker://bfb7417114d852e33ce299c5267587fa1be0103ebb9bc106c18c35401777260b ...... Command: /bin/sh -c sleep 60,exit 1 State: Terminated Reason: Error Exit Code: 1 Started: Thu, 15 Jun 2023 05:26:50 +0800 Finished: Thu, 15 Jun 2023 05:26:50 +0800 Ready: False Restart Count: 0 Environment: <none> Mounts: /var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-btfrd (ro) ......
查看Pod状态,Pod中容器退出状态码为非0的话,Pod状态为Error。
[root@node1 test]# kubectl get pods -n=test-restartpolicy NAME READY STATUS RESTARTS AGE test-restartpolicy 0/1 Error 0 2m41s
示例三:
创建一个如下的Pod,重启策略为Nerver。
apiVersion: v1 kind: Pod metadata: name: test-restartpolicy namespace: test-restartpolicy spec: restartPolicy: Never containers: - name: demo1 image: busybox:1.31.1 command: ["/bin/sh","-c","sleep 60,exit 1"] - name: demo2 image: busybox:1.31.1 command: - /bin/sh - -c - sleep 3000
创建Pod大约1分钟后查看Pod状态,只要Pod中有一个容器异常退出,那么它的状态就会变成error。
[root@node1 test]# kubectl get pods -n=test-restartpolicy NAME READY STATUS RESTARTS AGE test-restartpolicy 1/2 Error 0 2m
此时进入demo2容器,可以正常进入,说明demo2容器是正常运行的。
[root@node1 test]# kubectl exec -it -n=test-restartpolicy test-restartpolicy -c demo2 /bin/sh kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [COMMAND] instead. / # exit
对于Never重启策略的Pod,通过以上三个示例可以得出如下结论:
- Pod中只要有容器停止,并且停止容器的状态码都为0,那么Pod状态为Completed。
- Pod中只要有容器停止,并且存在非0退出状态码,那么Pod状态为Error。
- 不管退出状态码是Completed还是Error,都能查看Pod日志的,那么Never重启策略的Pod在某些场景下是非常有用的,比如Pod中的容器频繁重启,这时如果Pod是默认的Always,可以通过临时将Pod的重启策略改成Never,这样可以通过describe Pod和查看Pod日志来分析Pod重启原因。
- 同一个Pod中的一个容器宕掉时,它的故障通常不会直接影响其他容器的运行。其他容器仍然可以继续运行,除非它们与宕掉容器之间存在依赖关系。
3.2 OnFailure重启策略
示例一:
创建一个如下的Pod,重启策略为OnFailure。
apiVersion: v1 kind: Pod metadata: name: test-restartpolicy namespace: test-restartpolicy spec: containers: - name: demo1 image: nginx:1.14-alpine ports: - name: nginx-port containerPort: 80 livenessProbe: httpGet: scheme: HTTP port: 80 path: /hello restartPolicy: OnFailure
这个示例在3.1示例一中已经讲过,这里不再详述,Pod中的demo1容器在启动30秒后会因为存活探针检测导致容器停止,容器退出码是0,此时查看Pod信息,Pod状态是Completed。
[root@node1 test]# kubectl get pods -n=test-restartpolicy NAME READY STATUS RESTARTS AGE test-restartpolicy 0/1 Completed 4 3m9s
注意 1:查看Pod信息的时候和3.1示例一中不同的是Pod RESTARTS字段重启次数为4(在3.1实例中,我们知道存活探针检查失败的容器退出状态码为0,而这里重启次数为什么是4,目前这里没搞清楚,是bug,还是这块研究不深,有大神可以评论给解惑下)。
查看Pod详情,重启次数为4是因为探针导致。
[root@node1 test]# kubectl describe pods -n=test-restartpolicy test-restartpolicy Name: test-restartpolicy Namespace: test-restartpolicy Priority: 0 Node: node1/10.20.30.31 Start Time: Wed, 14 Jun 2023 17:07:10 +0800 Labels: <none> Annotations: <none> Status: Running IP: 10.233.64.164 IPs: IP: 10.233.64.164 Containers: demo1: ...... Last State: Terminated Reason: Completed Exit Code: 0 Started: Wed, 14 Jun 2023 17:08:41 +0800 Finished: Wed, 14 Jun 2023 17:09:10 +0800 Ready: True Restart Count: 4 Liveness: http-get http://:80/hello delay=0s timeout=1s period=10s #success=1 #failure=3 Environment: <none> Mounts: /var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-8pj6p (ro) ....... Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal Scheduled 2m12s default-scheduler Successfully assigned test-restartpolicy/test-restartpolicy to node1 Normal Killing 42s (x3 over 102s) kubelet Container demo1 failed liveness probe, will be restarted Normal Pulled 41s (x4 over 2m9s) kubelet Container image "nginx:1.14-alpine" already present on machine Normal Created 41s (x4 over 2m9s) kubelet Created container demo1 Normal Started 41s (x4 over 2m8s) kubelet Started container demo1 Warning Unhealthy 32s (x10 over 2m2s) kubelet Liveness probe failed: HTTP probe failed with statuscode: 404
示例二:
创建一个如下的Pod,重启策略为OnFailure。
apiVersion: v1 kind: Pod metadata: name: test-restartpolicy namespace: test-restartpolicy spec: restartPolicy: OnFailure containers: - name: demo1 image: busybox:1.31.1 command: ["/bin/sh","-c","sleep 10,exit"]
注意 1:使用错误的命令"sleep 10,exit"
[root@node1 ~]# sleep 10,exit sleep: invalid time interval ‘10,exit’ Try 'sleep --help' for more information.
创建几分钟后,查看Pod状态,可看到容器当前已经重启了 5 次。
[root@node1 test]# kubectl get pods -n=test-restartpolicy NAME READY STATUS RESTARTS AGE test-restartpolicy 0/1 CrashLoopBackOff 5 4m5s
对于OnFailure重启策略的Pod,通过以上两个示例可以得出如下结论:
- Pod中容器停止,并且停止容器的状态码为0,那么Pod状态为Completed。
- Pod中容器停止,并且停止容器的状态码为非0,那么Pod就会像Always策略那样重启容器。
4、总结
- 一般Pod是通过工作负载去管理的,在五种工作负载中,一般建议:Deployment、StatefulSet、DaemonSet设置为Always;Job与CronJob设置为OnFailure或Never。
- 虽然restartPolicy字段是Pod的配置,但是其实是作用于Pod的Container,换句话说,不应该叫Pod的重启策略,而是叫Container的重启策略;Pod中的所有Container都适用于这个策略。
- 重启策略适用于Pod对象中的所有容器,首次需要重启的容器,将在其需要时立即进行重启,随后再次需要重启的操作将由Kubelet延迟一段时间后进行,且反复的重启操作的延迟时长为10s,20s,40s,80s,160s,300s,300s是最大延迟时长。
- Pod中重启的容器以k8s_<ContainerName_In_Pod>_<PodName>_<Namespace>_<PodID>_<Index>规则命名。
- 对于Always重启策略的Pod来说,Pod中容器重启时,查看Pod 状态字段值是有规则的,Pod中容器整个重启过程Pod状态会从Running -> NotReady -> CrashLoopBackOff -> Running,周而复始。
- 查看Pod RESTARTS字段值是有规则的,
RESTARTS
字段表示整个Pod中所有容器的累计重启次数。如果任何一个容器在Pod中重启,RESTARTS
字段的值会增加。这意味着即使只有一个容器重启了,整个Pod的RESTARTS
字段值也会增加。 - 同一个Pod中每个容器都有自己的进程空间, 当同一个Pod中的一个容器宕掉时,它的故障通常不会直接影响其他容器的运行。其他容器仍然可以继续运行,除非它们与宕掉容器之间存在依赖关系。 对于Never重启策略的Pod:
- Pod中只要有容器停止,并且停止容器的状态码都为0,那么Pod状态为Completed。
- Pod中只要有容器停止,并且存在非0退出状态码,那么Pod状态为Error。
- 不管退出状态码是Completed还是Error,都能查看Pod日志的,那么Never重启策略的Pod在某些场景下是非常有用的,比如Pod中的容器频繁重启,这时如果Pod是默认的Always,可以通过临时将Pod的重启策略改成Never,这样可以通过describe Pod和查看Pod日志来分析Pod重启原因。
- 同一个Pod中的一个容器宕掉时,它的故障通常不会直接影响其他容器的运行。其他容器仍然可以继续运行,除非它们与宕掉容器之间存在依赖关系。
- Pod中容器停止,并且停止容器的状态码为0,那么Pod状态为Completed。
- Pod中容器停止,并且停止容器的状态码为非0,那么Pod就会像Always策略那样重启容器。