Kubernetes Pod重啟策略

2023-06-14 18:00:21

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中的某個容器裡:

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 test]# kubectl describe pod -n=test-restartpolicy test-restartpolicy 
Containers:
  demo1:
    Container ID:   docker://183a5fb4ad7556ba74460dc2af1afe2821f60100fadb0d2882cc0db929348ecc
    ......
    State:          Terminated
      Reason:       Completed
      Exit Code:    0
      Started:      Wed, 14 Jun 2023 16:32:57 +0800
      Finished:     Wed, 14 Jun 2023 16:33:24 +0800
    Ready:          False
    Restart Count:  0
    Liveness:       http-get http://:80/hello delay=0s timeout=1s period=10s #success=1 #failure=3
    ......
                             node.kubernetes.io/unreachable:NoExecute op=Exists for 300s
Events:
  Type     Reason     Age   From               Message
  ----     ------     ----  ----               -------
  Normal   Scheduled  11s   default-scheduler  Successfully assigned test-restartpolicy/test-restartpolicy to node1
  Normal   Pulled     9s    kubelet            Container image "nginx:1.14-alpine" already present on machine
  Normal   Created    8s    kubelet            Created container demo1
  Normal   Started    8s    kubelet            Started container demo1
  Warning  Unhealthy  1s    kubelet            Liveness probe failed: HTTP probe failed with statuscode: 404
[root@node1 test]# kubectl get pods -n=test-restartpolicy 
NAME                 READY   STATUS    RESTARTS   AGE
test-restartpolicy   1/1     Running   0    

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: harbor.openserver.cn:443/library/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,目前原理沒搞清楚)。

檢視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: harbor.openserver.cn:443/library/busybox:1.31.1
    command: ["/bin/sh","-c","sleep 10,exit"]

建立幾分鐘後,檢視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中的一個容器宕掉時,它的故障通常不會直接影響其他容器的執行。其他容器仍然可以繼續執行,除非它們與宕掉容器之間存在依賴關係。
    對於OnFailure重啟策略的Pod:
    • Pod中容器停止,並且停止容器的狀態碼為0,那麼Pod狀態為Completed。
    • Pod中容器停止,並且停止容器的狀態碼為非0,那麼Pod就會像Always策略那樣重啟容器。

參考:https://www.kancloud.cn/pshizhsysu/kubernetes/1802621

參考:https://developer.aliyun.com/article/932900