到目前為止,我們學了很多「怎麼建東西」—— Deployment、Service、ConfigMap、PV、StatefulSet……
但有一個問題我們一直沒問:
當你
kubectl apply一個 Pod,Kubernetes 是怎麼決定它要跑在哪個 Node 上的?
你可能以為 Pod 是「隨機分配」到某個 Node,但其實不是
Kubernetes 背後有一個專門負責排程的元件 —— kube-scheduler,它會根據 Pod 的需求與各個 Node 的狀態,挑選適合這個 Pod 執行的 Node
如果 Scheduler 找不到符合條件的 Node,Pod 就會維持在 Pending 狀態,直到出現可以被排程的 Node
今天會學:
以下操作皆在 master 節點 執行。
先來動手製造一個「卡住」的 Pod,直接觀察 Pod 進入 Pending 狀態時會發生什麼事。
建立一個指定不存在 Node 標籤的 Pod:
vim pending-demo.yaml
apiVersion: v1
kind: Pod
metadata:
name: pending-demo
spec:
nodeSelector:
gpu: "true" # 指定要有 gpu=true 標籤的 Node(但我們的叢集沒有)
containers:
- name: nginx
image: nginx
kubectl apply -f pending-demo.yaml
查看狀態:
kubectl get pods

Pod 一直 Pending,不是 Running、不是 Error,就是卡著不動。
用 describe 看看發生什麼事:
kubectl describe pod pending-demo
在 Events 區塊會看到類似這樣的訊息:

丟一個問題給你思考:
Ready
Pending?答案就是:
Scheduler 找不到符合 Pod 排程條件的 Node。
Node 顯示 Ready,只代表這個 Node 目前可以正常工作,並不代表它一定符合這個 Pod 的排程需求。
在這個例子中,我們透過 nodeSelector 要求 Node 必須具備gpu=true
但叢集中沒有任何 Node 符合這個條件,因此 Scheduler 在 Filtering 階段就會把所有 Node 排除掉,Pod 最後只能停在 Pending。
造成 Pod Pending 的原因還有很多,例如:
這些都是 Scheduler 在排程 Pod 時會檢查的項目。
kube-scheduler 的排程邏輯可以簡化成三個階段:

第一步可以把它想成淘汰賽 —— Scheduler 會先把不符合 Pod 排程條件的 Node 全部排除。
常見的淘汰原因包括:
requests
nodeSelector,但 Node 沒有符合的標籤hostPort 已經被該 Node 上其他 Pod 佔用如果 Filtering 結束後沒有任何 Node 符合條件,Pod 就會維持在 Pending 狀態。
通過 Filtering 的 Node 會進入評分階段。
Scheduler 會透過多種 Scoring Plugin 幫候選 Node 計算分數,例如:
Scheduler 會綜合各項評分結果,最後從分數最高的候選 Node 中選出一個來執行 Pod。
Scheduler 選定最適合的 Node 後,會透過 API Server 完成 Binding,把這個 Pod 指派到指定的 Node。
這個結果會反映在 Pod 的spec.nodeName欄位中。
接著,該 Node 上的 kubelet 會發現有新的 Pod 被指派給自己,開始進行後續工作,例如:
到這一步,Pod 才真正開始在選定的 Node 上執行。
💡 一句話總結
Scheduler 不是隨機分配 Pod,而是經過 Filtering(篩選)→ Scoring(評分)→ Binding(綁定) 的流程,最後將 Pod 排程到符合條件且評分較高的 Node 上。
知道了 Scheduler 會先篩選 Node,那它是怎麼判斷「這台 Node 的資源夠不夠」的?
關鍵就在 Pod 設定的 Requests 和 Limits。
其中:
所以在排程階段,Scheduler 最主要看的其實是 requests。
想像你要訂飯店房間:
對應到 Kubernetes:
| 比較項目 | Requests(請求) | Limits(限制) |
|---|---|---|
| 主要作用階段 | 排程階段 | Pod 執行階段 |
| 意思 | Pod 表示:「我需要保留這麼多資源」 | Container 表示:「我最多可以使用這麼多資源」 |
| Scheduler 會不會看? | 會,Scheduler 主要根據 requests 判斷 Node 是否有足夠資源 |
通常不作為排程容量判斷的主要依據 |
| CPU 超過時 | — | 可能被 Throttle(限速),不會因為單純超過 CPU Limit 而被終止 |
| Memory 超過時 | — | 可能觸發 OOMKilled,Container 被終止 |
| 沒有設定時 | 如果沒有其他機制補上預設值,Scheduler 可能低估 Pod 的資源需求 | Container 沒有設定對應上限,可能使用更多 Node 資源 |
apiVersion: v1
kind: Pod
metadata:
name: resource-demo
spec:
containers:
- name: nginx
image: nginx
resources:
requests: # Scheduler 排程依據
cpu: "250m" # 0.25 個 CPU 核心
memory: "128Mi" # 128 MiB 記憶體
limits: # 運行時的上限
cpu: "500m" # 最多 0.5 個 CPU 核心
memory: "256Mi" # 最多 256 MiB 記憶體
CPU 單位補充
1= 1 個 CPU 核心500m= 0.5 個 CPU 核心250m= 0.25 個 CPU 核心其中
m代表 millicpu,1000m = 1 CPU。Memory 單位補充
Mi= MiB(Mebibyte,2^20bytes)Gi= GiB(Gibibyte,2^30bytes)Kubernetes 也支援
M、G等十進位單位,但它們和Mi、Gi代表的容量不同。例如:
512Mi、1Gi
先了解叢集有多少資源可用:
kubectl describe nodes | grep -A 5 "Allocatable"
或者更清楚地看單一 Node:
kubectl describe node <node-name>
在輸出中找到兩個關鍵區塊:

requests / limits 加總從 Allocatable 可以看出,這台 Node 目前大約可以提供 2 CPU、4Gi Memory 給 Pod 使用。
這裡顯示的是 Node 可分配給 Pod 的資源總量,至於目前已經有多少資源被 Pod 的 requests / limits 使用,則需要查看 kubectl describe node 中的 Allocated resources 區塊。
vim resource-demo.yaml
apiVersion: v1
kind: Pod
metadata:
name: resource-demo
spec:
containers:
- name: nginx
image: nginx
resources:
requests:
cpu: "250m"
memory: "128Mi"
limits:
cpu: "500m"
memory: "256Mi"
kubectl apply -f resource-demo.yaml
確認 Pod 正常運行:
kubectl get pod resource-demo -o wide
-o wide 會顯示 Pod 被排程到哪個 Node。

現在試試部署一個「要求超大資源」的 Pod:
vim greedy-pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: greedy-pod
spec:
containers:
- name: nginx
image: nginx
resources:
requests:
cpu: "100" # 要求 100 個 CPU 核心!
memory: "128Gi" # 要求 128 GiB 記憶體!
kubectl apply -f greedy-pod.yaml
查看狀態:
kubectl get pod greedy-pod

果然,Pod 進入了 Pending 狀態!
接著用 describe 看看 Scheduler 為什麼無法完成排程:
kubectl describe pod greedy-pod
會在 Events 中看到:

意思是:目前沒有任何 Node 同時具備足夠的 CPU 與 Memory 來滿足這個 Pod 的 requests。
因此 Scheduler 在 Filtering 階段就會把所有不符合資源需求的 Node 排除,Pod 最後只能維持在 Pending 狀態。
如果你的叢集有安裝 Metrics Server,可以用:
kubectl top nodes

這裡顯示的是 Node 目前 CPU 與 Memory 的實際使用量,不是 Pod 宣告的 requests。
⚠️ Scheduler 看的是 Requests,不是實際使用量!
即使一台 Node 的實際 CPU 使用率只有 10%,如果上面已經排程的 Pod,其 CPU
requests加總已經接近或達到 Node 的可分配容量,Scheduler 就可能無法再把新的 Pod 排進去。這就像飯店的房間已經被預訂了,即使房客還沒入住,新客人也不能再訂同一間房。
如果沒有設定 requests:
如果沒有設定 limits:
在生產環境中,建議至少合理設定 Requests,讓 Scheduler 能正確判斷資源需求;是否設定 Limits,則應依應用程式特性與資源管理策略決定。
如果應用程式實際只需要約 100m CPU,但 requests 卻設定成 2000m:
Pending
所以 requests 不宜隨意設得過高,應根據應用程式實際需求與監控數據進行調整。
如果 limits 設得太低,CPU 和 Memory 會有不同的結果:
可以用以下指令排查是否曾經發生 OOMKilled:
kubectl get pod <pod-name> -o jsonpath='{.status.containerStatuses[0].lastState}'
如果看到類似:
reason: OOMKilled
就代表 Container 曾經因為超過 Memory Limit 而被 OOM Kill,需要重新評估記憶體需求與 limits 設定。
今天我們學會了 Kubernetes 的排程與資源管理機制:
| 重點 | 說明 |
|---|---|
| Scheduler 三階段 | Filtering(篩選)→ Scoring(評分)→ Binding(綁定) |
| Requests | Pod 宣告的資源需求,是 Scheduler 判斷 Node 是否有足夠資源的重要依據 |
| Limits | Container 的資源使用上限,CPU 超過可能被 Throttling,Memory 超過可能被 OOMKilled |
| Pod Pending | 可能是 Scheduler 在 Filtering 階段找不到符合條件的 Node |
| 資源觀察 | kubectl top 看實際使用量,kubectl describe node 可查看 Requests / Limits 的配置情況 |
現在我們知道 Scheduler 會根據各種條件篩選 Node,但如果想要更精確地控制 Pod 該跑在哪裡呢?
例如:
明天我們來學 Taints & Tolerations 與 Node Affinity,看看 Kubernetes 如何用更細緻的規則控制 Pod 的排程位置!