iT邦幫忙

2025 iThome 鐵人賽

DAY 4
3

賢者大叔的容器修煉手札系列 第 4 篇

前情提要:昨天我們理解了 Pod 跟 Pod YAML,但似乎還不知道 K8s 是怎麼管理跟擴容 pod 的。

📚 今日學習目標

從手動管理 Pod 到自動化的 Deployment 管理

🎯 學習成果

✅ 理解什麼是 Deployment 及其作用
✅ 掌握 Deployment 與 Pod 的關係
✅ 學會建立和管理基本的 Deployment
✅ 熟悉常用的 Deployment 操作指令

🤔 從 Docker Compose 開始理解

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:

https://ithelp.ithome.com.tw/upload/images/20250818/20104930G1KMRBrP3z.png

現實世界的比喻
想像你從經營單一分店升級到連鎖店:

場景 Docker Compose Kubernetes Deployment
規模 🏪 單一分店 🏢 連鎖店集團
人員管理 👨‍💼 店長手動排班 🤖 總部自動調配人力
故障處理 📞 店長接到通知才處理 🚨 系統自動派遣替補
擴展 🔨 需要重新裝潢 ⚡ 自動開設新分店
更新 🚪 暫停營業更新 🔄 分批更新不停業

🤔 為什麼需要 Deployment?

現實世界的比喻

想像你經營一家 24 小時便利商店:
https://ithelp.ithome.com.tw/upload/images/20250818/20104930SUJiQRdpKS.png

手動管理 Pod 的痛點

# 😰 手動管理的噩夢
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?

Deployment 是 K8s 中一種聲明式控制器,用來管理跟維護一組 Pod 副本。主要適用於管理 stateless application 的生命週期。通過 Deploment 聲明,可以自動地控制 application 的副本數量、進行 zero down time更新、擴縮容等。

關於 stateless application,能參考小弟之前的文章無狀態服務

簡單比喻

想像你是餐廳老闆:

  • Pod = 一個服務員
  • Deployment = 人事經理,負責管理所有服務員

https://ithelp.ithome.com.tw/upload/images/20250818/20104930cXhJjPAAeM.png

Deployment 自動幫你:

  • ✅ Pod 掛了自動重啟
  • ✅ 想要 3 個副本就維持 3 個
  • ✅ 更新應用不用停機

Pod、ReplicaSet 和 Deployment 三者的關係

https://ithelp.ithome.com.tw/upload/images/20250818/20104930zjmMFxok1q.png

各層職責詳解

層級 角色比喻 主要職責 管理範圍
Deployment 🎯 總經理 制定策略、版本管理、滾動更新 管理多個 ReplicaSet
ReplicaSet 📋 部門經理 維持人員數量、監控狀態 管理多個 Pod
Pod 🏃 員工 執行實際工作 運行容器

這樣的三層架構,其實在 Docker compose 設計時就有類似的概念能對照了。
https://ithelp.ithome.com.tw/upload/images/20250818/20104930luJz7FsDxU.png

📝 Deployment YAML 解析

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 欄位說明

  • replicas: 想要的 Pod 數量
  • selector: 告訴 Deployment 要管理哪些 Pod
  • template: Pod 的模板,就像 Day 3 學的 Pod YAML

https://ithelp.ithome.com.tw/upload/images/20250818/20104930k8crxWdZwN.png

實際動手玩

🛠️ 基本操作

部署和查看

# 建立 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了,這裡的 YAML 有跟POD的內容重複?

# ========== 原始 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

# 😊 結果:只寫一次,到處重用!

Deployment 內都標明是這些Container了,還需要 Selector?

因為很可能同一個 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 能讓我們方便去定義管理版本跟副本數量。

https://ithelp.ithome.com.tw/upload/images/20250819/20104930Ebv8XvNGoA.png


上一篇
Pod YAML 詳解與實作
下一篇
Deployment 進階 - Affinity 機制
系列文
賢者大叔的容器修煉手札17
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言