iT邦幫忙

2026 iThome 鐵人賽

DAY 17
0
Kubernetes

從零到 CKA:30 天掌握 Kubernetes 核心觀念與實作系列 第 17

Day 17|Init Container — Pod 啟動前的初始化機制

  • 分享至 

  • xImage
  •  

前言

昨天我們結束了排程系列(Day 12–16),從「Pod 該去哪裡」一路學到「資源不足時誰應該優先」。

但回頭想想,到目前為止我們討論的 Pod,大多都是啟動後就直接執行主要程式。

在真實的生產環境中,Pod 啟動前經常還需要先完成一些準備工作,例如:

  • 等待資料庫就緒,確認可以連線後再啟動應用
  • 從遠端下載設定檔或憑證
  • 初始化資料目錄、設定權限
  • 等待相依的 Service 準備完成

這些「主程式啟動前的準備工作」,就可以交給 Init Container 來處理。

今天我們來學:

  1. 核心概念 — 什麼是 Init Container?
  2. 用比喻理解 — 餐廳開店前的準備工作
  3. Init Container 的重要特性 — 執行順序、失敗重試、資源計算
  4. 實作練習 — 三個常見的 Init Container 使用場景
  5. 失敗處理 — Init Container 失敗時會發生什麼?
  6. 常見使用場景總整理 — 等待服務、下載設定、初始化資料等
  7. Init Container vs Sidecar Container — 兩者有什麼不同?

以下操作皆在 master 節點 執行。


一、核心概念

什麼是 Init Container?

Init Container 是 Pod 中一種特殊的 Container,會在主要 Container 啟動之前先執行。

Init Container 有以下幾個重要特性:

  • 依序執行:如果有多個 Init Container,會按照 YAML 中定義的順序一個一個執行;前一個成功完成後,下一個才會啟動
  • 失敗會重試:如果 Init Container 執行失敗,Kubernetes 會根據 Pod 的 restartPolicy 處理;一般情況下會持續重試,直到成功完成
  • 完成後退出:Init Container 完成任務後就會結束,不會像主要 Container 一樣持續執行
  • 主要 Container 會等待:所有 Init Container 都成功完成後,主要 Container 才會開始啟動

簡單來說:

Init Container 先把準備工作做完,主要 Container 才正式開始執行。

為什麼不直接寫在主容器裡?

你可能會想:「這些準備工作直接寫在主容器的啟動腳本裡不就好了?」

使用 Init Container 的好處主要有三個:

  1. 關注點分離 — 初始化邏輯和業務邏輯分開,讓主容器保持單純
  2. 可以使用不同的 Image — 例如主容器是 Nginx,但初始化需要用 curl 下載設定檔,就不需要把 curl 額外安裝進 Nginx Image
  3. 可以使用不同的權限與工具 — Init Container 可以依初始化需求設定不同的工具、Volume 或權限,完成工作後就退出,減少主容器需要具備的額外能力

💡Pod 啟動流程

  1. Init Container 1 啟動 → 完成 → 退出
  2. Init Container 2 啟動 → 完成 → 退出
  3. ...依照定義順序執行
  4. 所有 Init Container 完成
  5. 主要 Container 啟動

二、用比喻理解

想像一間餐廳開店前的準備工作

  • Init Container 1(採購員):去市場買食材 → 買完就下班
  • Init Container 2(清潔員):打掃廚房、擦桌子 → 做完就下班
  • Init Container 3(設備檢查員):檢查瓦斯、冰箱、烤箱是否正常 → 確認沒問題就下班
  • 主要 Container(主廚 + 服務生):所有準備工作完成後,餐廳才正式營業!

對應到 Kubernetes:

餐廳準備工作 Kubernetes
採購員(買食材) Init Container(下載設定檔 / 憑證)
清潔員(打掃廚房) Init Container(初始化資料目錄、設定權限)
設備檢查員(檢查設備) Init Container(等待相依服務就緒)
主廚 + 服務生(正式營業) 主要 Container(應用程式開始運行)

💡 重點

每個 Init Container 完成自己的任務後就會結束,不會持續執行。

這就是 Init Container 的特色 —— 完成初始化後退出,而主要 Container 則會接著啟動並持續執行。


三、Init Container 欄位詳解

基本結構

apiVersion: v1
kind: Pod
metadata:
  name: myapp-pod
spec:
  initContainers:
  - name: init-download-config
    image: busybox:1.36
    command: ["sh", "-c", "wget -O /config/app.conf http://config-server/config"]
    volumeMounts:
    - name: config-volume
      mountPath: /config
  - name: init-wait-db
    image: busybox:1.36
    command: ["sh", "-c", "until nc -z mysql-service 3306; do echo waiting for db...; sleep 2; done"]
  containers:
  - name: myapp
    image: myapp:latest
    volumeMounts:
    - name: config-volume
      mountPath: /config
  volumes:
  - name: config-volume
    emptyDir: {}

關鍵特性

特性 說明
定義位置 spec.initContainers[],與 spec.containers[] 位於同一層級
執行順序 多個 Init Container 會按照定義順序依序執行,不是並行
成功條件 前一個 Init Container 必須成功完成,下一個才會開始
失敗行為 Init Container 執行失敗時,Kubernetes 會依 Pod 的 restartPolicy 決定是否重試
Probe 支援 一般 Init Container 不支援 livenessProbereadinessProbestartupProbe
資料共享 可以和主要 Container 掛載相同的 Volume,用來傳遞初始化後的檔案或資料

補充

Kubernetes 也支援在 initContainers 中定義 restartPolicy: Always 的 Sidecar Container。

這類 Container 會持續執行,生命週期和一般 Init Container 不同,也可以使用 Probe。

資源計算規則

Init Container 的資源需求也會影響 Pod 的排程,但計算方式和主要 Container 不太一樣。

可以先簡單記成:

Pod 的有效資源請求 = Init Containers 中最大的請求 vs 主要 Containers 請求總和,兩者取較大值

而且 CPU、Memory 等資源會分開計算

例如 CPU:

  • Init Container 1:requests.cpu: 500m
  • Init Container 2:requests.cpu: 200m
  • 主要 Container:requests.cpu: 300m

計算方式:

Init Containers 最大值 = 500m
主要 Containers 總和 = 300m

所以:

Pod 有效 CPU Request = max(500m, 300m) = 500m

因為一般 Init Container 是依序執行的,不會同時執行,所以 Init Containers 之間不需要全部相加,而是取其中最大的資源需求。

Scheduler 會根據這個有效資源請求,判斷哪一台 Node 有足夠的資源可以執行這個 Pod。


四、實作練習

練習 1:等待 Service 就緒後才啟動

這是最常見的 Init Container 使用場景 — 確保依賴的服務已經上線。

先建立一個會「等待」的 Pod:

vim init-wait-service.yaml
apiVersion: v1
kind: Pod
metadata:
  name: init-wait-demo
  labels:
    app: init-wait-demo
spec:
  initContainers:
  - name: wait-for-myservice
    image: busybox:1.36
    command: ["sh", "-c", "until nslookup myservice.default.svc.cluster.local; do echo 'Waiting for myservice...'; sleep 3; done; echo 'myservice is ready!'"]
  containers:
  - name: main-app
    image: nginx
kubectl apply -f init-wait-service.yaml

觀察 Pod 狀態:

kubectl get pods init-wait-demo -w

會看到 Pod 停在 Init:0/1 狀態 — 因為 myservice 還不存在。

https://ithelp.ithome.com.tw/upload/images/20260819/20181928Rpq5Y0Mgts.png

查看 Init Container 的 log:

kubectl logs init-wait-demo -c wait-for-myservice

會看到不斷輸出 Waiting for myservice...

https://ithelp.ithome.com.tw/upload/images/20260819/20181928HGcxGPiYVI.png

現在建立那個 Service,讓 Init Container 通過:

vim myservice.yaml
apiVersion: v1
kind: Service
metadata:
  name: myservice
spec:
  ports:
  - port: 80
    protocol: TCP
kubectl apply -f myservice.yaml

再觀察 Pod 狀態:

kubectl get pods init-wait-demo -w

https://ithelp.ithome.com.tw/upload/images/20260819/20181928Kq7xu8s1nJ.png

https://ithelp.ithome.com.tw/upload/images/20260819/20181928tMzBPiictg.png

會看到:

  • Init Container 偵測到 myservice 已經可以解析後 → 成功完成並退出
  • Pod 狀態從 Init:0/1Running

💡 生產環境中的應用

假設你的 API Server 依賴 MySQL,如果 MySQL 還沒準備好,API Server 就直接啟動,可能會不斷出現連線失敗。

這時可以用 Init Container 先等待 MySQL 可以連線,再讓 API Server 啟動。

這樣就能避免應用程式在相依服務還沒準備完成時過早啟動。

練習 2:用 Init Container 下載設定檔

Init Container 把設定檔下載到共享 Volume,主容器直接使用。

vim init-download-config.yaml
apiVersion: v1
kind: Pod
metadata:
  name: init-config-demo
  labels:
    app: init-config-demo
spec:
  initContainers:
  - name: download-config
    image: busybox:1.36
    command:
    - sh
    - -c
    - |
      echo 'server {' > /config/default.conf
      echo '  listen 80;' >> /config/default.conf
      echo '  location / {' >> /config/default.conf
      echo '    return 200 "Hello from Init Container config!\n";' >> /config/default.conf
      echo '  }' >> /config/default.conf
      echo '}' >> /config/default.conf
      echo "Config file created successfully"
    volumeMounts:
    - name: config-volume
      mountPath: /config
  containers:
  - name: nginx
    image: nginx
    volumeMounts:
    - name: config-volume
      mountPath: /etc/nginx/conf.d
  volumes:
  - name: config-volume
    emptyDir: {}
kubectl apply -f init-download-config.yaml
kubectl get pods init-config-demo -w

https://ithelp.ithome.com.tw/upload/images/20260819/20181928CfuwdhbtH8.png

等 Pod 變成 Running 後,驗證設定是否生效:

# 查看 Init Container 的 log
kubectl logs init-config-demo -c download-config

# 驗證 Nginx 是否使用了 Init Container 產生的設定
kubectl exec init-config-demo -- curl -s localhost

應該會看到:Hello from Init Container config!

https://ithelp.ithome.com.tw/upload/images/20260819/201819288Aw8brWcxe.png

💡 資料流動方向

Init Container(download-config)

↓ 寫入設定檔

/config/default.conf

↓ 透過 emptyDir Volume 共享

主要 Container(nginx)

↓ 掛載並讀取

/etc/nginx/conf.d/default.conf

這就是 Init Container 很常見的資料傳遞方式 —— 透過共享 Volume,把初始化產生的檔案交給主要 Container 使用。

練習 3:多個 Init Container 依序執行

觀察多個 Init Container 的執行順序

vim init-multi-steps.yaml
apiVersion: v1
kind: Pod
metadata:
  name: init-multi-demo
  labels:
    app: init-multi-demo
spec:
  initContainers:
  - name: step1-check-env
    image: busybox:1.36
    command: ["sh", "-c", "echo '[Step 1] Checking environment...' && sleep 3 && echo '[Step 1] Environment OK'"]
  - name: step2-init-data
    image: busybox:1.36
    command:
    - sh
    - -c
    - |
      echo '[Step 2] Initializing data directory...'
      mkdir -p /data/app
      echo '{"initialized": true, "timestamp": "'$(date)'"}' > /data/app/init.json
      sleep 2
      echo '[Step 2] Data initialized'
    volumeMounts:
    - name: data-volume
      mountPath: /data
  - name: step3-final-check
    image: busybox:1.36
    command:
    - sh
    - -c
    - |
      echo '[Step 3] Final check...'
      cat /data/app/init.json
      echo '[Step 3] All checks passed!'
    volumeMounts:
    - name: data-volume
      mountPath: /data
  containers:
  - name: main-app
    image: busybox:1.36
    command: ["sh", "-c", "echo 'Main app started!' && cat /data/app/init.json && sleep 3600"]
    volumeMounts:
    - name: data-volume
      mountPath: /data
  volumes:
  - name: data-volume
    emptyDir: {}
kubectl apply -f init-multi-steps.yaml

觀察 Init Container 依序啟動:

kubectl get pods init-multi-demo -w

https://ithelp.ithome.com.tw/upload/images/20260819/20181928POdeNgR4Ds.png

會看到狀態變化:

  • Init:0/3 → Step 1 正在跑
  • Init:1/3 → Step 1 完成,Step 2 正在跑
  • Init:2/3 → Step 2 完成,Step 3 正在跑
  • Running → 所有 Init Container 完成,主容器啟動

查看每個 Init Container 的 log:

kubectl logs init-multi-demo -c step1-check-env
kubectl logs init-multi-demo -c step2-init-data
kubectl logs init-multi-demo -c step3-final-check

# 主容器的 log — 確認它有拿到 Init Container 準備的資料
kubectl logs init-multi-demo -c main-app

https://ithelp.ithome.com.tw/upload/images/20260819/201819283RNoIYhaDK.png

kubectl describe 觀察完整的啟動流程:

kubectl describe pod init-multi-demo

在 Events 區段你會看到每個 Init Container 依序啟動和結束的事件紀錄。

https://ithelp.ithome.com.tw/upload/images/20260819/20181928iAmZgcHZVm.png

💡 觀察重點

  1. 三個 Init Container 不會同時啟動,而是依照定義順序依序執行:
    Step 1 完成 → Step 2 啟動 → Step 2 完成 → Step 3 啟動

  2. Step 2 寫入的 init.json,Step 3 和主要 Container 都可以透過共享 Volume 讀取

  3. 使用 kubectl describe pod <pod-name> 查看時,可以在 Init Containers 區段看到已完成的 Init Container:

State:      Terminated
Reason:     Completed

這表示該 Init Container 已經成功完成任務並退出。


五、Init Container 失敗會怎樣?

如果 Init Container 執行失敗,Kubernetes 會根據 Pod 的 restartPolicy 決定後續行為:

restartPolicy Init Container 失敗時的行為
Always(預設) 失敗的 Init Container 會被重新執行,直到成功
OnFailure 失敗的 Init Container 會被重新執行,直到成功
Never 不會重試,Pod 會被標記為 Failed

💡 注意

Init Container 失敗時,通常是重新執行失敗的那一個,不是每次都從第一個 Init Container 重新開始。

不過 Init Container 仍可能因為 Pod 重新啟動或重建而再次執行,因此初始化操作最好設計成冪等(idempotent) —— 執行多次也不會造成錯誤或重複副作用。

我們來快速驗證一下:

vim init-fail-demo.yaml
apiVersion: v1
kind: Pod
metadata:
  name: init-fail-demo
  labels:
    app: init-fail-demo
spec:
  initContainers:
  - name: will-fail
    image: busybox:1.36
    command: ["sh", "-c", "echo 'Init starting...' && exit 1"]
  containers:
  - name: main-app
    image: nginx
kubectl apply -f init-fail-demo.yaml
kubectl get pods init-fail-demo -w

https://ithelp.ithome.com.tw/upload/images/20260819/20181928nwokonnHKv.png

會看到 Pod 一直在 Init:CrashLoopBackOff 狀態 — Init Container 失敗 → 重試 → 失敗 → 重試,主容器永遠不會啟動。

# 查看失敗的 Init Container log
kubectl logs init-fail-demo -c will-fail

# 查看事件
kubectl describe pod init-fail-demo

https://ithelp.ithome.com.tw/upload/images/20260819/20181928O3LyA39osV.png


六、常見使用場景總整理

場景 Init Container 做什麼 範例
等待依賴服務 用迴圈確認 Service 是否可達,再讓主要 Container 啟動 until nslookup db-service; do sleep 2; done
下載設定檔 從遠端取得設定檔,寫入共享 Volume wget -O /config/app.conf http://config-server/config
初始化資料目錄 建立目錄、準備檔案結構或設定權限 mkdir -p /data/app && chown 1000:1000 /data/app
資料庫 Migration 在應用程式啟動前先執行資料庫 Schema 更新 python manage.py migrate
等待外部系統 確認外部 API 或相依系統已經可以使用 until curl -sf http://api-gateway/health; do sleep 5; done
取得敏感設定 由 Init Container 從 Vault 等系統取得 Secret,再透過共享 Volume 提供給主要 Container 使用 Init Container 負責取 Secret,主要 Container 只讀取結果

七、Init Container vs Sidecar Container

今天學了 Init Container —— 「完成任務後就退出」的初始化容器。

但有些工作不是一次性的,而是需要在主要 Container 執行期間持續在旁邊提供支援,例如:

  • 持續收集 Log
  • 代理網路流量
  • 同步設定或資料

這類 Container 就稱為 Sidecar Container

先簡單比較:

特性 Init Container Sidecar Container
執行時機 主要 Container 啟動之前 啟動後會與主要 Container 一起執行
生命週期 完成任務後退出 持續執行,通常伴隨 Pod 的生命週期
用途 初始化、準備工作 持續提供輔助功能
比喻 開店前的準備人員 營業期間一直在旁邊協助的副手

💡 先知道一個概念

Kubernetes 原生 Sidecar 的做法,是在 initContainers 中設定:

restartPolicy: Always

一般 Init Container 完成後會退出;設定 restartPolicy: Always 的 Sidecar 則會持續執行,並和主要 Container 一起工作。

這項機制在 Kubernetes v1.28 以 Alpha 推出,目前已成為 Stable 功能。

明天我們會再深入了解 Sidecar Container 的啟動順序、生命週期與實際使用方式。


小結

今天我們學了 Init Container —— Pod 啟動前的初始化機制:

重點 說明
定義位置 spec.initContainers[],與主要 Container 位於同一層級
執行特性 依序執行,前一個成功完成後,下一個才會開始
資料傳遞 可以透過共享 Volume,例如 emptyDir,把初始化產生的資料交給主要 Container
常見場景 等待依賴服務、下載設定檔、初始化資料目錄、執行 DB Migration
失敗處理 Init Container 失敗時,Kubernetes 會依 Pod 的 restartPolicy 決定是否重試
資源計算 Init Containers 中最大的資源請求,會和主要 Containers 的資源請求總和比較,取較大的值

Init Container 負責的是「開店前的準備工作」—— 任務完成後就退出。

但如果有些工作不是一次性的,而是需要一個 Container 持續待在旁邊提供支援呢?

明天我們來學 Sidecar Container —— Pod 的最佳副手,看看它如何和主要 Container 一起運作,以及 Kubernetes 原生 Sidecar 的生命週期設計。


參考資源


上一篇
Day 16|PriorityClass 與 Preemption — Pod 的優先級與搶佔機制
下一篇
Day 18|Sidecar Container — Pod 的最佳副手
系列文
從零到 CKA:30 天掌握 Kubernetes 核心觀念與實作18
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言