Deployment 與自我修復:reconcile loop 的實戰

· tech

#kubernetes#concept

第一篇給了靈魂(reconcile loop),第二篇給了原子(Pod)。但實務上你幾乎不會手動去建一個 Pod —— 你宣告的是 Deployment,而它正是 reconcile loop 最實用、最常見的化身。這篇看它怎麼自我修復、又怎麼零停機換版

為什麼不直接建 Pod

因為裸 Pod 掛了沒人救。 你手動建一個 Pod,它一旦當掉或所在的 node 壞了,就這樣沒了 —— 沒有任何東西記得「本來該有它」。你要的不是「開一個 Pod」,而是「永遠維持 N 個健康的 Pod」。這正是需要一個 controller 幫你盯著的事,而 Deployment 就是幹這個的:

Deployment 期望:replicas = 3 · image v1 ReplicaSet 確保永遠有 3 個 Pod Pod ✓ 健康 Pod ✗ 掛了 Pod ✓ 健康 少一個 → ReplicaSet 觀察到落差 → 立刻補一個新的回到 3 個
你宣告 Deployment,它透過 ReplicaSet 維持「永遠有 3 個 Pod」;掛了一個就自動補一個 —— 這就是 reconcile loop 的自我修復

分工很清楚:Deployment 管版本與更新策略;它底下的 ReplicaSet 只負責一件事——盯著實際 Pod 數,少了就補、多了就砍。 你只宣告「我要 3 份 v1」,剩下的都是那個迴圈在跑。

自我修復:reconcile loop 一直在跑

所謂「K8s 會自我修復」,拆開來一點都不神秘,就是 reconcile loop 在做它該做的:

  • 你宣告期望 = 3 個 Pod。
  • ReplicaSet controller 不斷比對實際:現在幾個健康的?
  • Pod 當掉、或整台 node 壞掉 → 實際變 2 → 有落差 → 建一個新 Pod 補回 3。

你半夜不用被叫起來重啟服務,因為那個迴圈替你做了。 這也是為什麼上一篇說 Pod 短命是特性:正因為它可拋棄,壞了才能無痛換新的。

滾動更新:把「部署」變成日常

Deployment 真正值錢的另一半,是換版不中斷服務。你把 image 從 v1 改成 v2,它不會一次全砍掉重開,而是新版一個個起、舊版一個個收:

開始 更新中 完成 v1 v1 v1 v1 v1 v2 v2 v2 v2 ■ 舊版 v1 ■ 新版 v2 新版起一個、舊版收一個 → 全程有服務;出包 kubectl rollout undo 一鍵回滾
滾動更新:一次換一點,新舊版交棒,服務不中斷;背後是 Deployment 開一個新 ReplicaSet(v2)、慢慢把舊的(v1)縮到 0

背後的機制還是同一套:更新時 Deployment 開一個新的 ReplicaSet(v2),一邊把它擴上去、一邊把舊 ReplicaSet(v1)縮下來。出包了怎麼辦?因為舊 ReplicaSet 還留著,一行 kubectl rollout undo 就秒回到 v1。

日常操作其實就這幾條,全是「改期望」:

kubectl apply -f web.yaml                    # 宣告期望(3 份 v1)
kubectl set image deploy/web web=web:2.0     # 換版 → 觸發滾動更新
kubectl rollout undo deploy/web              # 出包 → 一鍵回滾
kubectl scale deploy/web --replicas=5        # 改份數 → loop 幫你補到 5

注意:你從頭到尾沒有下過一個「開容器」「停容器」的指令 —— 你只是不斷更新那份「期望」,reconcile loop 把現實收斂過去。

反思

「自我修復」不是魔法,是那個迴圈一直在跑

第一次看到 Pod 被 kill 掉、幾秒後自己又冒出來,確實很神奇。但拆開就發現一點都不玄:ReplicaSet controller 只是不停地問「實際幾個?和期望差多少?」,有差就動手。 想通這件事之後,K8s 的「韌性」對我不再是黑魔法,而是一個很樸素的迴圈 —— 這也讓我 debug 更有方向:服務沒被拉回來,那八成是這個迴圈被什麼卡住了(資源不夠排不進、健康檢查一直失敗…),而不是「玄學」。把神奇的東西還原成機制,是我學任何系統的第一步。

滾動更新讓「部署」從緊張大事變成日常

我很吃這一套。以前部署是件要挑半夜、全員待命、深怕中斷服務的大事;有了 Deployment 的滾動更新 + 一鍵回滾,部署變成低風險的日常動作 —— 新版慢慢頂替、出包秒退。這跟我在 Airflow 那篇講的「生產作業要冪等、可重跑」是同一種安全感:讓「改變」變得可逆、可控,人就敢頻繁地小步前進,而不是攢一大包、賭一次大的。

你宣告「要什麼」,不是「怎麼做」——Deployment 是最好的示範

整個系列的主軸在這篇最具體:你給 Deployment 的永遠是目標狀態(3 份、v2),從不是步驟(先開這個、再停那個)。這份「期望」還能寫進 Git、版控、review —— 就是第一篇說的宣告式 + GitOps 的紅利。之後你會遇到的 Service、StatefulSet、HPA,全是同一個模式的不同套用。抓住「宣告期望、loop 收斂」,K8s 後面的東西就都是變形題。