掌握Pod-Pod調度策略

  • 2019 年 11 月 22 日
  • 筆記

一 Pod生命周期管理

1.1 Pod生命周期

Pod在整個生命周期過程中被系統定義了如下各種狀態。

狀態值

描述

Pending

API Server已經創建該Pod,且Pod內還有一個或多個容器的鏡像沒有創建,包括正在下載鏡像的過程。

Running

Pod內所有容器均已創建,且至少有一個容器處於運行狀態、正在啟動狀態或正在重啟狀態。

Succeeded

Pod內所有容器均成功執行退出,且不會重啟。

Failed

Pod內所有容器均已退出,但至少有一個容器退出為失敗狀態。

Unknown

由於某種原因無法獲取該Pod狀態,可能由於網路通訊不暢導致。

1.2 Pod重啟策略

Pod重啟策略(RestartPolicy)應用於Pod內的所有容器,並且僅在Pod所處的Node上由kubelet進行判斷和重啟操作。當某個容器異常退出或者健康檢查失敗時,kubelet將根據RestartPolicy的設置來進行相應操作。

Pod的重啟策略包括Always、OnFailure和Never,默認值為Always。

  • Always:當容器失效時,由kubelet自動重啟該容器;
  • OnFailure:當容器終止運行且退出碼不為0時,由kubelet自動重啟該容器;
  • Never:不論容器運行狀態如何,kubelet都不會重啟該容器。

kubelet重啟失效容器的時間間隔以sync-frequency乘以2n來計算,例如1/2/4/8倍等,最長延時5min,並且在成功重啟後的10min後重置該時間。

Pod的重啟策略與控制方式關聯,當前可用於管理Pod的控制器包括ReplicationController、Job、DaemonSet及直接管理kubelet管理(靜態Pod)。

不同控制器的重啟策略限制如下:

  • RC和DaemonSet:必須設置為Always,需要保證該容器持續運行;
  • Job:OnFailure或Never,確保容器執行完成後不再重啟;
  • kubelet:在Pod失效時重啟,不論將RestartPolicy設置為何值,也不會對Pod進行健康檢查。

Pod包含的容器數

Pod當前的狀態

發生事件

Pod的結果狀態

RestartPolicy=Always

RestartPolicy=OnFailure

RestartPolicy=Never

包含1個容器

Running

容器成功退出

Running

Succeeded

Succeeded

包含1個容器

Running

容器失敗退出

Running

Running

Failed

包括兩個容器

Running

1個容器失敗退出

Running

Running

Running

包括兩個容器

Running

容器被OOM殺掉

Running

Running

Failed

1.3 Pod健康檢查

對Pod的健康檢查可以通過兩類探針來檢查:LivenessProbe和ReadinessProbe。

LivenessProbe探針:用於判斷容器是否存活(running狀態),如果LivenessProbe探針探測到容器不健康,則kubelet將殺掉該容器,並根據容器的重啟策略做相應處理。若一個容器不包含LivenessProbe探針,kubelet認為該容器的LivenessProbe探針返回值用於是「Success」。

ReadineeProbe探針:用於判斷容器是否啟動完成(ready狀態)。如果ReadinessProbe探針探測到失敗,則Pod的狀態將被修改。Endpoint Controller將從Service的Endpoint中刪除包含該容器所在Pod的Eenpoint。

kubelet定期執行LivenessProbe探針來診斷容器的健康狀態,通常有以下三種方式:

  • ExecAction:在容器內執行一個命令,若返回碼為0,則表明容器健康。

示例:通過執行"cat /tmp/health"命令判斷一個容器運行是否正常。容器初始化並創建該文件,10s後刪除該文件,15s秒通過命令判斷,由於該文件已被刪除,因此判斷該容器Fail,導致kubelet殺掉該容器並重啟。

  1 [root@uk8s-m-01 study]# vi dapi-liveness.yaml    2 apiVersion: v1    3 kind: Pod    4 metadata:    5   name: dapi-liveness-pod    6   labels:    7     test: liveness-exec    8 spec:    9   containers:   10     - name: dapi-liveness   11       image: busybox   12       args:   13       - /bin/sh   14       - -c   15       - echo ok > /tmp/health; sleep 10; rm -rf /tmp/health; sleep 600   16       livenessProbe:   17         exec:   18           command:   19           - cat   20           - /tmp/health   21   22 [root@uk8s-m-01 study]# kubectl describe pod dapi-liveness-pod
  • TCPSocketAction:通過容器的IP地址和埠號執行TCP檢查,若能建立TCP連接,則表明容器健康。

示例:

  1 [root@uk8s-m-01 study]# vi dapi-tcpsocket.yaml    2 apiVersion: v1    3 kind: Pod    4 metadata:    5   name: dapi-healthcheck-tcp    6 spec:    7   containers:    8     - name: nginx    9       image: nginx   10       ports:   11       - containerPort: 80   12       livenessProbe:   13         tcpSocket:   14           port: 80   15         initialDelaySeconds: 30   16         timeoutSeconds: 1   17   18 [root@uk8s-m-01 study]# kubectl create -f dapi-tcpsocket.yaml

提示:對於每種探測方式,都需要設置如下兩個參數,其包含的含義如下:

initialDelaySeconds:啟動容器後進行首次健康檢查的等待時間,單位為s;

timeoutSeconds:健康檢查發送請求後等待響應的超時時間,單位為s,當超時發生時,kubelet會認為容器已經無法提供服務,將會重啟該容器。

二 Pod調度

Kubernetes中,Pod通常是容器的載體,一般需要通過Deployment、DaemonSet、RC、Job等對象來完成一組Pod的調度與自動控制功能。

2.1 Depolyment/RC自動調度

Deployment或RC的主要功能之一就是自動部署一個容器應用的多份副本,以及持續監控副本的數量,在集群內始終維持用戶指定的副本數量。

示例:

  1 [root@uk8s-m-01 study]# vi nginx-deployment.yaml    2 apiVersion: apps/v1beta1    3 kind: Deployment    4 metadata:    5   name: nginx-deployment-01    6 spec:    7   replicas: 3    8   template:    9     metadata:   10       labels:   11         app: nginx   12     spec:   13       containers:   14       - name: nginx   15         image: nginx:1.7.9   16         ports:   17         - containerPort: 80   18   19 [root@uk8s-m-01 study]# kubectl get deployments   20 NAME                  READY   UP-TO-DATE   AVAILABLE   AGE   21 nginx-deployment-01   3/3     3            3           30s   22 [root@uk8s-m-01 study]# kubectl get rs   23 NAME                             DESIRED   CURRENT   READY   AGE   24 nginx-deployment-01-5754944d6c   3         3         3       75s   25 [root@uk8s-m-01 study]# kubectl get pod | grep nginx   26 nginx-deployment-01-5754944d6c-hmcpg   1/1     Running     0          84s   27 nginx-deployment-01-5754944d6c-mcj8q   1/1     Running     0          84s   28 nginx-deployment-01-5754944d6c-p42mh   1/1     Running     0          84s

2.2 NodeSelector定向調度

當需要手動指定將Pod調度到特定Node上,可以通過Node的標籤(Label)和Pod的nodeSelector屬性相匹配。

# kubectl label nodes <node-name> <label-key>=<label-value>

node節點創建對應的label後,可通過在定義Pod的時候加上nodeSelector的設置實現指定的調度。

示例:

  1 [root@uk8s-m-01 study]# kubectl label nodes 172.24.9.14 speed=io    2 node/172.24.9.14 labeled    3 [root@uk8s-m-01 study]# vi nginx-master-controller.yaml    4 kind: ReplicationController    5 metadata:    6   name: nginx-master    7   labels:    8     name: nginx-master    9 spec:   10   replicas: 1   11   selector:   12     name: nginx-master   13   template:   14     metadata:   15       labels:   16         name: nginx-master   17     spec:   18       containers:   19       - name: master   20         image: nginx:1.7.9   21         ports:   22         - containerPort: 80   23       nodeSelector:   24         speed: io   25   26 [root@uk8s-m-01 study]# kubectl create -f nginx-master-controller.yaml   27 [root@uk8s-m-01 study]# kubectl get pods -o wide   28 NAME                READY   STATUS    RESTARTS    AGE    IP            NODE   29 nginx-master-7fjgj  1/1     Running   0           82s    172.24.9.71   172.24.9.14

提示:可以將集群中具有不同特點的Node貼上不同的標籤,實現在部署時就可以根據應用的需求設置NodeSelector來進行指定Node範圍的調度。

注意:若在定義Pod中指定了NodeSelector條件,但集群中不存在符合該標籤的Node,即使集群有其他可供使用的Node,Pod也無法被成功調度。

2.3 NodeAffinity親和性調度

親和性調度機制極大的擴展了Pod的調度能力,主要增強功能如下:

  1. 更具表達力,即更精細的力度控制;
  2. 可以使用軟限制、優先採用等限制方式,即調度器在無法滿足優先需求的情況下,會使用其他次條件進行滿足;
  3. 可以依據節點上正在運行的其他Pod的標籤來進行限制,而非節點本身的標籤,從而實現Pod之間的親和或互斥關係。

目前有兩種節點親和力表達:

requiredDuringSchedulingIgnoredDuringExecution:硬規則,必須滿足指定的規則,調度器才可以調度Pod至Node上(類似nodeSelector,語法不同)。

preferredDuringSchedulingIgnoredDuringExecution:軟規則,優先調度至滿足的Node的節點,但不強求,多個優先順序規則還可以設置權重值。

IgnoredDuringExecution指:如果一個Pod所在的節點在Pod運行期間標籤發生了變化,不再符合該Pod的節點親和性需求,則系統將忽略Node上Label的變化,該Pod能繼續在該節點運行。

示例:

條件1:只運行在amd64的節點上;盡量運行在ssd節點上。

  1 [root@uk8s-m-01 study]# vi nodeaffinity-pod.yaml    2 apiVersion: v1    3 kind: Pod    4 metadata:    5   name: with-node-affinity    6 spec:    7   affinity:    8     nodeAffinity:    9       requiredDuringSchedulingIgnoredDuringExecution:   10         nodeSelectorTerms:   11         - matchExpressions:   12           - key: kubernetes.io/arch   13             operator: In   14             values:   15             - amd64   16       preferredDuringSchedulingIgnoredDuringExecution:   17       - weight: 1   18         preference:   19           matchExpressions:   20           - key: disk-type   21             operator: In   22             values:   23             - ssd   24   containers:   25   - name: with-node-affinity   26     image: gcr.azk8s.cn/google_containers/pause:2.0

NodeAffinity操作語法;In、NotIn、Exists、DoesNotExist、Gt、Lt。NotIn和DoesNotExist可以實現互斥功能。

NodeAffinity規則設置注意事項:

  • 若同時定義nodeSelector和nodeAffinity,則必須兩個條件都滿足,Pod才能最終運行指定在Node上;;
  • 若nodeAffinity指定多個nodeSelectorTerms,則只需要其中一個能夠匹配成功即可;
  • 若nodeSelectorTerms中有多個matchExpressions,則一個節點必須滿足所有matchExpressions才能運行該Pod。

2.4 PodAffinity親和性調度

PodAffinity根據節點上正在運行的Pod標籤而不是Node標籤來判斷和調度,要求對節點和Pod兩個條件進行匹配。

規則描述為:若在具有標籤X的Node上運行了一個或多個符合條件Y的Pod,則Pod應該(或者不應該)運行在這個Node上。

X通常為Node節點的機架、區域等概念,Pod是屬於某個命名空間,所以條件Y表達的是一個或全部命名空間中的一個Label Selector。

Pod親和性定義與PodSpec的affinity欄位下的podAffinity欄位里,互斥性定義於同一層次的podAntiAffinity子欄位中。

舉例:

  1 [root@uk8s-m-01 study]# vi nginx-flag.yaml	#創建名為pod-flag,帶有兩個標籤的Pod    2 apiVersion: v1    3 kind: Pod    4 metadata:    5   name: pod-affinity    6 spec:    7   affinity:    8     podAffinity:    9       requiredDuringSchedulingIgnoredDuringExecution:   10       - labelSelector:   11           matchExpressions:   12           - key: security   13             operator: In   14             values:   15             - S1   16         topologyKey: kubernetes.io/hostname   17   containers:   18   - name: with-pod-affinity   19     image: gcr.azk8s.cn/google_containers/pause:2.0
  1 [root@uk8s-m-01 study]# vi nginx-affinity-in.yaml	#創建定義標籤security=S1,對應如上Pod 「Pod-flag」。    2 apiVersion: v1    3 kind: Pod    4 metadata:    5   name: pod-affinity    6 spec:    7   affinity:    8     podAffinity:    9       requiredDuringSchedulingIgnoredDuringExecution:   10       - labelSelector:   11           matchExpressions:   12           - key: security   13             operator: In   14             values:   15             - S1   16         topologyKey: kubernetes.io/hostname   17   containers:   18   - name: with-pod-affinity   19     image: gcr.azk8s.cn/google_containers/pause:2.0   20   21 [root@uk8s-m-01 study]# kubectl create -f nginx-affinity-in.yaml   22 [root@uk8s-m-01 study]# kubectl get pods -o wide

提示:由上Pod親和力可知,兩個Pod處於同一個Node上。

  1 [root@uk8s-m-01 study]# vi nginx-affinity-out.yaml	#創建不能與參照目標Pod運行在同一個Node上的調度策略    2 apiVersion: v1    3 kind: Pod    4 metadata:    5   name: anti-affinity    6 spec:    7   affinity:    8     podAffinity:    9       requiredDuringSchedulingIgnoredDuringExecution:   10       - labelSelector:   11           matchExpressions:   12           - key: security   13             operator: In   14             values:   15             - S1   16         topologyKey: failure-domain.beta.kubernetes.io/zone   17     podAntiAffinity:   18       requiredDuringSchedulingIgnoredDuringExecution:   19       - labelSelector:   20           matchExpressions:   21           - key: security   22             operator: In   23             values:   24             - nginx   25         topologyKey: kubernetes.io/hostname   26   containers:   27   - name: anti-affinity   28     image: gcr.azk8s.cn/google_containers/pause:2.0   29   30 [root@uk8s-m-01 study]# kubectl get pods -o wide	#驗證

2.5 Taints和Tolerations(污點和容忍)

Taint:使Node拒絕特定Pod運行;

Toleration:為Pod的屬性,表示Pod能容忍(運行)標註了Taint的Node。

Taint語法:$ kubectl taint node node1 key=value:NoSchedule

解釋:為node1加上一個Taint,該Taint的鍵為key,值為value,Taint的效果為NoSchedule。即除非特定聲明可以容忍此Taint,否則不會調度至node1上。

Toleration示例:

  1 tolerations:    2 - key: "key"    3   operator: "Equal"    4   value: "value"    5   effect: "NoSchedule"

  1 tolerations:    2 - key: "key"    3   operator: "Exists"    4   effect: "NoSchedule"

注意:Pod的Toleration聲明中的key和effect需要與Taint的設置保持一致,並且滿足以下條件:

  • operator的值是Exists(無須指定value);
  • operator的值是Equal並且value相等;
  • 空的key配合Exists操作符能夠匹配所有的鍵和值;
  • 空的effect匹配所有的effect。

若不指定operator,則默認值為Equal。

taint說明:系統允許在同一個Node上設置多個taint,也可以在Pod上設置多個toleration。Kubernetes調度器處理多個taint和toleration的邏輯順序:首先列出節點中所有的taint,然後忽略pod的toleration能夠匹配的部分,剩下的沒有忽略掉的taint就是對pod的效果。以下是幾種特殊情況:

若剩餘的taint中存在effect=NoSchedule,則調度器不會把該Pod調度到這一節點上;

若剩餘的taint中沒有NoSchedule效果,但有PreferNoSchedule效果,則調度器會嘗試不把這個Pod指派到此節點;

若剩餘taint的效果有NoSchedule,並且這個Pod已經在該節點上運行,則會被驅逐,若沒有在該節點上運行,也不會再被調度到該節點上。

示例:

  1 $ kubectl taint node node1 key=value1:NoSchedule    2 $ kubectl taint node node1 key=value1:NoExecute    3 $ kubectl taint node node1 key=value2:NoSchedule    4 tolerations:    5 - key: "key1"    6   operator: "Equal"    7   value: "value"    8   effect: "NoSchedule"    9 tolerations:   10 - key: "key1"   11   operator: "Equal"   12   value: "value1"   13   effect: "NoExecute"

釋義:此Pod聲明了兩個容忍,且能匹配Node1的taint,但是由於沒有能匹配第三個taint的toleration,因此此Pod依舊不能調度至此Node。若該Pod已經在node1上運行了,那麼在運行時設置了第3個taint,它還能繼續在node1上運行,這是因為Pod可以容忍前兩個taint。

通常,若node加上effect=NoExecute的taint,那麼該Node上正在運行的所有無對應toleration的Pod都會被立刻驅逐,而具有相應toleration的Pod則永遠不會被驅逐。同時,系統可以給具有NoExecute效果的toleration加入一個可選的tolerationSeconds欄位,表明Pod可以在taint添加到Node之後還能在此Node運行多久。

  1 tolerations:    2 - key: "key1"    3   operator: "Equal"    4   value: "value"    5   effect: "NoSchedule"    6   tolerationSeconds: 3600

釋義:若Pod正在運行,所在節點被加入一個匹配的taint,則這個pod會持續在該節點運行3600s後被驅逐。若在此期限內,taint被移除,則不會觸發驅逐事件。

Taints和Tolerations常用場景:

  • 獨佔節點:

給特定的節點運行特定應用。

$ kubectl taint nodes 【nodename】 dedicated=groupName:NoSchedule

同時在Pod中設置對應的toleration配合,帶有合適toleration的Pod允許同時使用其他節點一樣使用有taint的節點。

  • 具有特殊硬體設備的節點

集群中部分特殊硬體(如安裝了GPU),則可以把不需要佔用GPU的Pod禁止在此Node上調度。

  1 $ kubectl taint nodes 【nodename】 special=true:NoSchedule    2 $ kubectl taint nodes 【nodename】 special=true:PreferNoSchedule
  • 定義Pod驅逐行為

NoExecute的taint對節點上正在運行的Pod有以下影響:

  1. 沒有設置toleration的pod會被立刻驅逐;
  2. 配置了對應toleration的pod,若沒有為tolerationSeconds賦值,則會一直保留在此節點中;
  3. 配置了對應toleration的pod,且為tolerationSeconds賦值,則在指定時間後驅逐。

2.6 DaemonSet

DaemonSet是在每個Node上調度一個Pod的資源對象,用於管理集群中每個Node僅運行一份Pod的副本實例。

常見場景:

在每個Node上運行一個GlusterFS存儲的Daemon進程;

在每個Node上運行一個日誌採集程式,例如Fluentd;

在每個Node上運行一個性能監控程式,採集該Node的運行性能數據,例如Prometheus。

示例:

  1 [root@uk8s-m-01 study]# vi fluentd-ds.yaml    2 apiVersion: extensions/v1beta1    3 kind: DaemonSet    4 metadata:    5   name: fluentd-cloud-logging    6   namespace: kube-system    7   labels:    8     k8s-app: fluentd-cloud-logging    9 spec:   10   template:   11     metadata:   12       namespace: kube-system   13       labels:   14         k8s-app: fluentd-cloud-logging   15     spec:   16       containers:   17       - name: fluentd-cloud-logging   18         image: gcr.azk8s.cn/google_containers/fluentd-elasticsearch:1.17   19         resources:   20           limits:   21             cpu: 100m   22             memory: 200Mi   23         env:   24         - name: FLUENTD_ARGS   25           value: -q   26         volumeMounts:   27         - name: varlog   28           mountPath: /var/log   29           readOnly: false   30         - name: containers   31           mountPath: /var/lib/docker/containers   32           readOnly: false   33       volumes:   34       - name: containers   35         hostPath:   36           path: /var/lib/docker/containers   37       - name: varlog   38         hostPath:   39           path: /var/log

2.7 Job批處理調度

通過Kubernetes Job資源對象可以定義並啟動一個批處理任務,批處理任務通過並行(或者串列)啟動多個計算進程去處理一批工作項。根據批處理方式不同,批處理任務可以分為如下幾種模式:

Job Template Expansion模式:一個Job對象對應一個待處理的Work item,有幾個work item就產生幾個獨立的Job。通常適合Work item數量少、每個Work item要處理的數據量比較大的場景。

Queue with Pod Per Work Item模式:採用一個任務隊列存放Work item,一個Job對象作為消費者去完成這些Work item。此模式下,Job會啟動N個Pod,每個Pod都對應一個Work item。

Queue with Variable Pod Count模式:採用一個任務隊列存放Work item,一個Job對象作為消費者去完成這些Work item,但此模式下Job啟動的數量是可變的。

Kubernetes將Job氛圍以下三類:

  • Non-parallel Jobs

通常一個Job只啟動一個Pod,除非Pod異常,才會重啟該Pod,一旦此Pod正常結束,Job將結束。

  • Parallel Jobs with a fixed completion count

並行Job會啟動多個Pod,此時需要設定Job的.spec.completions參數為一個正數,當正常結束的Pod數量達至此參數設定的值後,Job結束。同時.spec.parallelism參數用來控制並行度,即同時啟動幾個Job來處理Work Item。

  • Parallel Jobs with a work queue

任務隊列方式的並行Job需要一個獨立的Queue,Work Item都在一個Queue中存放,不能設置Job的.spec.completions參數,此時Job具有以下特性:

  1. 每個Pod都能獨立判斷和決定是否還有任務項需要處理;
  2. 如果某個Pod正常結束,則Job不會再啟動新的Pod;
  3. 如果一個Pod成功結束,則此時應該不存在其他Pod還在工作的情況。它們應該都處於即將結束、退出的狀態;
  4. 如果所有Pod都結束了,且至少有一個Pod成功結束,則整個Jod成功結束。

2.8 Cronjob定時任務

表達式:Minutes Hours DayofMonth Month DayofWeek Year

Minutes:可出現","、"_"、"*"、"/",有效範圍為0~59的整數;

Hours:出現","、"_"、"*"、"/",有效範圍為0~23的整數;

DayofMonth:出現","、"_"、"*"、"/"、"L"、"W"、"C",有效範圍為0~31的整數;

Month:可出現","、"_"、"*"、"/",有效範圍為1~12的整數或JAN~DEC;

DayofWeek:出現","、"_"、"*"、"/"、"L"、"W"、"C"、"#",有效範圍為1~7的整數或SUN~SAT;

*: 表示匹配該域的任意值, 假如在Minutes域使用「*」, 則表示每分鐘都會觸發事件。

/: 表示從起始時間開始觸發, 然後每隔固定時間觸發一次,例如在Minutes域設置為5/20, 則意味著第1次觸發在第5min時, 接下來每20min觸發一次, 將在第25min、 第45min等時刻分別觸發。

示例:*/1 * * * * #每隔1min執行一次任務

  1 [root@uk8s-m-01 study]# vi cron.yaml    2 apiVersion: batch/v2alpha1    3 kind: CronJob    4 metadata:    5   name: hello    6 spec:    7   schedule: "*/1 * * * *"    8   jobTemplate:    9     spec:   10       template:   11         spec:   12           containers:   13           - name: hello   14             image: busybox   15             args:   16             - /bin/sh   17             - -c   18             - date; echo Hello from the Kubernetes cluster   19           restartPolicy: OnFailure
  1 [root@master study]# kubectl create -f cron.yaml    2 [root@master study]# kubectl get cronjob hello    3 NAME    SCHEDULE      SUSPEND   ACTIVE   LAST SCHEDULE   AGE    4 hello   */1 * * * *   False     0        <none>          29s    5 [root@master study]# kubectl get pods    6 NAME                     READY   STATUS      RESTARTS   AGE    7 hello-1573378080-zvvm5   0/1     Completed   0          68s    8 hello-1573378140-9pmwz   0/1     Completed   0          8s    9 [root@node1 ~]# docker logs c7					#node節點查看日誌   10 Sun Nov 10 09:31:13 UTC 2019   11 Hello from the Kubernetes cluster   12 [root@master study]# kubectl get jobs				#查看任務   13 NAME               COMPLETIONS   DURATION   AGE   14 hello-1573378500   1/1           8s         3m7s   15 hello-1573378560   1/1           4s         2m7s   16 hello-1573378620   1/1           6s         67s   17 hello-1573378680   1/1           4s         7s   18 [root@master study]# kubectl get pods -o wide | grep hello-1573378680	#以job任務查看對應的pod   19 [root@master study]# kubectl delete cj hello			#刪除cronjob

2.9 初始化容器

在很多應用場景中, 應用在啟動之前都需要進行如下初始化操作。

  • 等待其他關聯組件正確運行( 例如資料庫或某個後台服務) 。
  • 基於環境變數或配置模板生成配置文件。
  • 從遠程資料庫獲取本地所需配置, 或者將自身註冊到某個中央資料庫中。
  • 下載相關依賴包, 或者對系統進行一些預配置操作。

示例:以Nginx應用為例, 在啟動Nginx之前, 通過初始化容器busybox為Nginx創建一個index.html主頁文件。同時init container和Nginx設置了一個共享的Volume, 以供Nginx訪問init container設置的index.html文件。

  1 [root@uk8s-m-01 study]# vi nginx-init-containers.yaml    2 apiVersion: v1    3 kind: Pod    4 metadata:    5   name: nginx    6   annotations:    7 spec:    8   initContainers:    9   - name: install   10     image: busybox   11     command:   12     - wget   13     - "-O"   14     - "/work-dir/index.html"   15     - http://kubernetes.io   16     volumeMounts:   17     - name: workdir   18       mountPath: "/work-dir"   19   containers:   20   - name: nginx   21     image: nginx:1.7.9   22     ports:   23     - containerPort: 80   24     volumeMounts:   25     - name: workdir   26       mountPath: /usr/share/nginx/html   27   dnsPolicy: Default   28   volumes:   29   - name: workdir   30     emptyDir: {}
  1 [root@uk8s-m-01 study]# kubectl get pods    2 NAME    READY   STATUS     RESTARTS   AGE    3 nginx   0/1     Init:0/1   0          2s    4 [root@uk8s-m-01 study]# kubectl get pods    5 NAME    READY   STATUS    RESTARTS   AGE    6 nginx   1/1     Running   0          13s    7 [root@uk8s-m-01 study]# kubectl describe pod nginx		#查看事件可知會先創建init容器,名為install

init容器與應用容器的區別如下。

(1) init container的運行方式與應用容器不同, 它們必須先於應用容器執行完成, 當設置了多個init container時, 將按順序逐個運行, 並且只有前一個init container運行成功後才能運行後一個init container。 當所有init container都成功運行後, Kubernetes才會初始化Pod的各種資訊, 並開始創建和運行應用容器。

(2) 在init container的定義中也可以設置資源限制、 Volume的使用和安全策略, 等等。 但資源限制的設置與應用容器略有不同。

  • 如果多個init container都定義了資源請求/資源限制, 則取最大的值作為所有init container的資源請求值/資源限制值。
  • Pod的有效(effective) 資源請求值/資源限制值取以下二者中的較大值。
    • 所有應用容器的資源請求值/資源限制值之和。
    • init container的有效資源請求值/資源限制值。
  • 調度演算法將基於Pod的有效資源請求值/資源限制值進行計算,即init container可以為初始化操作預留系統資源, 即使後續應用容器無須使用這些資源。
  • Pod的有效QoS等級適用於init container和應用容器。
  • 資源配額和限制將根據Pod的有效資源請求值/資源限制值計算生效。
  • Pod級別的cgroup將基於Pod的有效資源請求/限制, 與調度機制

一致。

(3) init container不能設置readinessProbe探針, 因為必須在它們成功運行後才能繼續運行在Pod中定義的普通容器。在Pod重新啟動時, init container將會重新運行, 常見的Pod重啟場景如下。

  • init container的鏡像被更新時, init container將會重新運行, 導致Pod重啟。 僅更新應用容器的鏡像只會使得應用容器被重啟。
  • Pod的infrastructure容器更新時, Pod將會重啟。
  • 若Pod中的所有應用容器都終止了, 並且RestartPolicy=Always, 則Pod會重啟。