Kubernetes Node 節點管理與維護
Node (節點) 是 Kubernetes 叢集中實際運作負載的工作機器,可以是一台實體機 (Bare Metal) 或虛擬機 (VM)。每個 Node 都由 Control Plane (控制平面) 管理。
Node 架構簡介
一個標準的 Node 包含以下關鍵組件,確保 Pod 能夠運行:
- Kubelet: Node 上的代理人 (Agent)。負責與 Control Plane 溝通,接收 PodSpec 並確保容器在健康狀態。
- Kube-proxy: 負責維護網路規則 (Network Rules),實現 Service 的負載平衡與網路轉發。
- 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 Type | Status | 正常值 | 說明 |
|---|---|---|---|
| Ready | True/False | True | Kubelet 健康且可接收 Pod。 |
| DiskPressure | True/False | False | 磁碟空間或 Inode 不足。若為 True,K8s 會開始垃圾回收或驅逐 Pod。 |
| MemoryPressure | True/False | False | 記憶體不足。若為 True,可能會發生 OOM Killing。 |
| PIDPressure | True/False | False | 進程數量過多 (Process ID 耗盡)。 |
| NetworkUnavailable | True/False | False | 網路配置異常。 |
資源容量:Capacity vs Allocatable
在 kubectl describe node 中,你會看到兩個重要的資源指標:
- Capacity (總容量): 該機器的實體資源總量 (例如 4 CPU, 16GB RAM)。
- Allocatable (可分配量):扣除 OS 與 K8s 系統組件 (System Reserved) 後,真正能給 Pod 使用的資源量。
調度器 (Scheduler) 是根據 Allocatable 來判斷節點是否還有空間塞 Pod。
節點維護操作 (Maintenance)
在真實的運維場景中,我們經常需要對節點進行維護(例如:升級 OS Kernel、更換硬體)。這時就需要用到 Cordon 與 Drain。
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 會做兩件事:
- 自動執行
cordon。 - 安全地驅逐 (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
- 檢查 Kubelet: Kubelet 是否掛了?
- SSH 到該節點,執行
systemctl status kubelet。
- SSH 到該節點,執行
- 檢查磁碟空間:
df -h查看是否磁碟滿了。
- 檢查資源壓力:
kubectl describe node <node-name>查看 Conditions 是否有 MemoryPressure 或 DiskPressure。