昨天我們學了 Init Container —— Pod 啟動前的初始化機制。
Init Container 的特性是「完成任務後就退出」,主要負責在主要 Container 啟動前,先把必要的準備工作做好。
但如果有些工作不是一次性的,而是需要一個 Container 持續待在旁邊提供支援呢?
例如:
這時候,就需要用到今天的主角:Sidecar Container —— Pod 的最佳副手。
今天我們來學:
restartPolicy: Always
以下操作皆在 master 節點 執行。
Sidecar Pattern 是一種容器設計模式:在同一個 Pod 裡,除了主要的應用 Container 之外,再放一個或多個輔助 Container(Sidecar),負責處理和主程式相關、但不屬於核心業務邏輯的工作。
例如:
因為 Sidecar 和主要 Container 位於同一個 Pod,所以它們可以共享:
localhost 互相通訊| 場景 | 主要 Container | Sidecar Container | 說明 |
|---|---|---|---|
| Log 收集 | 應用程式 | Fluentd / Fluent Bit | Sidecar 讀取共享 Volume 中的 Log,並轉發到集中式日誌系統 |
| 網路代理 | API Server | Envoy 等 Proxy | Sidecar 負責處理流量代理、mTLS、負載均衡或流量控制 |
| Config Reload | Nginx | Config Watcher | Sidecar 監看設定變化,並在需要時通知主要 Container 重新載入設定 |
| 資料同步 | Web Server | Git Sync | Sidecar 定期從 Git 同步最新檔案到共享 Volume,提供給主要 Container 使用 |
在學原生 Sidecar 之前,先釐清一個容易搞混的概念:
| 特性 | Init Container | Sidecar Container |
|---|---|---|
| 執行時機 | 主要 Container 啟動之前 | 啟動後會持續執行,並與主要 Container 一起運作 |
| 生命週期 | 完成任務後退出 | 通常會持續運行到主要 Container 結束 |
| 用途 | 初始化(下載設定、等待依賴服務就緒) | 輔助運行(Log 收集、Proxy、監控) |
| 執行方式 | 依序執行,前一個完成後才執行下一個 | 啟動後持續運行,不需要等 Sidecar 結束才啟動主要 Container |
簡單來說:
想像一間餐廳的廚房:
對應到 Kubernetes:
| 餐廳廚房 | Kubernetes |
|---|---|
| 主廚(做菜) | Main Container(核心業務邏輯) |
| 副手(備料、洗碗、傳菜) | Sidecar Container(Log、Proxy、Sync 等輔助功能) |
| 廚房 | Pod |
| 共用食材區 | 共享 Volume,例如 emptyDir |
| 共用溝通空間 | 共享網路,可以透過 localhost 互相通訊 |
在 Kubernetes 原生 Sidecar 機制出現之前,Sidecar Pattern 早就已經被廣泛使用。
傳統做法是:直接在 spec.containers[] 裡放入多個 Container,其中一個是主要 Container,另一個則負責輔助工作。
例如:
spec:
containers:
- name: main-app # 主容器
image: nginx
- name: log-collector # Sidecar(但 K8s 不知道它是 sidecar)
image: busybox
傳統 Sidecar 的問題:
spec.containers[] 裡的 Container 本質上都是一般 ContainerKubernetes 1.28 引入了原生 Sidecar Container 的概念。
做法很巧妙:不是新增一個 sidecarContainers 欄位,而是讓 initContainers 支援 restartPolicy: Always:
spec:
initContainers:
- name: log-collector # 原生 Sidecar
image: busybox
restartPolicy: Always # 關鍵!讓 Container 持續運行
command: ["sh", "-c", "tail -f /var/log/app.log"]
containers:
- name: main-app # 主要 Container
image: nginx
💡 為什麼放在
initContainers裡?因為
initContainers本身有啟動順序,可以讓 Sidecar 在主要 Container 之前先啟動。加上:
restartPolicy: Always之後,這個 Container 不會像一般 Init Container 一樣「完成後退出」,而是會持續執行。
如果需要確保 Sidecar 真的準備完成後才啟動主要 Container,還可以搭配
startupProbe。這種設計很適合需要先啟動輔助服務,再啟動主要應用程式的場景。
| 特性 | 傳統 Sidecar | 原生 Sidecar |
|---|---|---|
| 定義位置 | spec.containers[] |
spec.initContainers[] + restartPolicy: Always |
| 啟動順序 | Kubernetes 不特別保證 Sidecar 比主要 Container 先啟動 | 可以在主要 Container 之前啟動 |
| 終止順序 | 沒有 Sidecar 專屬的終止順序保證 | 主要 Container 結束後,Sidecar 才會被終止 |
| Job 完成判定 | Sidecar 持續執行時,可能讓 Job 無法正常完成 | Sidecar 不會阻止 Job 在主要 Container 完成後結束 |
| Probe 支援 | 支援 | 支援 startupProbe / livenessProbe / readinessProbe |
| Kubernetes 是否知道它是 Sidecar | 不知道,只視為一般 Container | 有原生 Sidecar 的生命週期語意 |
💡 原生 Sidecar 解決的核心痛點
- 啟動順序 —— Sidecar 可以先啟動,再啟動主要 Container
- 終止順序 —— 主要 Container 先結束,Sidecar 最後再關閉
- Job 相容 —— 主要 Container 完成後,不會因為 Sidecar 持續運行而讓 Job 卡住
apiVersion: v1
kind: Pod
metadata:
name: sidecar-demo
spec:
initContainers:
- name: log-sidecar
image: busybox:1.36
restartPolicy: Always
command: ["sh", "-c", "tail -f /var/log/app/app.log"]
volumeMounts:
- name: log-volume
mountPath: /var/log/app
startupProbe:
exec:
command: ["test", "-f", "/var/log/app/app.log"]
periodSeconds: 5
containers:
- name: main-app
image: busybox:1.36
command: ["sh", "-c", "for i in $(seq 1 10); do echo \"$(date) Log entry $i\" >> /var/log/app/app.log; sleep 2; done; echo 'Main app done'"]
volumeMounts:
- name: log-volume
mountPath: /var/log/app
volumes:
- name: log-volume
emptyDir: {}
| 欄位 | 說明 |
|---|---|
restartPolicy: Always |
放在 initContainers 中的關鍵設定,讓這個 Container 持續運行,而不是完成後退出,形成原生 Sidecar |
startupProbe |
用來確認 Sidecar 是否已經成功啟動;在 Probe 通過前,後續的 Init Container 或主要 Container 不會繼續啟動 |
volumeMounts |
可以透過共享 Volume(例如 emptyDir)與主要 Container 交換檔案或資料 |
先用傳統方式實作一個最基本的 Sidecar:Nginx 寫 access log,Sidecar 負責即時讀取。
vim traditional-sidecar.yaml
apiVersion: v1
kind: Pod
metadata:
name: traditional-sidecar
spec:
containers:
- name: nginx
image: nginx
volumeMounts:
- name: log-volume
mountPath: /var/log/nginx
- name: log-reader
image: busybox:1.36
command: ["sh", "-c", "tail -f /var/log/nginx/access.log"]
volumeMounts:
- name: log-volume
mountPath: /var/log/nginx
volumes:
- name: log-volume
emptyDir: {}
kubectl apply -f traditional-sidecar.yaml
kubectl get pods traditional-sidecar
觀察 Sidecar 讀取 log:
# 在另一個終端製造一些 access log
kubectl exec traditional-sidecar -c nginx -- curl -s localhost > /dev/null
# 查看 log-reader sidecar 的輸出
kubectl logs traditional-sidecar -c log-reader

💡 注意
-c參數當 Pod 裡有多個 Container 時,使用
kubectl logs或kubectl exec時,可以透過-c <container-name>指定要操作哪一個 Container。
現在用原生 Sidecar 改寫,重點是觀察定義方式和 Pod 結構的差異。
這次我們讓 Sidecar 做一件簡單的事 — 每 5 秒印出一行 heartbeat,不依賴主容器的任何資源:
vim native-sidecar.yaml
apiVersion: v1
kind: Pod
metadata:
name: native-sidecar
spec:
initContainers:
- name: log-sidecar # 原生 Sidecar
image: busybox:1.36
restartPolicy: Always # 關鍵:讓它持續運行
command: ["sh", "-c", "while true; do echo \"[$(date)] sidecar is running\"; sleep 5; done"]
containers:
- name: nginx # 主容器
image: nginx
kubectl apply -f native-sidecar.yaml
kubectl get pods native-sidecar

💡 和練習 1 對比一下結構上的不同
練習 1(傳統 Sidecar):主要 Container 和 Sidecar 都寫在
spec.containers[]裡,Kubernetes 會把它們都視為一般 Container。練習 2(原生 Sidecar):Sidecar 寫在
spec.initContainers[]裡,並加上:restartPolicy: Always這樣 Kubernetes 就會套用原生 Sidecar 的生命週期行為。
Step 1:觀察 Pod 狀態
kubectl describe pod native-sidecar

會看到:
log-sidecar 出現在 Init Containers 區段,而且狀態是 Running
nginx 出現在 Containers 區段log-sidecar 會先啟動,再讓主要 Container nginx 接著啟動這表示 log-sidecar 雖然定義在 initContainers 裡,但因為設定了 restartPolicy: Always,所以不會像一般 Init Container 一樣完成後退出,而是會持續運行。
Step 2:查看 Sidecar 的 log 輸出
kubectl logs native-sidecar -c log-sidecar
會看到每 5 秒一行的 heartbeat,代表這個 init container 並沒有跑完就退出,而是持續運行中:

這是原生 Sidecar 最大的優勢之一 — 主容器完成後,Pod 可以正常結束:
vim sidecar-job.yaml
apiVersion: batch/v1
kind: Job
metadata:
name: sidecar-job
spec:
template:
spec:
initContainers:
- name: log-sidecar
image: busybox:1.36
restartPolicy: Always
command: ["sh", "-c", "while true; do echo '[sidecar] watching...'; sleep 5; done"]
containers:
- name: worker
image: busybox:1.36
command: ["sh", "-c", "echo 'Working...'; sleep 10; echo 'Job done!'"]
restartPolicy: Never
kubectl apply -f sidecar-job.yaml
# 觀察 — Job 應該在 worker 完成後正常結束
watch -n 2 kubectl get pods -l job-name=sidecar-job

會看到:
worker Container 執行約 10 秒後完成log-sidecar(原生 Sidecar)接著被終止💡 如果用傳統 Sidecar 做同樣的事?
如果
log-sidecar是放在spec.containers[]裡的傳統 Sidecar,即使worker已經完成,Sidecar 仍可能持續執行。這樣 Pod 就無法進入
Completed,Job 也會一直等待。原生 Sidecar 可以配合 Job 的生命週期,在主要 Container 完成後由 Kubernetes 處理 Sidecar 的終止,改善傳統 Sidecar 在 Job 場景中的生命週期問題。
今天我們學了 Sidecar Container —— Pod 內多 Container 協作的核心模式:
| 重點 | 說明 |
|---|---|
| Sidecar Pattern | 主要 Container + 輔助 Container 在同一個 Pod 中,共享網路和儲存 |
| 常見用途 | Log 收集、網路代理、Config Reload、資料同步 |
| 傳統 Sidecar | 放在 containers[],Kubernetes 只會把它視為一般 Container,生命週期控制較有限 |
| 原生 Sidecar | 放在 initContainers[],搭配 restartPolicy: Always,具備原生 Sidecar 的啟動與終止生命週期 |
| 共享機制 | 可以透過 emptyDir 等 Volume 共享檔案,也能透過 localhost 互相通訊 |
到目前為止,我們的 Pod 大多都跑在 default Namespace 裡。
但當叢集裡的 Pod 越來越多,不同團隊、不同環境的資源要怎麼分類、隔離與管理?
明天我們來學 Namespace —— Kubernetes 的資源隔離與多租戶管理,看看如何把叢集中的資源整理得更有層次!