跳至主要内容

Advanced - Pod Lifecycle

在 Kubernetes 中,Pod 是最小的可部署單位,它代表一組容器的集合。 Pod 的生命週期包含多個階段,每個階段都反映了 Pod 的狀態和行為。 以下將介紹 Pod 的生命週期、主要的容器類型以及相關的探針(Probes)。


Pod Lifecycle

pod_lifecycle_1

pod_lifecycle_2

Pod 的生命週期中有以下重要的部分:

  1. Init Container (初始化容器):
    • Init Container 是在 Main Container 啟動之前執行的特殊容器,負責完成初始化任務。
    • 這些任務包括檢查條件是否滿足、準備必要的資源(如配置文件或數據初始化)。
    • Init Container 必須執行成功,才能啟動後續的 Main Container。
  2. Main Container (主容器):
    • Main Container 是 Pod 的核心,執行應用程序的主要工作負載。
    • Pod 通常至少包含一個 Main Container,負責提供主要的服務或執行任務。
  3. Post Start / Pre Stop Hook (生命週期鉤):
    • Kubernetes 提供了容器級別的鉤子,用於在容器啟動後或終止前執行一些任務。
    • Post Start Hook:
      • 在容器啟動後立即執行,用於執行初始化操作。
    • Pre Stop Hook:
      • 在容器終止前執行,用於清理資源或執行優雅關閉操作。
  4. Liveness / Readiness Probe (健康檢查機制):
    • 探針是用於監控容器健康狀態的機制,確保應用穩定性和高可用性。
    • Liveness Probe
      • 用於檢查容器是否仍然存活。
      • 如果檢查失敗,Kubernetes 會自動重啟該容器。
    • Readiness Probe
      • 用於檢查容器是否準備好接受流量。
      • 如果檢查失敗,Kubernetes 會從該容器的服務端點中移除。

Pod Phase (階段)

pod_phase

Pod 可以分為以下主要階段:

  1. Pending:
    • 當 Pod 被創建後,進入 Pending 狀態。
    • 在這個階段,Kubernetes 正在尋找適合的節點(Node)來調度 Pod,並拉取所需的容器映像。
  2. Running:
    • 當 Pod 已被調度到某個節點,且所有的容器都成功啟動時,Pod 進入 Running 狀態。
    • 此時,Pod 開始執行其定義的工作負載。
  3. Succeeded:
    • 當 Pod 中所有的容器都正常執行完畢並成功退出,Pod 進入 Succeeded 狀態。
    • 這通常發生於執行一次性任務的 Pod,例如批次作業。
  4. Failed:
    • 如果 Pod 中任何容器異常退出且未被重啟策略恢復,Pod 進入 Failed 狀態。
  5. Unknown:
    • 當 Kubernetes 無法與執行 Pod 的節點通訊時,Pod 進入 Unknown 狀態。

Restart Policies

Pod 支援三種重啟策略:

  • Always: 無論退出狀態如何,總是重啟容器(預設值)。
  • OnFailure: 只有在容器異常退出時才重啟。
  • Never: 容器退出後不重啟。

restartPolicy 僅適用於 kubelet 在同一節點上重新啟動容器。 Kubelet 將根據指數增加的延遲(10s, 20s, 40s)重新啟動不健康的容器,延遲上限為 5 分鐘,並在容器成功執行 10 分鐘後重置延遲。

控制器與重啟策略

  • Job:
    • 用於一次性任務,例如批量計算。
    • 任務結束後,Pod 會被此類控制器清除。
    • 支援的重啟策略為 OnFailureNever
  • Replication Controller / ReplicaSet / Deployment:
    • 這些控制器旨在確保 Pod 持續運行。
    • 僅支援 Always 作為重啟策略。
  • DaemonSet:
    • 在每個節點上只會運行一個 Pod。
    • 重啟策略必須是 Always

範例

就像我們之前建立 Deployment 一樣,主要是為了確保 Pod 持續運行,所以重啟策略設定為 Always。

always_deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: v1-deployment
labels:
type: demo-v1
spec:
replicas: 1
selector:
matchLabels:
type: demo-v1
template:
metadata:
labels:
type: demo-v1
spec:
restartPolicy: Always
containers:
- name: v1
image: hello-world:v1.0.0
imagePullPolicy: Always
ports:
- containerPort: 8080

Container Types

在 Pod 中,可以包含多種類型的容器,每種類型都有其特定的用途。

Main Container

Main Container 是 Pod 的核心,負責執行應用程序的主要工作負載。通常,Pod 至少包含一個 Main Container。

Init Container

Init Container 是在 Main Container 啟動之前執行的特殊容器。它們的作用包括:

  • 等待其他服務準備好
    • 這種作法特別適用於解決服務器之間的依賴,例如有一個應用需要資料庫的服務,但啟動主服務的時候並不能保證被依賴的資料庫是否就緒, 這個時候我們可以簡單使用一個 Init Container,來監測資料庫服務是否 OK,確認 OK 就可以退出,並交由主服務開始啟動。
  • 執行初始化任務
    • 比如叢集檢測所有已經存在的成員節點,為主容器準備好叢集的設定資訊,這樣主容器啟動後就能用這些設定加入叢集。
提示

Init Container 必須執行成功,才能啟動 Main Container。

範例

  1. 首先我們想實現一個 google 首頁的服務,我們可以透過 InitContainers 來抓取首頁當成我們的首頁, 當他成功抓取之後並產出 index.html 後會隨即退出,再透過 volume 將資料夾掛載到主容器,實現初始化並共享資源,最後讓 nginx 服務啟動。
init-container.yaml
apiVersion: v1
kind: Pod
metadata:
name: init-demo
spec:
volumes:
- name: workdir
emptyDir: {}

initContainers:
- name: install
image: busybox
command: # 抓取google首頁當作index.html
- wget
- "-O"
- "/work-dir/index.html"
- https://www.google.com
volumeMounts: # 透過volume掛載到主容器上
- name: workdir
mountPath: /work-dir

containers:
- name: nginx
image: nginx
ports:
- containerPort: 80
volumeMounts: # 透過volume我們可以讀到init container抓到的東西
- name: workdir
mountPath: /usr/share/nginx/html

Hooks: Post Start & Pre Stop

Pod 支援兩種容器級別的鉤子(Hooks),他們是在初始化容器執行完畢後由 kubelet 發起,用於在容器啟動或停止時執行任務。

Post Start Hook

  • 這個鉤子在容器建立後立刻執行。但是並不能保證鉤子將在容器 Enterpoint(入口點)之前運行,因為他不會傳遞任何參數給作業程序。
  • 主要用於資源部屬、環境準備等。
  • 不過需要注意如果鉤子花費太多時間,以至於不能運行或者遇到問題,容器將不能達到 Running 狀態。

Pre Stop Hook

  • 是一個在容器結束運行前立刻被呼叫的鉤子。他是同步的,可以延遲終止過程,必須在容器被正式終止前完成執行。
  • 主要用於優雅的關閉應用、通知其他系統等。
  • 如果鉤子在執行期間掛起,Pod 階段將停留在 Running 狀態,並且永遠不會達到 Failed 狀態。

範例

以下的例子就是在 Pod 創立和刪除時會 echo 出來。

apiVersion: v1
kind: Pod
metadata:
name: lifecycle-demo
spec:
containers:
- name: lifecycle-demo-container
image: nginx
lifecycle:
postStart:
exec:
command: ['/bin/sh', '-c', 'echo Container started']
preStop:
exec:
command: ['/bin/sh', '-c', 'echo Container stopping']

Probes (探針)

為了確保應用的穩定性,Kubernetes 提供了 Liveness ProbeReadiness ProbeStartup Probe,用於監控和管理 Pod 中的容器狀態,如果出現異常將透過自我檢測和修復來避免把流量導到不健康的 Pod。

常見的檢查方式

  • Exec 檢查:執行容器內的一個命令,並檢查返回值,回傳 0 代表成功,其餘皆為失敗。
  • TCP 檢查:嘗試連接到容器的某個 TCP 埠,連接埠開啟代表成功,否則代表失敗。
  • HTTP 檢查:發送 HTTP 請求到容器內的指定端點,狀態大於等於 200 且小於 400 皆為成功,其餘皆失敗。
  • gRPC 檢查:可以透過對容器 IP 為紙上的指定連接埠發起 gRPC 請求,這裡需要注意的是使用 gRPC 作為 action 時需要特別指定連接埠。

Liveness Probe

Liveness Probe 用於檢查容器是否仍然存活。如果檢查失敗,Kubernetes 將重啟該容器,避免因應用停滯而導致服務不可用。

Readiness Probe

Readiness Probe 用於檢查容器是否已準備好接受流量。如果檢查失敗,Kubernetes 將從該容器的服務端點中移除,確保流量只分配給可用的容器。

Startup Probe

Startup Probe 用於檢查容器的啟動狀態,適用於需要較長時間啟動的應用程式。該探針允許 Kubernetes 在啟動期間給予容器更多時間,避免過早判定為失敗並進行重啟。

探針比較

探針類型功能失敗後行為
Liveness Probe檢查容器是否存活,若失敗表明應用已陷入無法恢復的狀態。Kubernetes 重啟容器。
Readiness Probe檢查容器是否準備好接受流量,若失敗表明應用暫時無法處理請求。Kubernetes 從服務端點中移除容器,暫停流量分配。
Startup Probe檢查容器的啟動過程是否完成,適用於啟動時間較長的應用程式。在超過失敗閾值前,Kubernetes 不會認定容器失敗或重啟。

範例

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: # 使用 TCP 檢查的方式
port: 8080 # 檢查的目標 TCP 埠
initialDelaySeconds: 5 # 探針檢查的初始延遲時間(單位:秒),容器啟動後 5 秒開始進行檢查
periodSeconds: 10 # 每次探針檢查的間隔時間(單位:秒)
livenessProbe: # 檢查容器是否仍然存活的探針
tcpSocket: # 使用 TCP 檢查的方式
port: 8080 # 檢查的目標 TCP 埠
initialDelaySeconds: 15 # 探針檢查的初始延遲時間(單位:秒),容器啟動後 15 秒開始進行檢查
periodSeconds: 20 # 每次探針檢查的間隔時間(單位:秒)

總結

Pod 的生命週期、容器類型、鉤子以及探針設定是 Kubernetes 中非常重要的概念,它們幫助我們更好地監控和管理應用的健康狀態。通過正確地使用 liveness 和 readiness 和 startup 探針,以及適當設置 Init Container 和鉤子,我們可以提升應用的穩定性和可靠性。