昨天打了 kubectl get pods -A,看到一堆自己沒建過的泡泡(Pod)。
那些是誰?誰在管這座島?
島上有一區叫燈塔村 (Control Plane),住著四個核心管理角色。

這是燈塔村的平面圖:全部先指向中央的燈塔櫃台(API Server)。
燈塔櫃台(API Server)
島上唯一的窗口。吹哨子(kubectl)下的控制面指令,先到 API Server;其他控制面角色通常也透過櫃台讀寫叢集狀態。
看圖上的箭頭:沒有任何一條線繞過櫃台(API Server)。
實際意義是,只要能跟 API Server 說話,就能操作整座島。
記憶樹(etcd)
Kubernetes API 物件主要持久化在這裡。要什麼、現在有什麼,核心狀態都記在這棵樹上。
燈塔櫃台(API Server),每次都去問記憶樹(etcd)。
記憶樹(etcd)倒了,島就失憶了,正式環境備份 etcd 就是在備份這個。
選樹官(Scheduler)
專門處理一件事:有新泡泡(Pod)要掛,但還沒決定掛哪棵樹,並且看每棵樹可配置的資源與其他條件,挑一棵,把答案寫回櫃台。
就這樣,它不負責真的把泡泡(Pod)掛上去。
巡邏隊長(Controller Manager)
拿著清單一直繞島巡邏,持續比對「你想要的結果」與「實際島上現況有的」。
Controller Manager 裡面包含多種控制器,其中的 Deployment controller 會負責讓 Deployment 這類資源的期望狀態逐步實現。

巡邏隊長(Controller Manager)舉著寫有「要 3 顆」的清單,對照樹上只有 2 顆泡泡(Pod),中間這個落差就是它要補上的工作。
我們描述「我要三顆泡泡(Pod)」這個目標,系統再持續把現況對齊到這個目標。
差別在哪?
描述動作的話,泡泡(Pod)破了就沒了,因為指令早就執行完了。
描述結果的話,泡泡(Pod)破了,巡邏隊長(Controller Manager)會發現數字不對,自己補回來。
之後寫的每一份 YAML,都是在跟櫃台(API Server)描述結果,分工上:燈塔村 (Control Plane) 只出一張嘴。
選樹官(Scheduler)決定泡泡(Pod)掛哪棵樹,巡邏隊長(Controller Manager)發現數量不足後,會向櫃台(API Server) 登記補充需求。
真正把泡泡(Pod)吹出來的是樹上的管家松鼠(kubelet),每棵樹上都住著一隻,盯著櫃台看有沒有自己這棵樹的活。
決定跟執行是分開的,這也是為什麼燈塔村 (Control Plane) 掛掉的時候,已經在跑的服務不會馬上跟著死。

昨天我們看完了島、樹 (Node)、泡泡(Pod)三層。今天不加資源,只去燈塔村 (Control Plane) 點名。
燈塔村 (Control Plane) 的成員全住在 kube-system 這個區域:
kubectl get pods -n kube-system
你會在清單裡看到 kube-apiserver-hello-control-plane(櫃台 API Server)、etcd-hello-control-plane(記憶樹 etcd )、kube-scheduler-hello-control-plane 選樹官(Scheduler)、kube-controller-manager-hello-control-plane(巡邏隊長 Controller Manager)。四個角色,四顆泡泡(Pod),都是 Running。
原來 Control Plane 自己也是用泡泡(Pod)跑的。

橘色標出來的,就是櫃台(API Server)、記憶樹(etcd)、選樹官(Scheduler)、巡邏隊長(Controller Manager)。
看看選樹官(Scheduler)當初把你的 hello 泡泡(Pod)派去哪:
kubectl describe pod hello | sed -n '/Events:/,$p'
Events 裡有一行 Successfully assigned default/hello to hello-control-plane,發出這行的角色是 default-scheduler。這就是選樹官(Scheduler)做完決定的簽名。
驗證:所有事情都經過櫃台 (API Server):
kubectl get pods -v=6
-v=6 會把 kubectl 背後的動作印出來。你會看到一行 GET https://127.0.0.1:xxxxx/api/v1/namespaces/default/pods。哨子(kubectl)做的事情,其實就是對櫃台發 HTTP 請求。
最後看櫃台跟記憶樹(etcd)健不健康:
kubectl get --raw='/readyz?verbose' | head -20
一連串 ok,其中有一行 [+]etcd ok。櫃台正在回報:我問得到記憶樹(etcd)。
最後回答一個你現在一定會想到的問題:燈塔村 (Control Plane) 掛掉會怎樣?
分兩種情況。已經在跑的服務通常還能繼續 ── 樹上的管家松鼠(kubelet)不需要櫃台就能繼續照顧現有的泡泡(Pod),道路管理員整理好的地道規則也還在,是否無感要看 kubelet、Runtime、網路與應用程式狀態。
但你會失去「改變」的能力:不能部署、不能擴容,泡泡(Pod)破了也沒有人會補,因為負責發現這件事的巡邏隊長(Controller Manager)不在了。所以正式環境通常會替燈塔村與記憶樹(etcd)做高可用與備份,而記憶樹(etcd)是所有東西裡最需要定期備份的 ── 它一失憶,整座島就不知道自己該長什麼樣子。
你也可以親眼看看記憶樹(etcd)裡存了什麼形狀的東西:
kubectl get pod hello -o yaml | head -20
metadata、spec、status ── 你要的(spec)跟現況(status)並排放在同一份紀錄裡。巡邏隊長(Controller Manager)一輩子就在比對這兩段。
你只描述結果,巡邏隊長(Controller Manager)負責把現實調整成你的期望。