Pod對象的聲明周期(Pod的相位、創建過程、重要行為、探測、重啟策略、終止過程) Pod 對象自從其創建開始至其終止退出的時間範圍稱為其生命周期。在這段時間中,Pod 會處於多種不同的狀態,並執行一些操作;其中,創建主容器(main container)為必須的操作,其他科選的操作還包括進行初始化 ...
Pod對象的聲明周期(Pod的相位、創建過程、重要行為、探測、重啟策略、終止過程)
Pod 對象自從其創建開始至其終止退出的時間範圍稱為其生命周期。在這段時間中,Pod 會處於多種不同的狀態,並執行一些操作;其中,創建主容器(main container)為必須的操作,其他科選的操作還包括進行初始化容器(init container)、容器啟動後鉤子(post start hook)、容器的存活性探測(liveness probe)、就緒型探測(readiness probe)以及容器終止前鉤子(pre stop hook)等,這些操作是否執行則取決於 Pod 的定義。
一、Pod 的相位
無論是用戶手動創建,還是通過 Deployment 等控制器創建,Pod 對象總是應該處於其生命進程中以下幾個相位(phase)之一:
-
- pending:API Server 創建了 Pod 資源對象並已存入 etcd 中,但是它尚未被調度完成,或者仍處於從倉庫下載鏡像的過程中。
- Running:Pod 已經被調度至某節點,並且所有容器都已經被 kubelet 創建完成。
- Succeeded:Pod 中的所有容器都已經成功終止並且不會被重啟。
- Failed:所有容器都已經終止,但至少有一個容器終止失敗,即容器返回了非 0 值的退出狀態或已經被系統終止。
- Unkown:API Server 無法正常獲取到 Pod 對象的狀態信息,通常是由於其無法與所在工作節點的 kubelet 通信所致。
Pod 相位是在其聲明周期的巨集觀概述,而非對容器或 Pod 對象的綜合彙總,而且相位的數量和含義被嚴格界定,它僅包含上面列舉的相位值。
二、Pod 的創建過程
Pod 是 Kubernetes 的基礎單元,理解它的創建過程對於瞭解系統運作有很大幫助。
1)用戶通過 kubectl 或其他 API 客戶端提交 Pod Spec 給 API Server。
2)API Server 嘗試著將 Pod 對象的相關信息存入 etcd 中,待寫入操作執行完成,API Server 即會返回確認信息至客戶端。
3)API Server 返回 etcd 中的狀態變化。
4)所有的 Kubernetes 組件均使用 "watch" 機制來跟蹤檢查 API Server 上的相關的變動。
5)kube-scheduler(調度器)通過其 "watch" 覺察到 API Server 創建了新的 Pod 對象但尚未綁定至任何工作節點。
6)kube-scheduler 為 Pod 對象挑選一個工作節點將結果更新至 API Server。
7)調度結果信息由 API Server 更新至 etcd 存儲系統,而且 API Server 也開始反映此 Pod 對象的調度結果。
8)Pod 被調度到的目標工作節點上的 kubelet 嘗試在當前節點上調用 Docker 啟動容器,並將容器的結果狀態送至 API Server。
9)API Server 將 Pod 狀態信息存入 etcd 系統中。
10)在 etcd 確認寫入操作成功完成後,API Server 將確認信息發送至相關的 kubelet,事件將通過它被接受。
三、Pod 生命周期中的重要行為
除了創建應用容器(主容器及其輔助容器)之外,用戶還可以為 Pod 對象定義其生命周期中的多種行為,如初始化容器、存活性探測及就緒性探測等。
1、初始化容器
初始化容器(init container)即應用程式的主容器啟動之前要運行的容器,常用於為主容器執行一些預置操作,它們具有兩種典型特征:
1)初始化容器必須運行完成執直至結束,若某初始化容器運行失敗,那麼 Kubernetes 需要重啟它直至成功完成。
2)每個初始化容器都必須按定義的順序串列運行。
有不少場景都需要在應用容器啟動之前進行部分初始化操作,例如,等待其他關聯組件服務可用、基於環境變數或配置模版為應用程式生成配置文件、從配置中心獲取配置等。初始化容器的典型應用需求具體包括如下幾種:
用於運行特定的工具程式,處於安全的個方面的原因,這些程式不適於包含在主容器鏡像中。
2)提供主容器鏡像中不具備的工具程式或自定義代碼。
3)為容器鏡像的構建和部署人員提供了分離、獨立工作的途徑,使得他們不必協同起來製作單個鏡像文件。
4)初始化容器和主容器處於不同的文件系統視圖中,因此可以分別安全地使用敏感數據,例如 Secrets 資源。
5)初始化容器要先於應用容器串列啟動並運行完成,因此可用於延後應用容器的啟動直至其依賴的條件得到滿足。
Pod 資源的 "spec.initContainers" 欄位以列表的形式定義可用的初始化容器,其嵌套可用欄位類型於 "spec.containers"。下麵的資源清單僅是一個初始化容器的使用示例參考:
kind: Pod
apiVersion: v1
metadata:
name: redis-ha-haproxy-64444759d4-wf45w
generateName: redis-ha-haproxy-64444759d4-
namespace: kubesphere-system
labels:
app: redis-ha-haproxy
pod-template-hash: 64444759d4
release: ks-redis
annotations:
checksum/config: 46138f8b2005948188bc12c93b08a9c6460354af2db98eaa2158bcf1717e82de
cni.projectcalico.org/podIP: 10.233.105.1/32
cni.projectcalico.org/podIPs: 10.233.105.1/32
prometheus.io/path: /metrics
prometheus.io/port: '9101'
prometheus.io/scrape: 'true'
spec:
volumes:
- name: config-volume
configMap:
name: redis-ha-configmap
defaultMode: 420
- name: shared-socket
emptyDir: {}
- name: data
emptyDir: {}
- name: redis-ha-haproxy-token-5lqwd
secret:
secretName: redis-ha-haproxy-token-5lqwd
defaultMode: 420
initContainers:
- name: config-init
image: 'registry.cn-beijing.aliyuncs.com/kubesphereio/haproxy:2.0.4'
command:
- sh
args:
- /readonly/haproxy_init.sh
resources: {}
volumeMounts:
- name: config-volume
readOnly: true
mountPath: /readonly
- name: data
mountPath: /data
- name: redis-ha-haproxy-token-5lqwd
readOnly: true
mountPath: /var/run/secrets/kubernetes.io/serviceaccount
terminationMessagePath: /dev/termination-log
terminationMessagePolicy: File
imagePullPolicy: IfNotPresent
containers:
- name: haproxy
image: 'registry.cn-beijing.aliyuncs.com/kubesphereio/haproxy:2.0.4'
ports:
- name: redis
containerPort: 6379
protocol: TCP
resources: {}
volumeMounts:
- name: data
mountPath: /usr/local/etc/haproxy
- name: shared-socket
mountPath: /run/haproxy
- name: redis-ha-haproxy-token-5lqwd
readOnly: true
mountPath: /var/run/secrets/kubernetes.io/serviceaccount
livenessProbe:
httpGet:
path: /healthz
port: 8888
scheme: HTTP
initialDelaySeconds: 5
timeoutSeconds: 1
periodSeconds: 3
successThreshold: 1
failureThreshold: 3
terminationMessagePath: /dev/termination-log
terminationMessagePolicy: File
imagePullPolicy: IfNotPresent
restartPolicy: Always
terminationGracePeriodSeconds: 30
dnsPolicy: ClusterFirst
serviceAccountName: redis-ha-haproxy
serviceAccount: redis-ha-haproxy
nodeName: mh-k8s-master-prd-243.24
securityContext:
runAsUser: 1000
runAsNonRoot: true
fsGroup: 1000
affinity:
nodeAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 100
preference:
matchExpressions:
- key: node-role.kubernetes.io/master
operator: In
values:
- ''
podAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchLabels:
app: redis-ha-haproxy
release: ks-redis
topologyKey: kubernetes.io/hostname
schedulerName: default-scheduler
tolerations:
- key: node-role.kubernetes.io/master
effect: NoSchedule
- key: CriticalAddonsOnly
operator: Exists
- key: node.kubernetes.io/not-ready
operator: Exists
effect: NoExecute
tolerationSeconds: 60
- key: node.kubernetes.io/unreachable
operator: Exists
effect: NoExecute
tolerationSeconds: 60
priority: 0
enableServiceLinks: true
2、聲明周期鉤子函數
生命周期鉤子函數(lifcycle hook)是編程語言(如 Angular)中常用的生命周期管理的組件,它實現了程式運行周期中的關鍵時刻的可見性,並賦予用戶為此採取某種行動的能力。類似地,容器聲明周期鉤子使它能夠感知其自身生命周期管理中的事件,併在相應的時刻到來時運行由用戶指定的處理程式代碼。Kubernetes 為容器提供了兩種生命周期的鉤子。
1)postStart:於容器創建完成之後立即運行的鉤子處理器(handler),不過 Kubernetes 無法確保它一定會於容器中的 ENTRYPOINT 之前運行。
2)preStop:於容器終止操作之前立即運行的鉤子處理器,它以同步的方式調用,因此在其完成之前會阻塞刪除容器的操作的調用。
鉤子處理器的實現方式有 "Exec" 和 "HTTP" 兩種,前一種在鉤子事件觸發時直接在當前容器中運行由用戶定義的命令,後一種則是在當前容器中向某 URL 發起 HTTP請求。
3、容器探測
容器探測(container probe)是 Pod 對象生命周期中的一項重要的日常任務,它是 kubelet 對容器周期性執行的健康狀態診斷,診斷操作由容器的處理器(handler)進行定義。
Kubernetes 支持三種處理器用於 Pod 探測。
-
- ExecAction:在容器中執行一個命令,並根據其返回的狀態碼進行診斷的操作稱為 Exec 探測,狀態碼為 0 表示成功,否則即為不健康狀態。
- TCPSocketAction:通過與容器的某 TCP 埠嘗試建立連接進行診斷,埠能夠成功打開即為正常,否則為不健康狀態。
- HTTPGetAction:通過向容器 IP 地址的某指定埠的指定 path 發起 HTTP GET 請求進行診斷,響應碼為 2xx 或 3xx 時即為成功,否則為失敗。
任何一種探測方式都可能存在三種結果:"Success"(成功)、"Failure"(失敗)或 "Unknown"(未知),只有第一種結果表示成功通過檢測。
存活性檢測:
用於判定容器是否處於 "運行"(Running)狀態;一旦此類檢測未通過,kubelet 將殺死容器並根據其 restartPolicy 決定是否將其重啟;未定義存活性檢測的容器的預設狀態為 "Success"。
就緒性檢測:
用於判斷容器是否準備就緒並可對外提供服務;未通過檢測的容器意味著其尚未準備就緒,端點控制器(如 Service 對象)會將其 IP 從所有匹配到此 Pod 對象的 Service 對象的端點列表中移除;檢測通過之後,會再次將其 IP 添加至端點列表中。
四、容器調度重啟策略
容器程式發生崩潰或容器申請超過限制的資源等原因都可能會導致 Pod 對象的終止,此時是否應該重建該 Pod 對象則取決於其重啟策略(restartPolicy)屬性的定義。
1)Always:但凡 Pod 對象終止就將其重啟,此為預設設定。
2)OnFailure:僅在 Pod 對象出現錯誤時方纔能將其重啟。
3)Nerver:從不重啟
提示:
restartPolicy 適用於 Pod 對象中的所有容器,而且它僅用於控制在同一節點上重新啟動 Pod 對象的相關容器。
首次需要重啟的容器,將在其需要時立即進行重啟,隨後再次需要重啟的操作由 kubelet 延遲一段時間後進行,且反覆的重啟操作的延遲時長依次為 10秒、20秒、40秒、80秒、160秒 和 300秒,300秒是最大延遲時長。
Pod 一旦綁定到一個節點,Pod對象將永遠不會被重新綁定到另一個點,它要麼被重啟,要麼終止,直到節點發生故障或被刪除。
五、Pod 的終止過程
Pod 對象代表了在 Kubernetes 集群節點上運行的進程,它可能曾用於處理生產數據或向用戶提供服務等,但是,當 Pod 本身不再具有存在的價值時,如何將其優雅地終止就顯得尤為重要了,而用戶也需要能夠在正常提交刪除操作後可以獲知其如何開始終止並最終完成。
操作中,當用戶提交刪除請求後,系統就會進行強制刪除操作的寬限期倒計時,並將 TERM 信息發送給 Pod 對象的每個容器中的主進程。寬限期倒計時結束後,這些進程將啊收到強制終止的 KILL 信號,Pod 對象隨即也將由 API Server 刪除。如果在等待進程終止的過程中,kubelet 或容器管理器發生了重啟,那麼終止操作會重新獲得一個滿額的刪除寬限期並重新進行刪除操作。·
一個典型的 Pod 對象終止流程具體如下:
1)用戶發送刪除 Pod 對象的命令。
2)API 伺服器中的 Pod 對象會隨著時間的推移而更新,在寬限期內(預設 30秒),Pod 視為 "dead"。
3)將 Pod 標記為 "Terminating" 狀態。
4)(與第 3 步同時運行)kubelet 在監控到 Pod 對象轉為 "Terminating" 狀態的同時啟動 Pod 關閉過程。
5)(與第 3 步同時運行)端點控制器監控到 Pod 對象的關閉行為時將其從所有匹配到此端點的 Service 資源的端點列表中移除。
6)如果當前 Pod 對象定義了 preStop 鉤子處理器,則在其標記為 "terminating" 後即會以同步的方式啟動執行;如若寬限期結束後,preStop 仍未執行結束,則第 2 步會被重新執行並額外獲取一個時長為 2 秒 的小寬限期。
7)Pod 對象中的容器進程收到 TERM 信號。
8)寬限期結束後,若存在任何一個仍在運行的進程,那麼 Pod 對象即會收到 SIGKILL 信號。
9)Kubelet 請求 API Server 將此 Pod 資源的寬限期設置為 0 從而完成刪除操作,它變得對用戶不再可見。
預設情況下,所有刪除操作的寬限期都是 30秒,不過, kubectl delete 命令可以使用 "--grace-period=<seconds>"選項自定義其時長,若使用 0 值則表示直接強制刪除指定的資源,不過,此時需要同時為命令使用 "--force" 選項。