K8s · 工作負載 · 第 16 課 · · 9min read

K8s 自我修復原理:Labels 和 Selector 在做什麼?

為什麼 delete pod 之後 K8s 自動補一個?因為 Deployment 用 selector 一直在數「我管的 label 有幾個 Pod」,少一個就補一個。這篇用 label 拆穿 K8s 的魔法。

#Kubernetes #自我修復 #Labels #Selector
章節目錄 · 12

Deployment 怎麼知道哪些 Pod 屬於自己?

Deployment 你已經會用了。但有沒有想過:

  • 你刪一個 Pod,Deployment 是怎麼發現少一個的?
  • 同一個叢集跑 nginx 跟 httpd 兩個 Deployment,K8s 怎麼分得出哪些 Pod 屬於誰
  • Pod 名字有 hash 不固定,Deployment 用什麼追蹤 Pod
答案不是 Pod 名字,而是 Labels(標籤)+ Selector(選擇器)。這是 K8s 整個資源關聯的核心機制。

Labels = Pod 上的便利貼

每個 Pod 都可以貼任意數量的 label:

metadata:
  name: my-nginx
  labels:
    app: nginx       # 應用名稱
    tier: frontend   # 層級
    env: prod        # 環境
    version: v1      # 版本

Label 是 key-value pair。愛貼幾個就貼幾個,K8s 不會限制。

Selector = 告訴 K8s「我要找哪些 Pod」

Deployment 用 selector 找自己的 Pod:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deploy
spec:
  replicas: 3
  selector:
    matchLabels:
      app: nginx     # 找 app=nginx 的 Pod
  template:
    metadata:
      labels:
        app: nginx   # template 建出來的 Pod 會有這個 label
    spec:
      containers:
      - name: nginx
        image: nginx:1.27

ReplicaSet 持續監控:「目前有幾個 app=nginx 的 Pod?少一個就建一個。」

⚠️ selector 跟 template labels 必須一致

這是 Deployment 最常踩的坑。

spec:
  selector:
    matchLabels:
      app: nginx       # 我要找 app=nginx
  template:
    metadata:
      labels:
        app: web       # ❌ 但建出的 Pod label 是 app=web

結果:

  • ReplicaSet 找不到自己建的 Pod(label 不符)
  • 以為「Pod 不夠」一直建新的
  • 永遠停不下來
寫 Deployment YAML 時務必檢查這兩處 label 一致。

自我修復的真正原理

1. Deployment 設 replicas: 3
   ↓
  • ReplicaSet 用 selector「app=nginx」找 Pod
  • 你 kubectl delete pod my-nginx-xxx
  • ReplicaSet 重新查:app=nginx 的 Pod 只剩 2 個
  • 期望 3 但實際 2 → 用 template 建一個新的
  • Deployment 從來不認 Pod 名字、只認 label。只要 label 對得上,新 Pod 就被「認領」。

    實作:手動驗證 label 機制

    kubectl create deployment nginx-deploy --image=nginx:1.27 --replicas=3
    

    # 看 Pod label
    kubectl get pods --show-labels
    # NAME ... LABELS
    # nginx-deploy-xxx-aaa ... app=nginx-deploy,pod-template-hash=xxx
    # nginx-deploy-xxx-bbb ... app=nginx-deploy,pod-template-hash=xxx
    # nginx-deploy-xxx-ccc ... app=nginx-deploy,pod-template-hash=xxx

    K8s 自動加了:

    • app=nginx-deploy(你的 selector)
    • pod-template-hash=xxx(給 ReplicaSet 區分版本用,滾動更新會看到不同 hash)

    用 label 篩選 Pod

    # 篩 app=nginx-deploy
    kubectl get pods -l app=nginx-deploy
    

    # 多個條件用逗號(AND)
    kubectl get pods -l app=nginx-deploy,tier=frontend

    # 反向選擇
    kubectl get pods -l app!=nginx-deploy

    實用場景:

    # 一次刪除所有 app=test 的 Pod
    kubectl delete pods -l app=test
    

    # 看所有 prod 環境的 Pod
    kubectl get pods --all-namespaces -l env=prod

    「孤兒 Pod」實驗

    如果你直接修改 Pod 的 label 把它跟 Deployment 切斷會怎樣?

    # 看一下 Deployment 跟 Pod
    kubectl get pods -l app=nginx-deploy
    # 3 個 Pod
    

    # 改其中一個 Pod 的 label,把 app 改成別的
    kubectl label pod nginx-deploy-xxx-aaa app=orphan --overwrite

    # 馬上看
    kubectl get pods -l app=nginx-deploy
    # 只剩 2 個!

    kubectl get pods
    # 但總共有 4 個 Pod!
    # nginx-deploy-xxx-aaa(label app=orphan) ← 孤兒,不歸 Deployment 管
    # nginx-deploy-xxx-bbb(label app=nginx-deploy)
    # nginx-deploy-xxx-ccc(label app=nginx-deploy)
    # nginx-deploy-xxx-NEW(label app=nginx-deploy) ← Deployment 補的新 Pod

    Deployment 看到 app=nginx-deploy 的 Pod 變 2 個,立刻補一個新的。原本那個 Pod 還活著、但 label 不符 → 變孤兒,Deployment 不再管它(你要自己 kubectl delete pod 殺掉)。

    這個實驗很清楚地展示了 K8s 的關聯都是 label 驅動的

    Service 也是用 label 找 Pod

    不只 Deployment,後面學的 Service 也一樣:

    apiVersion: v1
    kind: Service
    metadata:
      name: nginx-svc
    spec:
      selector:
        app: nginx     # ← 把流量送到所有 app=nginx 的 Pod
      ports:
      - port: 80

    label = K8s 整個世界的關聯機制。掌握 label 就掌握 K8s。

    自我修復的場景

    實際工作中 K8s 自我修復救過很多次:

    情境K8s 怎麼救
    Pod OOM 被 kernel killReplicaSet 補新 Pod
    Node 當機上面所有 Pod 被自動排到別台 Node
    你誤刪 Pod馬上補回來
    容器 crash 退出restartPolicy 重啟
    不需要你寫腳本、不需要你半夜爬起來,這就是 K8s 比 Docker 強的核心

    重點整理

    • K8s 用 label + selector 關聯資源(不認名字)
    • Deployment 的 selector.matchLabels 必須跟 template.metadata.labels 一致
    • ReplicaSet 持續監控 label 對得上的 Pod 數量,少了就補
    • kubectl get pods -l key=value 用 label 篩選
    • 改 Pod label 會讓它脫離 Deployment 變孤兒
    • Service 也用 label 找 Pod
    • 自我修復不是黑魔法,就是 ReplicaSet 持續比對 label 跟期望數量

    下一步

    Deployment + Pod 的故事告一段落。但外面怎麼連到 Pod?Pod IP 隨時會變、Pod 還會被 K8s 搬到別的 Node。下一篇進入 Service 的世界:ClusterIP:固定 IP 解決 Pod IP 飄忽問題