Kubernetes 系列(二):Workload 實戰入門 - 從 Pod 到 Job
前言
上一篇文章介紹了 Kubernetes 的控制平面與節點元件。本篇把焦點移到「應用程式到底要如何在叢集中運行」:你要部署的是可替換的 Web API、需要固定身份的資料服務、每台節點都要有一份的 agent,還是跑完就結束的批次工作?
Kubernetes 的 Workload 資源不是一堆互相獨立的 YAML 名詞,而是不同的生命週期模型。讀完本篇,你應該能先選對資源,再從 Pod、Controller、節點與容器四個層次判斷「誰會重啟、誰會補 Pod,以及為什麼」。
本篇會用幾個可以直接套用到測試叢集的實驗,觀察 Deployment 的滾動更新、StatefulSet 的固定身份、DaemonSet 隨節點變化的行為,以及 Job/CronJob 的完成與重試。為了讓主題保持集中,Service 只保留必要基礎;CoreDNS、EndpointSlice、CNI、L4/L7 與 Ingress 的封包路徑留到後續網路篇深入拆解。
實驗假設你已經有可使用的 Kubernetes 叢集與 kubectl。除非特別說明,以下資源都放在目前 context 的 default Namespace;正式環境請改用專用 Namespace,並為映像檔、資源限制與安全設定做審查。
一、先建立 Workload 選型表
Workload 解決的是什麼問題?
Pod 是實際承載容器的執行單位,但大多數應用程式不應直接由裸 Pod 管理。真正的 Workload Controller 會持續比較「期望狀態」與「目前狀態」,並建立、刪除或更新 Pod,讓兩者逐漸一致。
可以先用下面這張表做選型。這裡的「副本」不只是數字,而是 Kubernetes 對每個執行個體的身份、完成條件與替換方式的承諾。
| 資源 | 適合解決的問題 | 身份語意 | 儲存語意 | 副本/完成語意 | 常見場景 |
|---|---|---|---|---|---|
| 裸 Pod | 一個臨時、最小的執行單位 | 名稱與 IP 不保證長期穩定,沒有 Controller 負責補回 | 可用 emptyDir 或掛載 Volume;生命週期由 Pod 決定 | 只描述一個 Pod,不具備副本維護 | 除錯、一次性檢查、教學實驗 |
| Deployment | 可替換的無狀態服務 | Pod 是可互換的,替換後通常是新 UID、新 IP | 通常使用臨時儲存;共享資料應交給外部服務或另行設計 | replicas 表示同質、可替換的 Pod 數量 | Web、API、Worker、前端 |
| StatefulSet | 需要固定身份或每份獨立儲存的服務 | 具有穩定 ordinal,例如 stateful-demo-0、stateful-demo-1 | volumeClaimTemplates 可為每個 ordinal 建立獨立 PVC | replicas 表示一組有身份的成員,不等於資料自動複製 | 資料庫、訊息代理、需要節點身份的叢集 |
| DaemonSet | 每個符合條件的節點都執行一份 | 身份與「哪一台節點」相關,不是固定 ordinal | 常見 hostPath、節點本地目錄或 plugin volume | 沒有 replicas;符合條件的節點數決定 Pod 數 | Node agent、日誌收集器、CNI/CSI node plugin |
| Job | 有明確終點的批次工作 | Pod 可替換,重點是成功完成幾次 | 可用臨時 Volume 或外部儲存,需考慮重試造成的重複寫入 | completions、parallelism 與 backoffLimit 控制完成與重試 | Migration、資料匯入、報表、一次性批次 |
| CronJob | 按時間週期建立 Job | 每次排程產生新的 Job 與 Pod | 由每次 Job 的模板決定 | schedule 建立 Job;歷史數量與併發策略需另行設定 | 每日備份、定期同步、清理與報表 |
ReplicaSet 通常不是第一層的選型,而是 Deployment 在背後使用的 Controller:它負責維持某一版 Pod template 的數量;Deployment 則負責管理多個 ReplicaSet、滾動更新與回滾。
一個實用的選擇順序
遇到新服務時,可以按以下順序問自己:
- 這個程序會自然結束嗎?會的話選 Job;需要週期性執行則用 CronJob。
- 每一個符合條件的節點都需要它嗎?需要的話選 DaemonSet。
- 每個執行個體是否需要穩定名稱、順序或獨立 PVC?需要的話考慮 StatefulSet,但先確認應用程式本身的複製與故障轉移設計。
- 其他可互換的長駐服務,通常從 Deployment 開始。
- 只有短暫除錯或展示,才直接建立裸 Pod;不要因為 YAML 比較短就把正式服務放在裸 Pod 下。
二、Pod:共享網路與 Volume 的執行單位
Pod 不是「一個容器的別名」
Pod 是 Kubernetes 最小的可部署與調度單位。它可以只包含一個容器,也可以包含一組必須一起運行的容器。這些容器會被排到同一台節點,並共享部分執行環境:
graph LR
subgraph Pod["Pod:共同調度的執行單位"]
N["共享 Network Namespace<br/>同一個 Pod IP、localhost、Port 空間"]
V["Pod Volume<br/>必須由各容器明確掛載"]
C1["主容器"]
C2["Sidecar / 輔助容器"]
end
C1 <--> N
C2 <--> N
C1 --> V
C2 --> V
共享 Network Namespace
同一個 Pod 內的容器通常共享 Network Namespace,因此:
- 它們共用同一個 Pod IP。
- 一個容器在 127.0.0.1:8080 監聽時,同 Pod 其他容器可以用 localhost:8080 連線。
- 容器的 Port 不能互相衝突;兩個容器不能同時綁定同一個 IP/Port。
- Pod 外部的其他 Pod 不應依賴某個 Pod 的 IP 長期不變;Pod 被替換後,IP 通常會改變。
這也是為什麼 Sidecar 代理、日誌轉換器或和主程式緊密協作的輔助程式適合放在同一個 Pod。但兩個容器只要能各自獨立部署、擴展或故障處理,就不應為了「方便連線」而硬塞在同一個 Pod。
共享 Volume 不是自動發生的
Pod 可以定義 Volume,但每個容器仍要在 volumeMounts 中明確掛載它。emptyDir 會在 Pod 建立時出現,並在 Pod 被移除時消失;它不是跨 Pod 的永久儲存。若要讓資料跨越 Pod replacement 保留,應使用 PVC 或外部儲存,且還要確認應用程式的資料一致性設計。
同一個 Pod 內的容器還可能共享 Service Account、環境設定與其他 Pod-level 設定;但 Network Namespace 與 Volume 共享,不代表所有 Linux Namespace 都共享。例如 process namespace 預設不會讓一個容器直接看見另一個容器的程序,除非額外設定 shareProcessNamespace。
實驗:用兩個容器驗證 localhost 與共享檔案
下面的 YAML 讓 server 在 Pod 的 localhost:8080 啟動簡單 HTTP server,並把首頁寫入 emptyDir;client 透過 localhost 存取它,再從同一個 Volume 讀取檔案。套用前,先注意這個實驗要觀察的是「容器如何共享 Pod 的執行環境」,不是如何對外發布服務。
1 | apiVersion: v1 |
套用後可以從三個角度觀察:
1 | kubectl apply -f pod-shared-demo.yaml |
Pod 生命週期:三種「壞掉」不是同一件事
日常排查時,最容易混淆的是 container restart、Pod replacement 與 controller reconciliation。可以先用這張表分層:
| 事件 | 主要處理者 | Pod UID/IP | 你會看到什麼 | 典型原因 |
|---|---|---|---|---|
| Container restart | 節點上的 kubelet 與 container runtime | Pod 物件通常仍相同,IP 通常仍相同;restartCount 增加 | kubectl get pod 仍是同一個 Pod,可能出現 CrashLoopBackOff | 程序退出、liveness probe 失敗、restartPolicy 允許重啟 |
| Pod replacement | Workload Controller、Scheduler、kubelet 協作 | 新 Pod 會有新 UID,通常也會拿到新 IP | 舊 Pod 消失或進入終止,新 Pod 名稱/建立時間不同 | Deployment 副本不足、Pod 被刪除、節點故障或驅逐 |
| Controller reconciliation | API Server 儲存狀態;各 Controller 持續比較期望與實際狀態 | 可能不直接改變既有 Pod,也可能建立 replacement | Deployment、ReplicaSet、StatefulSet 或 DaemonSet 的 DESIRED/CURRENT/READY 逐漸靠攏 | 使用者修改宣告、節點加入、Pod 被刪、Probe/排程條件改變 |
因此,「Pod 掛掉不會自動重建」是一句不完整而且容易誤導的話,應該改成:
直接建立的裸 Pod 沒有 Controller 負責補回。容器程序失敗時,kubelet 可能依 restartPolicy 重啟同一個容器;如果整個 Pod 物件被替換,只有擁有它的 Deployment、StatefulSet、DaemonSet、Job 等 Controller 才會依自己的語意建立新 Pod。
CrashLoopBackOff 也不等於「Kubernetes 已經建立很多個新 Pod」;它通常表示同一個 Pod 內的容器反覆啟動、失敗,kubelet 逐步增加重試間隔。先看 restartCount、容器最後一次退出原因與事件,再判斷是否真的發生了 Pod replacement。
三、Deployment 與 ReplicaSet:管理可替換的長駐服務
三層關係:Deployment → ReplicaSet → Pod
對無狀態 Web/API 來說,最重要的不是某一個 Pod 的名字,而是「目前有幾個符合條件、已經 Ready 的 Pod」。Deployment 把這個期望狀態交給 ReplicaSet 維持:
graph TD
D["Deployment<br/>workload-demo"]
R1["ReplicaSet<br/>舊版本 template"]
R2["ReplicaSet<br/>新版本 template"]
P1["Pod"]
P2["Pod"]
P3["Pod"]
D -->|"管理版本與 rollout"| R1
D -->|"管理版本與 rollout"| R2
R1 -->|"維持舊副本"| P1
R2 -->|"維持新副本"| P2
R2 -->|"維持新副本"| P3
- Deployment 管理 ReplicaSet 的版本、更新策略、回滾與期望副本數。
- ReplicaSet 透過 selector 與 owner reference 維持某一個 Pod template 的數量。
- Pod 才是真正被排程、啟動容器與執行 probe 的物件。
更新 Deployment 的 Pod template 時,Deployment 會建立新的 ReplicaSet,逐步增加新版本、減少舊版本;舊 ReplicaSet 通常會保留在叢集中,讓 rollback 能夠回到上一個 template。不要在 Deployment 底下直接手動修改或縮放 ReplicaSet,否則 Deployment 下一次 reconciliation 可能把它改回去。
實驗:scale、刪除 Pod 與自動補回
先套用一個包含 readiness/liveness probe 的 Deployment。這裡 maxUnavailable: 0 與 minReadySeconds 方便我們觀察「新 Pod 真的 Ready 後,舊 Pod 才會被替換」,而不是只看到容器已經啟動就以為更新完成。
1 | apiVersion: apps/v1 |
先確認 Deployment、ReplicaSet 與 Pod 的層級關係:
1 | kubectl apply -f deployment-demo.yaml |
接著觀察水平擴展與 replacement。scale 會改變 Deployment 的期望副本數;刪除一個 Pod 則不會把 Deployment 的 replicas 減一,ReplicaSet 會發現實際數量不足並補一個新的 Pod。
1 | # 由 3 個副本擴展到 4 個 |
當你看到新 Pod 出現時,可以比較:
- Deployment 的 DESIRED 仍然是 4。
- ReplicaSet 的 CURRENT 會回到 4。
- 被刪除的 Pod 不會原地「復活」;新 Pod 是新的物件,通常有新的 UID 與 IP。
- Service 若選取這些 Pod,通常只會把流量交給已 Ready 的後端;Service 的 EndpointSlice 細節留到網路篇。
RollingUpdate:更新不只是換 image
用 kubectl set image 更新 Deployment 會改變 Pod template,因而產生新的 ReplicaSet。以下指令同時觀察 rollout、ReplicaSet 數量與每個 Pod 的版本:
1 | kubectl set image deployment/workload-demo web=nginx:1.27-alpine |
maxSurge: 1 允許更新期間比期望副本多一個 Pod;maxUnavailable: 0 則要求至少維持原本的可用副本數。這不是「所有更新都零停機」的保證:如果應用程式啟動很慢、探針錯誤、資料庫 migration 不相容或所有節點都沒有資源,rollout 仍可能卡住。
Readiness 與 rollback 實驗
readinessProbe 失敗時,容器可以仍然是 Running,但 Pod 會是 0/1 Ready;這個狀態主要用來阻止流量進入尚未準備好的 Pod,不是用來重啟容器。相對地,livenessProbe 失敗才會讓 kubelet 重啟容器。
下面故意把新版本的 readiness URL 改成不存在的路徑。這會讓新 ReplicaSet 的 Pod 啟動但長期不 Ready,Deployment 因 maxUnavailable: 0 保留舊版本,rollout 因而停在中間:
1 | kubectl patch deployment workload-demo --type='json' \ |
確認新 Pod 的狀態與事件後,使用 Deployment 的歷史版本回滾,而不是手動刪除新 Pod:
1 | kubectl rollout history deployment/workload-demo |
回滾會恢復前一個 Pod template,包含 image 與 readiness probe。若要回到特定版本,可先用 rollout history 找到 revision,再執行 kubectl rollout undo deployment/workload-demo –to-revision=
四、StatefulSet:固定身份,不是資料庫高可用按鈕
它保證了哪些事?
StatefulSet 適合「每個成員都需要知道自己是誰」的服務。當 replicas 設為 3 時,常見的成員名稱是:
1 | stateful-demo-0 |
StatefulSet 主要提供:
- 穩定、可預測的 ordinal identity。
- Pod 重新排程後仍可沿用相同的 ordinal 名稱。
- 透過 Headless Service 建立每個成員可尋找的網路身份。
- 透過 volumeClaimTemplates 為每個 ordinal 建立獨立 PVC,例如 data-stateful-demo-0。
- 預設依序建立與更新成員,避免所有成員同時變動。
它 不 自動提供資料複製、選主、共識、備份或故障轉移。資料庫是否具備高可用,仍取決於資料庫本身的 replication/consensus 協定、儲存系統、備份與 Operator。StatefulSet 只是把「成員身份與儲存掛載」這些基礎條件穩定地交給應用程式。
實驗:Headless Service、ordinal 與每 Pod PVC
這份範例刻意使用簡單的 HTTP server,讓我們可以觀察每個 Pod 的 hostname 與獨立資料目錄。套用前先確認叢集有可用的 StorageClass;若沒有,PVC 會停在 Pending,這本身就是後續儲存篇會排查的實務狀況。
1 | apiVersion: v1 |
觀察 StatefulSet 建立順序、Pod 名稱與 PVC 名稱:
1 | kubectl apply -f statefulset-demo.yaml |
刪除中間的 Pod,再觀察它是否以相同 ordinal 回來,以及原本的 PVC 是否仍被使用:
1 | kubectl delete pod stateful-demo-1 |
Headless Service 的重點是「不配置 ClusterIP」,讓每個成員可以有自己的 DNS 名稱。以下只用來驗證固定名稱;DNS 查詢如何進入 CoreDNS、記錄如何由 EndpointSlice 更新,會在網路篇完整拆解。
1 | kubectl run dns-client \ |
若要刪除測試環境,請先確認 PVC 內沒有需要保留的資料;刪除 StatefulSet 不代表所有 PVC 都會自動消失,實務上更不能把 StatefulSet deletion 當成資料清理策略。
五、DaemonSet:每個符合條件的節點各一份
它和 Deployment 的差別
Deployment 的副本數由 spec.replicas 決定;DaemonSet 則根據「目前有哪些節點符合條件」決定 Pod 數量。節點加入、移除、被標記或被 taint 時,DaemonSet Controller 會重新計算應該存在的 Pod。
DaemonSet 常見於:
- Node exporter、日誌收集器、監控或安全 agent。
- CNI plugin 的 node component。
- CSI driver 的 node plugin。
- 每台節點都要執行的清理、硬體探測或本地代理。
真正的 CNI/CSI DaemonSet 通常還需要 hostPath、hostNetwork、裝置掛載、RBAC、特定 toleration,甚至較高的 Linux capability。下面只用一個不需要主機權限的 busybox loop 做行為實驗,避免把有風險的系統權限 YAML 當成通用範本。
實驗:標記節點後才建立 Pod
這份 YAML 使用 nodeSelector,所以剛套用時如果沒有任何節點帶有 workload-agent=true,DaemonSet 的 desired Pod 數量會是 0。若要改成所有 Linux 節點各一份,可以移除 nodeSelector,或改成叢集一致的節點條件;正式環境還要一併檢查 taints/tolerations。
1 | apiVersion: apps/v1 |
先套用並確認沒有符合條件的節點,接著逐一標記節點:
1 | kubectl apply -f daemonset-selected-node.yaml |
再做一次「新增節點」實驗。節點必須先由雲端節點池、kubeadm、kind 或其他叢集工具加入並進入 Ready,Kubernetes 本身不會因為 DaemonSet 自動替你建立一台虛擬機器:
1 | # 節點加入流程完成後,等待它出現在 API Server |
理想結果是:每多一台符合 selector 的節點,就多一個 node-agent Pod;移除標籤後,該節點上的 Pod 會被 DaemonSet Controller 移除或不再視為應有副本:
1 | kubectl label node <node-a> workload-agent- |
如果新節點已經 Ready 卻沒有 Pod,依序檢查 nodeSelector、節點 taint、Pod 的 Events、映像檔拉取與資源容量。DaemonSet 的 DESIRED、CURRENT、READY 很適合用來判斷問題是在「節點是否符合條件」、Pod 是否建立,還是容器是否真正 Ready。
六、Job 與 CronJob:完成就停止的工作
Job 的生命週期
長駐服務用「一直維持幾個 Pod」描述;Job 則用「成功完成幾次」描述。Job Controller 會建立 Pod 執行工作,根據退出碼判斷成功或失敗,並依 backoffLimit 重試。restartPolicy: Never 通常會在失敗後建立新的 Pod;OnFailure 則允許 kubelet 在同一個 Pod 內重啟容器,兩者要分清楚。
graph LR
J["Job<br/>batch-demo"] --> P1["Pod attempt 1"]
P1 -->|"失敗,未超過 backoffLimit"| P2["Pod attempt 2"]
P2 -->|"exit 0"| C["Job Complete"]
實驗:一次性 Job 與重試
下面的 Job 會成功執行一次,完成後不再保持一個長駐服務;ttlSecondsAfterFinished 讓測試環境在完成一段時間後清理 Job 及其 Pod。套用前要觀察的是 completions、backoffLimit 與 Complete,不是 Deployment 式的 Ready。
1 | apiVersion: batch/v1 |
觀察 Job、Pod 與完成狀態:
1 | kubectl apply -f job-demo.yaml |
要看重試行為,可以建立一個故意失敗的 Job。它的 exit 1 會讓 Job 持續建立失敗嘗試,直到達到 backoffLimit:
1 | kubectl create job retry-demo \ |
批次工作必須考慮重試造成的副作用。例如「寫入一筆付款」不能只靠 Job 保證只執行一次;工作內容應設計成 idempotent,或以工作 ID、唯一鍵與交易狀態防止重複處理。
CronJob:按時間建立 Job
CronJob 不是直接執行容器,而是依 schedule 建立 Job;Job 再建立 Pod。下面每五分鐘建立一個短工作,並用 Forbid 避免同一個 CronJob 的前一個 Job 尚未結束時重疊執行。
1 | apiVersion: batch/v1 |
套用後不必等五分鐘,可以從 CronJob 立即複製一個 Job 做觀察:
1 | kubectl apply -f cronjob-demo.yaml |
在正式環境還要思考工作執行時間、時區、錯過排程時的處理、併發策略、歷史清理與外部系統的冪等性。Forbid 只能限制同一個 CronJob 的重疊,不會替你的業務邏輯提供分散式鎖。
七、Service 只先掌握必要基礎
Workload Controller 負責「Pod 應該存在幾個、如何更新」;Service 負責「其他客戶端如何找到一組會變動的 Pod」。Service 不會建立 Pod,也不是另一種 Workload Controller。
最小的 ClusterIP Service 如下。套用前請先注意 selector 必須與 Deployment template 的 label 完全匹配;selector 寫錯時,Service 物件仍可能是 Active,但沒有可用後端。
1 | apiVersion: v1 |
必要概念先記住三件事:
- ClusterIP 是叢集內穩定的虛擬端點,Pod 被替換後,客戶端不需要知道新的 Pod IP。
- NodePort 讓節點 IP 加上固定高位 Port 成為入口,常用於簡單測試或作為其他負載平衡器的後端。
- LoadBalancer 會請雲端或叢集整合元件配置外部負載平衡器;是否真的拿到外部 IP、流量如何進叢集,取決於環境。
Service 不是固定的「Round Robin 設定」,也不是 L7 HTTP Router。Service 的 selector、Ready 狀態、EndpointSlice、kube-proxy/eBPF 與外部 Load Balancer 會共同影響實際流量路徑。Part 3 先拆解 Pod-to-Pod 與 Service VIP 的封包路徑,Part 7 再深入 CoreDNS/Service Discovery,Part 8 則比較 L4/L7、Ingress 與 Gateway API。
八、用同一套觀察方式排查 Workload
遇到問題時,先不要只看 kubectl get pods 的一行狀態;把「物件、Controller、Pod、容器、事件」一起看:
1 | # 先看 Workload 與 Pod 是否達到期望狀態 |
可以用下表快速定位:
| 現象 | 優先確認 | 常見誤判 |
|---|---|---|
| CrashLoopBackOff | restartCount、容器退出碼、liveness probe、kubectl logs –previous | 以為 Kubernetes 建立了很多個新 Pod |
| Deployment rollout 卡住 | 新 ReplicaSet、readiness probe、映像檔、資源與事件 | 只刪掉不 Ready 的 Pod,結果 Controller 又建立同樣的 Pod |
| StatefulSet Pod Pending | 對應 PVC、StorageClass、Volume attach/mount 事件 | 以為 StatefulSet 會自動提供資料複製 |
| DaemonSet 少一份 | Node selector、taint/toleration、節點 Ready 與資源 | 只看 replicas,但 DaemonSet 沒有固定 replicas |
| Job 一直失敗 | Pod exit code、backoffLimit、輸入資料與重試副作用 | 把 Job 當成 Deployment,期待它永遠保持一個 Running Pod |
| Service 存在但連不到 | selector、Pod Ready 狀態與後端 Port | 先去改 CoreDNS,卻沒有先確認 Service 是否有後端 |
這些排查方式的共同點是:先確認是哪一層的狀態不一致,再決定要修改 workload template、節點條件、容器程式,或只是等待 controller 完成 reconciliation。
本篇重點回顧
- Pod 是共享 Network Namespace 與明確掛載 Volume 的執行單位,不是永久伺服器。
- Container restart 通常保留同一個 Pod;Pod replacement 會建立新的 Pod 物件;Controller reconciliation 則是讓期望狀態與實際狀態重新一致。
- 無狀態長駐服務優先使用 Deployment;ReplicaSet 是 Deployment 管理版本時的中介 Controller。
- StatefulSet 提供穩定 ordinal、Headless Service 身份與每 Pod PVC,但不會自動把資料庫變成高可用。
- DaemonSet 的副本數由符合條件的節點數決定,適合 node agent、日誌收集器與 CNI/CSI node plugin。
- Job 以完成次數為中心,CronJob 以排程建立 Job;兩者都必須設計好重試與冪等性。
- Service 只先理解為穩定地指向一組 Pod 的入口;Pod 網路見 Part 3,DNS/EndpointSlice 見 Part 7,L4/L7 見 Part 8。
下一篇預告
下一篇 Part 3 將從「Pod A 呼叫 Pod B」開始,逐跳拆解 Pod IP、CNI、Service 與 kube-proxy;CoreDNS/EndpointSlice 與 L4/L7 會在 Part 7、Part 8 延伸,讓 curl http://service-name 不再只是看起來會工作的魔法。
系列文章導覽
- Part 1:入門篇 - 認識 K8s 與核心架構
- Part 2:Workload 實戰入門 - 從 Pod 到 Job(本篇)
- Part 3:網路篇 - 服務發現與流量管理
- Part 4:配置與儲存篇 - ConfigMap、Secret 與 Volume
- Part 5:進階篇 - 資源管理與自動擴展
- Part 6:實戰篇 - 部署完整微服務應用
- Part 7:服務發現實戰 - CoreDNS、Service 與 EndpointSlice
- Part 8:L4/L7 負載平衡實戰 - 從 ClusterIP 到 Gateway API
- Part 9:故障排除篇 - 從症狀到根因的實戰診斷
- Part 10:Production Baseline - 把測試叢集變成可運維環境
- Part 11:資源治理與排程 - Requests、QoS、PDB 與 Topology
- Part 12:Autoscaling 與容量規劃 - HPA、VPA 與 Node Autoscaler
- Part 13:Release Engineering - 安全發布、回滾與漸進式交付
- Part 14:Observability 實戰 - Metrics、Logs、Traces 與 SLO
參考資源
- Pods - Kubernetes Documentation
- Deployments - Kubernetes Documentation
- ReplicaSet - Kubernetes Documentation
- StatefulSets - Kubernetes Documentation
- DaemonSet - Kubernetes Documentation
- Jobs - Kubernetes Documentation
- CronJob - Kubernetes Documentation
- Service - Kubernetes Documentation
- Liveness, Readiness, and Startup Probes - Kubernetes Documentation











