如果你曾經開始學 Kubernetes,很可能有過這種經驗。
影片裡講 Pod、Deployment、Service,好像每一個名詞都聽得懂。接著照著教學輸入:
kubectl apply -f deployment.yaml
kubectl get pods
kubectl get svc
Terminal 裡看到:
Running
那一瞬間會覺得:「好像懂 Kubernetes 了。」
但隔幾天如果有人突然問:
Deployment、ReplicaSet 和 Pod 到底是什麼關係?
腦袋可能瞬間一片空白。
又或者某天 Pod 突然出現:
CrashLoopBackOff
第一個反應不是思考「到底是哪一層壞掉」,而是把錯誤訊息整段複製貼給 ChatGPT。
這其實也是我一直覺得 Kubernetes 難學的地方。
Kubernetes 本身確實不簡單,但更大的問題是,很多學習方式很容易變成:
今天學 Pod
明天學 Deployment
後天學 Service
再來 ConfigMap
再來 Secret
每一個名詞好像都懂一點,卻很難回答一個更重要的問題:
它們為什麼要一起存在?
所以這 30 天,我想換一種方式來學 Kubernetes。
我們不會做 30 個彼此完全無關的小範例。
從 Day 1 開始,我們會一起養出 同一套 Kubernetes 系統。每天只增加一點複雜度,讓前一天的東西自然成為下一天的基礎。
整個系列使用的程式碼與 Kubernetes Manifest,我也會整理在 GitHub Repository 裡,讀者可以直接 Clone 下來一起操作:
GitHub Repository:
https://github.com/YIFUNLIN/k8s-30days
我們會從一個非常簡單的 FastAPI 開始。
一開始可能只有:
FastAPI
↓
Container
但隨著每天增加一個新的需求,最後會逐漸長成類似這樣:
Client
│
▼
Gateway
│
▼
HTTPRoute
│
▼
Service
│
┌─────┴─────┐
▼ ▼
API Pod API Pod
│
┌──────┴──────┐
▼ ▼
Service Service
Redis PostgreSQL
│ │
▼ ▼
Redis Pod PostgreSQL Pod
│
▼
PVC
│
▼
PV
到那個時候,我們會碰到 ConfigMap、Secret、Probe、HPA、NetworkPolicy、RBAC、Scheduling、Job、CronJob、DaemonSet、Gateway API、Helm、Kustomize、etcd,甚至一路做到 GitHub Actions、Argo CD 與 GitOps。
但重點是:
我們不會第一天就把全部東西裝完。
因為我覺得學 Kubernetes 最容易掉進的一個坑,就是還沒真正理解 Service 是什麼,就開始裝 Helm、Ingress、Argo CD、Prometheus。
最後畫面看起來很厲害,但只要其中一個 Pod 起不來,就完全不知道問題到底出在哪一層。
所以這個系列會遵守一個很簡單的原則:
一次只增加一個複雜度。
今天只有一層,明天再多一層。
這樣當系統真的壞掉時,我們才知道到底是哪一層出了問題。
因為這 30 天最重要的目標只有一個:
學 Kubernetes。
而不是一次學:
Kubernetes
+
VPC
+
IAM
+
Security Group
+
Load Balancer
+
Cloud Billing
如果一開始直接跑到 AWS、GCP 或 Azure,很容易發生一個問題:
你根本不知道現在出錯的到底是 Kubernetes,還是 Cloud 本身的網路、權限或其他設定。
因此這個系列前半段會全部在自己的電腦完成。
架構大概是:
Mac / Windows / Linux
│
▼
Docker
│
▼
kind
│
▼
Kubernetes Cluster
kind 的全名是:
Kubernetes IN Docker
它的概念很有趣。
正常來說 Kubernetes Cluster 會有多台 Node,而 kind 直接把這些 Node 做成 Docker Container。
因此在自己的筆電上,也可以建立:
control-plane
worker
worker
這種多節點 Kubernetes Cluster。
而且對學習來說,kind 有一個非常重要的優點:
玩壞了完全沒關係。
真的救不回來,最慘就是:
kind delete cluster
重新建立一個。
這反而比 Production Cluster 更適合學 Kubernetes,因為我們可以放心地:
改設定
→ 弄壞
→ Troubleshoot
→ 修好
而不用擔心真的把公司的服務炸掉。
先暫時不要背官方定義。
我們直接想像一個很簡單的場景。
假設今天有一個 FastAPI:
FastAPI
最開始只有一個 Container:
API Container
流量開始增加後,我們可能開成三個:
API Container
API Container
API Container
這時問題就開始出現了。
如果其中一個 Container 掛掉,誰負責重新啟動?
流量突然增加,誰負責多開幾份?
新版 API 上線時,要怎麼避免三個 Container 一次全部停掉?
如果 Container 重新啟動後 IP 變了,其他服務又要怎麼找到它?
甚至如果某一台 Server 整台掛掉,原本跑在上面的 Container 又要搬去哪裡?
這些事情在只有一兩個 Container 的時候,工程師可能還可以手動處理。
但當系統變成:
幾十個 Service
幾百個 Pod
多台 Node
再靠人工處理,很快就會失控。
Kubernetes 真正要解決的,就是這些問題。
所以我自己很喜歡用一句話理解 Kubernetes:
你告訴 Kubernetes「我希望系統長什麼樣子」,Kubernetes 持續把現實世界修正成你希望的樣子。
假設我們告訴 Kubernetes:
Desired State
API Pod = 3
意思是:
我希望永遠有 3 個 API Pod。
但某一刻其中一個 Pod 掛了,現在只剩:
Actual State
API Pod = 2
Kubernetes 發現:
Desired State = 3
Actual State = 2
2 ≠ 3
於是它就會想辦法再建立一個 Pod,把系統修回:
API Pod = 3
這個「持續比較希望狀態和實際狀態,再把差異修正回來」的過程,就叫做:
Reconciliation
中文可以理解成:
調和 / 協調 / 狀態修正。
這個概念非常重要。
因為接下來 30 天你會發現:
Deployment 在做這件事。
HPA 在做這件事。
Operator 在做這件事。
甚至最後的 Argo CD,其實也在做非常類似的事情。
整個 Kubernetes 世界背後,都一直圍繞著:
Desired State
↓
Compare
↓
Actual State
↓
Reconcile
這個系列真正想練的,不只是:
kubectl apply -f xxx.yaml
然後看到:
Running
就結束。
我更希望 30 天後,當你看到:
Pending
腦中會開始自然思考:
是不是 Scheduler 沒地方放?
Resource 不夠?
nodeSelector 沒符合?
Taint 擋住了?
PVC 還沒綁定?
看到:
ImagePullBackOff
會開始想到:
Image 名稱對嗎?
Tag 存在嗎?
Registry 有權限嗎?
CPU Architecture 對嗎?
看到:
Running 0/1
會開始去檢查:
Readiness Probe
而不是看到 Pod 明明:
Running
但 Service 打不到,就開始重啟 Pod。
這時應該會自然想到:
Service Selector
↓
Pod Label
↓
EndpointSlice
↓
Port
↓
NetworkPolicy
這也是我覺得真正「會 Kubernetes」和「會打 Kubernetes 指令」最大的差別。
真正會 Kubernetes,不是記住最多指令。
而是:
看到症狀之後,知道下一步應該去哪一層找證據。
每一天我們都會維持差不多的節奏。
不會一開始就說:
今天來背 StatefulSet。
而是先遇到問題。
例如某一天我們可能發現:
PostgreSQL Pod 被重建之後,名稱一直改,而且 Database 這種東西好像不像 API 一樣可以隨便換。
這時才開始問:
Kubernetes 有沒有更適合 Stateful Application 的 Workload?
然後才引出:
StatefulSet
也就是:
先遇到問題
↓
理解為什麼需要某個機制
↓
真的動手建立
↓
觀察它怎麼運作
↓
最後故意把它弄壞
最後那一步,我覺得尤其重要。
因為 Kubernetes 有一個很有趣的地方:
如果你只看過它正常工作的樣子,其實只學了一半。
例如只看過 Pod:
Running
你很難真的理解 Probe。
直到你第一次看到:
Running
0/1
然後一路查到 Readiness Probe,才會突然理解:
原來 Running 和 Ready 根本不是同一件事。
所以這系列會故意製造一些錯誤。
不是因為我們喜歡把 Cluster 弄壞。
而是因為:
Troubleshooting 本身,就是理解 Kubernetes 最快的方法之一。
今天我們甚至還沒有真正開始輸入 Kubernetes 指令。
但我反而覺得,這可能是整個系列最重要的一篇。
因為開始之前,有幾個觀念一定要先建立起來。
第一個是:
Kubernetes 不是 Docker 的替代品。
Docker 比較像是在回答:
怎麼把 Application
包裝成一個可以執行的 Container?
Kubernetes 則是在回答:
這些 Container
怎麼部署?
怎麼找到彼此?
怎麼擴展?
怎麼更新?
怎麼在故障後恢復?
第二個更重要。
Kubernetes 的核心不是:
kubectl
也不是:
YAML
而是:
Desired State
↓
Controller
↓
Actual State
↓
Reconcile
你描述「我希望系統變成什麼樣子」,Controller 持續觀察現實世界,然後把它修回去。
這個概念會一路貫穿接下來的 Deployment、HPA、Operator,甚至最後的 GitOps。
最後,我們接下來也不是要讀 30 篇彼此無關的 Kubernetes 筆記。
我們會從:
一個 FastAPI
開始。
每天加上一小塊。
慢慢長成:
Application
↓
Container
↓
Kubernetes Workload
↓
Service
↓
Storage
↓
Networking
↓
Security
↓
Autoscaling
↓
Scheduling
↓
Gateway
↓
GitHub Actions
↓
Argo CD
↓
GitOps
最後真的得到:
一套我們自己從零養出來,而且知道每一層為什麼存在的 Kubernetes 系統。
完整 Lab 與 Manifest 也會持續整理在:
GitHub:
https://github.com/YIFUNLIN/k8s-30days
如果哪一天操作到一半 Cluster 被玩壞了,也不用害怕。
因為某種程度上,那可能正是我們真正開始理解 Kubernetes 的時候。
明天我們反而會先暫時不碰 Kubernetes。
因為在真正理解 Kubernetes 之前,還有一個更根本的問題要先搞懂:
既然 Docker 已經可以跑 Container 了,為什麼我們還需要 Kubernetes?