概述#
走完三兄弟的實戰篇後,可以發現 Deployment、Service 都是以 Pod 為核心圍繞展開。Pod 通常會被視為一個服務的最小單位,內部可能包含一個或多個容器,能不能順利提供服務全靠它。要讓 Pod 在預期狀態下健康運作,就必須對它的 Pod 生命週期(Pod Lifecycle)有清楚的掌握,並善用重啟策略、生命週期鉤子與各類探針。
Pod 生命週期的階段#
完整的 Pod 生命週期不只主容器(main container),還包含初始化容器(init container)、生命週期鉤子(postStart / preStop hook)以及健康檢查(liveness / readiness probe)。在介紹各個環節前,先看 Pod 最頂層的狀態定義,也就是排錯時第一眼會看的訊息。
Pod Phase(階段)#
執行 kubectl get pods 時看到的 STATUS 欄位就是 Phase。可能值固定為下列幾種:
- Pending:Pod 已被提交至叢集,但尚未被調度到節點,或是映像檔還在下載中。
- Running:Pod 已綁定節點且容器已建立,至少一個容器正在執行、啟動或重啟。
- Succeeded:所有容器都成功終止,並且不會再被重啟。
- Failed:所有容器都已終止,且至少有一個容器以非零狀態結束或被系統終止。
- Unknown:因節點通訊失敗等原因,無法取得 Pod 狀態。
重啟策略(restartPolicy)#
可以透過 spec.template.spec.restartPolicy 為 Pod 中所有容器設定重啟策略,預設為 Always,可選值為:
Always:容器終止就重啟,預設。OnFailure:只有錯誤結束才重啟。Never:永不重啟。
restartPolicy 由 kubelet 在同一節點上重新啟動容器,重啟之間採指數退避(10s、20s、40s…),上限為 5 分鐘,連續成功執行 10 分鐘後重置。不同控制器對重啟策略有限制:
- Job:通常用於一次性批次任務,只能設成
OnFailure或Never。 - Replication Controller、ReplicaSet、Deployment:希望 Pod 一直運作,只能是
Always。 - DaemonSet:每個節點都要有一個 Pod,自然也是
Always。
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-app
labels:
app: my-app
spec:
serviceName: my-app
replicas: 1
selector:
matchLabels:
app: my-app
template:
metadata:
labels:
app: my-app
spec:
restartPolicy: Always
containers:
- name: my-app
image: myregistry:443/mydomain/my-app
imagePullPolicy: Always初始化容器(Init Container)#
Init Container 是 Pod 中最早被執行的容器,負責在主容器啟動前完成準備工作。一個 Pod 可以有多個 Init Container,會依宣告順序依序執行。常見應用場景:
- 等待依賴的服務就緒:例如主程式要等資料庫可用,可在 Init Container 中輪詢資料庫,確認就緒後再退出。
- 預先生成設定或共享資料:例如下載叢集成員清單、產生靜態檔案,再透過 Volume 共享給主容器。
下面範例利用 Init Container 預先抓取首頁內容並掛載到 Nginx 主容器:
apiVersion: v1
kind: Pod
metadata:
name: init-demo
spec:
volumes:
- name: workdir
emptyDir: {}
initContainers:
- name: install
image: busybox
command:
- wget
- "-O"
- "/work-dir/index.html"
- http://www.baidu.com
volumeMounts:
- name: workdir
mountPath: "/work-dir"
containers:
- name: nginx
image: nginx
ports:
- containerPort: 80
volumeMounts:
- name: workdir
mountPath: /usr/share/nginx/html生命週期鉤子(Lifecycle Hook)#
Init Container 結束後,主容器啟動的同時 kubelet 也會替我們發起兩個鉤子:
postStart:容器建立後立即執行,常用於資源部署或環境初始化。需注意它不保證在 ENTRYPOINT 之前運作;如果處理太久,容器將無法進入 Running。preStop:容器終止前執行,是同步阻塞的,常用於優雅關閉與通知其他系統。鉤子卡住時 Pod 會停留在 Running,永遠不會進入 Failed。
apiVersion: v1
kind: Pod
metadata:
name: lifecycle-demo
spec:
containers:
- name: lifecycle-demo-container
image: nginx
lifecycle:
postStart:
exec:
command:
[
"/bin/sh",
"-c",
"echo Hello from the postStart handler > /usr/share/message",
]
preStop:
exec:
command:
[
"/bin/sh",
"-c",
"nginx -s quit; while killall -0 nginx; do sleep 1; done",
]健康檢查(Health Check)#
主容器運作期間,能影響 Pod 狀態最關鍵的元素就是探針。Kubernetes 透過探針自我檢測並修復,避免流量被導入不健康的 Pod。
四種探測處理器:
- Exec:在容器內執行命令,回傳
0視為成功。 - TCPSocket:嘗試連線指定 TCP 端口,能連上即成功。
- HTTPGet:發起 HTTP GET 請求,狀態碼介於 200–399 視為成功。
- gRPC:自 v1.24 起支援,使用時需特別指定 port。
kubelet 可以執行三種探測:
- 存活探針(Liveness Probe):判斷容器是否正常運作,失敗時 kubelet 會終止容器並依重啟策略處理。不設定預設為
Success。 - 就緒探針(Readiness Probe):判斷容器是否準備好對外服務,失敗時 Endpoint Controller 會把該 Pod IP 從 Service 的 Endpoint 列表中移除。不設定預設為
Success。 - 啟動探針(Startup Probe):判斷應用是否已啟動完成。Startup Probe 啟用期間其他探針會被停用,等它成功後才接管。失敗時 kubelet 會終止容器。不設定預設為
Success。
apiVersion: v1
kind: Pod
metadata:
name: goproxy
labels:
app: goproxy
spec:
containers:
- name: goproxy
image: k8s.gcr.io/goproxy:0.1
ports:
- containerPort: 8080
readinessProbe:
tcpSocket:
port: 8080
initialDelaySeconds: 5
periodSeconds: 10
livenessProbe:
tcpSocket:
port: 8080
initialDelaySeconds: 15
periodSeconds: 20小結#
無論是學前後端框架還是基礎設施,「生命週期」都是反覆出現的關鍵字。理解 Pod 從建立、初始化、健康檢查到關閉的每個段落,才能在對的時機做對的事,把 Kubernetes 平台真正的彈性發揮出來。
原文出處#
- GitHub:https://github.com/MikeHsu0618/2022-ithelp/tree/main/Day10
- iThome:https://ithelp.ithome.com.tw/articles/10289034