Kubernetes Node 節點管理與維護

Node (節點) 是 Kubernetes 叢集中實際運作負載的工作機器,可以是一台實體機 (Bare Metal) 或虛擬機 (VM)。每個 Node 都由 Control Plane (控制平面) 管理。

Node 架構簡介

一個標準的 Node 包含以下關鍵組件,確保 Pod 能夠運行:

  1. Kubelet: Node 上的代理人 (Agent)。負責與 Control Plane 溝通,接收 PodSpec 並確保容器在健康狀態。
  2. Kube-proxy: 負責維護網路規則 (Network Rules),實現 Service 的負載平衡與網路轉發。
  3. Container Runtime: 負責真正運行容器的軟體 (例如 containerd, Docker Engine, CRI-O)。

監控 Node 狀態 (Status)

了解 Node 的狀態對於叢集運維至關重要。

查看節點列表

kubectl get nodes -o wide

輸出範例:

NAME       STATUS   ROLES           AGE   VERSION   INTERNAL-IP    OS-IMAGE
minikube   Ready    control-plane   10d   v1.28.3   192.168.49.2   Ubuntu 22.04
node-1     Ready    <none>          10d   v1.28.3   192.168.49.3   Ubuntu 22.04
  • STATUS: 最重要的欄位。Ready 表示節點健康且準備好接收 Pod。NotReady 表示節點失聯、網路中斷或 Kubelet 掛掉。

查看節點詳細健康指標

當 Node 發生問題時,使用 describe 查看詳細狀態與事件:

kubectl describe node <node-name>

重點觀察 Conditions 區塊,這裡反映了節點的資源壓力:

Condition TypeStatus正常值說明
ReadyTrue/FalseTrueKubelet 健康且可接收 Pod。
DiskPressureTrue/FalseFalse磁碟空間或 Inode 不足。若為 True,K8s 會開始垃圾回收或驅逐 Pod。
MemoryPressureTrue/FalseFalse記憶體不足。若為 True,可能會發生 OOM Killing。
PIDPressureTrue/FalseFalse進程數量過多 (Process ID 耗盡)。
NetworkUnavailableTrue/FalseFalse網路配置異常。

資源容量:Capacity vs Allocatable

kubectl describe node 中,你會看到兩個重要的資源指標:

  • Capacity (總容量): 該機器的實體資源總量 (例如 4 CPU, 16GB RAM)。
  • Allocatable (可分配量):扣除 OS 與 K8s 系統組件 (System Reserved) 後,真正能給 Pod 使用的資源量
調度器 (Scheduler) 是根據 Allocatable 來判斷節點是否還有空間塞 Pod。

節點維護操作 (Maintenance)

在真實的運維場景中,我們經常需要對節點進行維護(例如:升級 OS Kernel、更換硬體)。這時就需要用到 CordonDrain

Step 1: 暫停排程 (Cordon)

如果你希望某個節點 「暫時不要再接收新的 Pod」,但舊的 Pod 繼續運行,可以使用 cordon 指令。這會將節點標記為 Unschedulable (不可排程)。

# 禁止 Pod 調度到 node-1
kubectl cordon node-1

# 查看狀態,會顯示 SchedulingDisabled
kubectl get nodes
# NAME     STATUS                     ROLES    AGE
# node-1   Ready,SchedulingDisabled   <none>   10d

Step 2: 安全驅逐 (Drain)

如果你要對節點進行重開機或停機維護,必須確保上面的 Pod 被安全地遷移到其他節點。

drain 會做兩件事:

  1. 自動執行 cordon
  2. 安全地驅逐 (Evict) 該節點上的 Pod(優雅終止),讓控制器 (Deployment/StatefulSet) 在其他節點重建它們。
# 驅逐 node-1 上的所有 Pod
# --ignore-daemonsets: 忽略 DaemonSet 管理的 Pod (DaemonSet 不可驅逐,因為它每個節點都要有一份)
# --delete-emptydir-data: 允許刪除使用 emptyDir 的 Pod (警告:暫存資料會遺失)
kubectl drain node-1 --ignore-daemonsets --delete-emptydir-data

Step 3: 恢復排程 (Uncordon)

當維護完成,節點重新上線後,記得解除封鎖,讓 Pod 可以再次調度過來。

kubectl uncordon node-1

標籤 (Labels) 與 選擇器 (Selector)

Label 是 Kubernetes 調度的核心。我們可以為 Node 打上標籤,讓特定的 Pod 指定跑在這些節點上。

管理 Node Labels

# 新增標籤: 標記 node-1 為 SSD 節點
kubectl label nodes node-1 disktype=ssd

# 查看標籤
kubectl get nodes --show-labels

# 移除標籤: Key 後面加上減號
kubectl label nodes node-1 disktype-

Pod 如何指定節點 (Node Selector)

在 Pod 的 YAML 中使用 nodeSelector

apiVersion: v1
kind: Pod
metadata:
  name: nginx
spec:
  containers:
    - name: nginx
      image: nginx
  # 指定只跑在有 disktype=ssd 標籤的節點上
  nodeSelector:
    disktype: ssd

汙點 (Taints) 與 容忍 (Tolerations)

  • Label/NodeSelector: 是 Pod 主動 「選擇」 去某個節點 (吸鐵石)。
  • Taint/Toleration: 是節點主動 「排斥」 Pod (驅蟲劑)。除非 Pod 有「抗體」(Toleration),否則進不來。

這常用於保留專用節點(例如:GPU 運算節點、Master 節點)。

設定 Taint (節點端)

# 格式: key=value:Effect
# Effect: NoSchedule (不給排), NoExecute (驅逐既有), PreferNoSchedule (盡量不排)
kubectl taint nodes node-1 gpu=true:NoSchedule

此時,一般的 Pod 若沒設定 toleration,就無法被調度到 node-1

設定 Toleration (Pod 端)

若要讓 Pod 能跑在有汙點的節點上,需在 YAML 加入 tolerations

apiVersion: v1
kind: Pod
metadata:
  name: deep-learning-pod
spec:
  containers:
    - name: cuda-container
      image: nvidia/cuda:11.0
      resources:
        limits:
          nvidia.com/gpu: 1
  tolerations:
    # 只要節點有 key="gpu" 且 effect="NoSchedule",我就能忍受
    - key: 'gpu'
      operator: 'Exists'
      effect: 'NoSchedule'

常見問題排查 (Troubleshooting)

Node 狀態為 NotReady

  1. 檢查 Kubelet: Kubelet 是否掛了?
    • SSH 到該節點,執行 systemctl status kubelet
  2. 檢查磁碟空間:
    • df -h 查看是否磁碟滿了。
  3. 檢查資源壓力:
    • kubectl describe node <node-name> 查看 Conditions 是否有 MemoryPressure 或 DiskPressure。