前情提要:昨天我們理解了 Pod 跟 Pod YAML,但似乎還不知道 K8s 是怎麼管理跟擴容 pod 的。
從手動管理 Pod 到自動化的 Deployment 管理
Docker Compose 的熟悉世界
還記得你用 Docker Compose 管理多個容器的經驗嗎?
# docker-compose.yml - 你熟悉的方式
version: '3.8'
services:
web:
image: nginx:1.20
deploy:
replicas: 3 # 想要 3 個副本
ports:
- "80:80"
restart: always # 掛了自動重啟
environment:
- ENV=production
database:
image: mysql:8.0
environment:
- MYSQL_ROOT_PASSWORD=secret
volumes:
- db_data:/var/lib/mysql
volumes:
db_data:
現實世界的比喻
想像你從經營單一分店升級到連鎖店:
場景 | Docker Compose | Kubernetes Deployment |
---|---|---|
規模 | 🏪 單一分店 | 🏢 連鎖店集團 |
人員管理 | 👨💼 店長手動排班 | 🤖 總部自動調配人力 |
故障處理 | 📞 店長接到通知才處理 | 🚨 系統自動派遣替補 |
擴展 | 🔨 需要重新裝潢 | ⚡ 自動開設新分店 |
更新 | 🚪 暫停營業更新 | 🔄 分批更新不停業 |
想像你經營一家 24 小時便利商店:
# 😰 手動管理的噩夢
kubectl run nginx --image=nginx
# Pod 掛了...
kubectl delete pod nginx
kubectl run nginx --image=nginx # 又要重新建立
# 想要 3 個副本...
kubectl run nginx-1 --image=nginx
kubectl run nginx-2 --image=nginx
kubectl run nginx-3 --image=nginx
# 想更新版本...
kubectl delete pod nginx-1
kubectl run nginx-1 --image=nginx:1.21
# 😭 太痛苦了!
此時,K8s 提供 Deployment 來協助我們管理這些 Pod。
Deployment
是 K8s 中一種聲明式控制器,用來管理跟維護一組 Pod 副本。主要適用於管理 stateless application
的生命週期。通過 Deploment 聲明,可以自動地控制 application 的副本數量、進行 zero down time更新、擴縮容等。
關於 stateless application,能參考小弟之前的文章無狀態服務
想像你是餐廳老闆:
Deployment 自動幫你:
各層職責詳解
層級 | 角色比喻 | 主要職責 | 管理範圍 |
---|---|---|---|
Deployment | 🎯 總經理 | 制定策略、版本管理、滾動更新 | 管理多個 ReplicaSet |
ReplicaSet | 📋 部門經理 | 維持人員數量、監控狀態 | 管理多個 Pod |
Pod | 🏃 員工 | 執行實際工作 | 運行容器 |
這樣的三層架構,其實在 Docker compose 設計時就有類似的概念能對照了。
simple-deployment
# simple-deployment.yaml
apiVersion: apps/v1
kind: Deployment # 資源類型
metadata:
name: nginx-deployment # Deployment 名稱
labels:
app: nginx # 標籤(可選)
spec:
replicas: 3 # 期望的 Pod 數量,我要 3 個 Pod
selector: # 選擇器:告訴 Deployment 管理哪些 Pod
matchLabels:
app: nginx
template: # Pod 的模板
metadata:
labels:
app: nginx # Pod 的標籤(必須與 selector 匹配)
spec:
containers:
- name: nginx
image: nginx:1.29.0-otel
ports:
- containerPort: 80
YAML 欄位說明
部署和查看
# 建立 Deployment
> kubectl apply -f simple-deployment.yaml
# 成功創建了名為 nginx-deployment 的 Deployment
deployment.apps/nginx-deployment created
# 查看 Deployment 狀態
> kubectl get deploy nginx-deployment
NAME READY UP-TO-DATE AVAILABLE AGE
nginx-deployment 3/3 3 3 27s
# UP-TO-DATE: 3 個 Pod 都是最新版本
# AVAILABLE: 3 個 Pod 都可用
# 查看 Pod(會看到 3 個 Pod,符合 replicas: 3 的設定)
> kubectl get pods
NAME READY STATUS RESTARTS AGE
nginx-deployment-5945d66dc-28c44 1/1 Running 0 66s
nginx-deployment-5945d66dc-8w4qv 1/1 Running 0 66s
nginx-deployment-5945d66dc-s2nsh 1/1 Running 0 66s
# Pod 名稱格式:{deployment-name}-{replicaset-hash}-{random-suffix}
# 查看詳細資訊
> kubectl describe deployment nginx-deployment
Name: nginx-deployment
Namespace: default # default(默認命名空間)
CreationTimestamp: Mon, 18 Aug 2025 23:35:18 +0800
Labels: app=nginx # Deployment 的標籤
Annotations: deployment.kubernetes.io/revision: 1
Selector: app=nginx # selector,用於選擇管理的 Pod
Replicas: 3 desired | 3 updated | 3 total | 3 available | 0
# 副本狀態 期望 3 個,實際 3 個,全部可用
unavailable
StrategyType: RollingUpdate # 滾動更新策略,明天在介紹
MinReadySeconds: 0
RollingUpdateStrategy: 25% max unavailable, 25% max surge
# 更新時最多 25% 的 Pod 不可用,最多可以額外創建 25% 的 Pod,明天在介紹
Pod Template:
Labels: app=nginx # Pod的標籤
# 查看所有相關資源
> kubectl get deploy,rs,pods -l app=nginx
# 這指令中間的`deploy,rs,pods`,分別代表3種資源︰deployment、replicaset與pod
# `-l app=nginx` 則是 selector
# 完全展開版本︰
# kubectl get deployments,replicasets,pods --selector=app=nginx
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/nginx-deployment 3/3 3 3 2m34s
NAME DESIRED CURRENT READY AGE
replicaset.apps/nginx-deployment-5945d66dc 3 3 3 2m34s
NAME READY STATUS RESTARTS AGE
pod/nginx-deployment-5945d66dc-28c44 1/1 Running 0 2m34s
pod/nginx-deployment-5945d66dc-8w4qv 1/1 Running 0 2m34s
pod/nginx-deployment-5945d66dc-s2nsh 1/1 Running 0 2m34s
K8s 各資源類型縮寫對照表︰
deploy ︰deployment
rs︰replicaset
pods︰pod
svc ︰service
cm︰configmap
secret︰ secret
pv ︰ persistentvolume
pvc ︰ persistentvolumeclaim
擴縮容操作
# 擴展到 5 個副本
kubectl scale deployment nginx-deployment --replicas=5
# 縮減到 2 個副本
kubectl scale deployment nginx-deployment --replicas=2
# 即時觀察變化
kubectl get deployments -w
kubectl get pods -w
更新和回滾
# 更新映像檔版本
kubectl set image deployment/nginx-deployment nginx=nginx:1.21
# 查看更新狀態
kubectl rollout status deployment/nginx-deployment
# 查看更新歷史
kubectl rollout history deployment/nginx-deployment
# 回滾到上一個版本
kubectl rollout undo deployment/nginx-deployment
# ========== 原始 Pod YAML ==========
apiVersion: v1
kind: Pod
metadata:
name: my-web-app
labels:
app: web-app
spec: # 🔥 這整塊內容
containers: # 🔥 需要在 Deployment 中重複
- name: nginx # 🔥
image: nginx:1.20 # 🔥
ports: # 🔥
- containerPort: 80 # 🔥
env: # 🔥
- name: NODE_ENV # 🔥
value: "production" # 🔥
resources: # 🔥
requests: # 🔥
memory: "128Mi" # 🔥
cpu: "100m" # 🔥
limits: # 🔥
memory: "256Mi" # 🔥
cpu: "200m" # 🔥
volumes: # 🔥
- name: config-volume # 🔥
configMap: # 🔥
name: app-config # 🔥
restartPolicy: Always # 🔥
---
# ========== Deployment YAML ==========
apiVersion: apps/v1
kind: Deployment
metadata:
name: web-app-deployment
spec:
replicas: 3
selector:
matchLabels:
app: web-app
template: # 📦 這是包裝紙
metadata: # 📦 包裝上的標籤
labels:
app: web-app
spec: # 🔥 又要寫一遍相同內容!
containers: # 🔥 完全重複!
- name: nginx # 🔥
image: nginx:1.20 # 🔥
ports: # 🔥
- containerPort: 80 # 🔥
env: # 🔥
- name: NODE_ENV # 🔥
value: "production" # 🔥
resources: # 🔥
requests: # 🔥
memory: "128Mi" # 🔥
cpu: "100m" # 🔥
limits: # 🔥
memory: "256Mi" # 🔥
cpu: "200m" # 🔥
volumes: # 🔥
- name: config-volume # 🔥
configMap: # 🔥
name: app-config # 🔥
restartPolicy: Always # 🔥
# 😤 90% 的內容都重複了!
小弟我在之前有篇文章介紹 YAML時,有個技巧是Anchor錨點& 與 Alias引用*
這裡剛好能用此技巧來重構,重複利用 Pod 的規格內容。
# ========== 共用配置檔案 ==========
# shared-pod-spec.yaml
# 🎯 定義可重用的 Pod 規格
x-pod-spec: &pod-spec # 定義 anchor
containers:
- name: nginx
image: nginx:1.20
ports:
- containerPort: 80
env:
- name: NODE_ENV
value: "production"
resources:
requests:
memory: "128Mi"
cpu: "100m"
limits:
memory: "256Mi"
cpu: "200m"
volumes:
- name: config-volume
configMap:
name: app-config
restartPolicy: Always
# 🎯 定義可重用的標籤
x-labels: &common-labels
app: web-app
version: v1.0
tier: frontend
---
# ========== Pod YAML (使用重用配置) ==========
apiVersion: v1
kind: Pod
metadata:
name: my-web-app
labels: *common-labels # 🎯 引用 anchor
spec: *pod-spec # 🎯 引用 anchor
---
# ========== Deployment YAML (使用重用配置) ==========
apiVersion: apps/v1
kind: Deployment
metadata:
name: web-app-deployment
labels: *common-labels # 🎯 引用 anchor
spec:
replicas: 3
selector:
matchLabels:
app: web-app # 🎯 只需要關鍵標籤
template:
metadata:
labels: *common-labels # 🎯 引用 anchor
spec: *pod-spec # 🎯 引用 anchor
# 😊 結果:只寫一次,到處重用!
因為很可能同一個 namepsace 下的不同的 Deployment 的 pod,卻有同樣的label。
# 🏭 Deployment A
apiVersion: apps/v1
kind: Deployment
metadata:
name: factory-a-deployment
spec:
replicas: 2
# ❓ 如果沒有 selector,我怎麼知道哪些 Pod 是我的?
template:
metadata:
labels:
app: nginx
factory: a
spec:
containers:
- name: nginx
image: nginx:1.29
---
# 🏭 Deployment B
apiVersion: apps/v1
kind: Deployment
metadata:
name: factory-b-deployment
spec:
replicas: 2
# ❓ 如果沒有 selector,我怎麼知道哪些 Pod 是我的?
template:
metadata:
labels:
app: nginx # 🚨 同樣的 app 標籤!
factory: b
spec:
containers:
- name: nginx
image: nginx:1.21 # 不同版本
所以會希望能透過 select 比對多個標籤。
selector: # 🎯 我的身份證檢查器
matchLabels:
app: nginx
factory: a # 🏷️ 必須有這個標籤才是我的
今天我學習到了 Deployment,算是 Pod 的下一步, Pod 幫助我們知道怎如同 compose 中去定義一個容器的詳細規格,而 Deployment 能讓我們方便去定義管理版本跟副本數量。