掌握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的調度能力,主要增強功能如下:
- 更具表達力,即更精細的力度控制;
- 可以使用軟限制、優先採用等限制方式,即調度器在無法滿足優先需求的情況下,會使用其他次條件進行滿足;
- 可以依據節點上正在運行的其他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有以下影響:
- 沒有設置toleration的pod會被立刻驅逐;
- 配置了對應toleration的pod,若沒有為tolerationSeconds賦值,則會一直保留在此節點中;
- 配置了對應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具有以下特性:
- 每個Pod都能獨立判斷和決定是否還有任務項需要處理;
- 如果某個Pod正常結束,則Job不會再啟動新的Pod;
- 如果一個Pod成功結束,則此時應該不存在其他Pod還在工作的情況。它們應該都處於即將結束、退出的狀態;
- 如果所有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會重啟。