Kubernetes Limit / Request 使用指南
Kubernetes Limit / Request 使用指南
在 Kubernetes 部署應用程式時,resources.requests 與 resources.limits 是很重要的設定。它們會影響 Pod 是否能被排程、容器最多能使用多少 CPU 與記憶體,以及命名空間內的資源是否會被合理控管。
這篇文章會透過三份測試配置檔,依序觀察以下幾件事:
- 只在 Deployment 內設定
requests與limits - 使用
LimitRange統一限制命名空間內的單一容器資源範圍 - 使用
ResourceQuota控制整個命名空間的資源總配額
什麼是 requests 與 limits?
在 Kubernetes 的容器設定中,可以透過 resources 宣告 CPU 與記憶體需求:
1 | resources: |
requests 是容器啟動前向 Kubernetes 宣告的最低資源需求。Scheduler 會根據這個數值判斷目前有哪些 Node 還有足夠的可配置資源可以放置 Pod。如果 requests 超過 Node 剩餘可配置資源,Pod 就會停留在 Pending,並在事件中看到類似 Insufficient cpu 或 Insufficient memory 的訊息。
limits 則是容器可使用資源的上限。CPU 超過 limits 時通常會被節流,記憶體超過 limits 時則可能被 OOMKilled。也就是說,requests 主要影響排程,limits 則影響容器執行時的資源邊界。
CPU 常用 m 表示 millicore,例如 250m 代表 0.25 顆 CPU,1000m 代表 1 顆 CPU。記憶體常用 Mi、Gi 表示,例如 512Mi、2Gi。
測試一:只設定 Deployment resources
第一份配置檔 dockertest_resource_v1.yml 建立了 dockertest Namespace、Registry Secret、Deployment 與 ClusterIP Service。Deployment 中的容器設定了基本的 requests 與 limits:
1 | resources: |
套用配置檔:
1 | kubectl apply -f dockertest_resource_v1.yml |
套用完成後,可以看到 Namespace、Secret、Deployment 與 Service 都成功建立,Pod 也正常進入 Running 狀態。
接著檢查 Deployment 的設定,可以看到容器內已經有 limits 與 requests。在這個測試中,Pod 有明確宣告資源需求,因此 Kubernetes 可以依據 requests 進行排程。
如果將 Deployment 的 CPU 與記憶體需求手動調得太高,例如 requests 與 limits 都設定成超過單一 Node 可提供的資源,就會建立出新的 ReplicaSet,但新的 Pod 會停在 Pending。
從 kubectl describe pod 的事件可以看到:
1 | 0/1 nodes are available: 1 Insufficient cpu, 1 Insufficient memory. |
這代表 Scheduler 找不到符合 requests 條件的 Node,因此 Pod 無法被排程。這個狀況不是容器啟動失敗,而是 Kubernetes 在排程階段就判斷資源不足。
測試二:使用 LimitRange 控制單一容器資源範圍
第二份配置檔 dockertest_resource_v2.yml 在同一個 Namespace 中加入 LimitRange:
1 | apiVersion: v1 |
LimitRange 是命名空間層級的限制,用來規範單一容器可以設定的資源範圍。它有幾個常見用途:
max:限制單一容器可設定的最大 limitsmin:限制單一容器可設定的最小 requests 或 limitsdefault:容器沒有設定 limits 時,自動補上的預設 limitsdefaultRequest:容器沒有設定 requests 時,自動補上的預設 requests
套用第二份配置檔:
1 | kubectl apply -f dockertest_resource_v2.yml |
套用後可以看到 limitrange/dockertest-limitrange 被建立,Deployment 與 Service 也正常建立。
建立完成後,可以使用 kubectl get limitrange 查看 Namespace 內有哪些 LimitRange:
1 | kubectl get limitrange -n dockertest |
如果要確認 LimitRange 實際套用的 min、max、default 與 defaultRequest,可以使用 kubectl describe limitrange:
1 | kubectl describe limitrange dockertest-limitrange -n dockertest |
也可以輸出完整 YAML,確認 Kubernetes 儲存的資源內容:
1 | kubectl get limitrange dockertest-limitrange -n dockertest -o yaml |
在目前這份 v2 設定中,Deployment 的容器 requests 與 limits 都落在 LimitRange 允許的範圍內,所以 Pod 可以正常啟動。
如果後續把 Deployment 的 CPU limit 調高到超過 LimitRange 的 max.cpu,Kubernetes 會直接拒絕建立 Pod。這時候錯誤會出現在 ReplicaSet 的事件中,而不是讓 Pod 進入 Pending。
從畫面中的事件可以看到類似訊息:
1 | Error creating: pods "dockertest-deployment-..." is forbidden: |
這表示限制是在 API Server admission 階段生效。也就是說,LimitRange 不是用來判斷 Node 有沒有資源,而是用來檢查使用者提交的容器資源設定是否符合命名空間規範。
測試三:使用 ResourceQuota 控制命名空間總配額
第三份配置檔 dockertest_resource_v3.yml 同時加入 ResourceQuota 與 LimitRange。LimitRange 控制單一容器的資源範圍,而 ResourceQuota 控制整個 Namespace 的 requests 與 limits 加總:
1 | apiVersion: v1 |
這份設定代表 dockertest Namespace 內所有 Pod 的資源宣告加總不得超過:
| 項目 | 上限 |
|---|---|
requests.cpu |
2 |
requests.memory |
4Gi |
limits.cpu |
4 |
limits.memory |
8Gi |
同時,v3 的 Deployment 將副本數設定為 4,每個 Pod 的資源設定如下:
1 | replicas: 4 |
每個 Pod 的 CPU limit 是 1000m,也就是 1 顆 CPU。4 個副本加總後剛好是 4 顆 CPU,符合 limits.cpu: "4" 的 ResourceQuota 設定,因此可以正常建立。
1 | kubectl apply -f dockertest_resource_v3.yml |
建立完成後,可以使用 kubectl get resourcequotas 查看 Namespace 內有哪些 ResourceQuota:
1 | kubectl get resourcequotas -n dockertest |
如果要確認目前配額的 Used 與 Hard 數值,可以使用 kubectl describe resourcequota。這個指令很適合用來觀察目前 requests 與 limits 已經宣告了多少,以及是否接近 Namespace 的配額上限:
1 | kubectl describe resourcequota dockertest-resourcequota -n dockertest |
也可以用 YAML 形式查看完整設定:
1 | kubectl get resourcequota dockertest-resourcequota -n dockertest -o yaml |
套用後可以看到 4 個 Pod 都正常進入 Running,Deployment 也顯示 4/4。
接著如果將 Deployment scale 到 5 個副本,第 5 個 Pod 會讓 Namespace 內的 limits.cpu 加總變成 5 顆 CPU,超過 ResourceQuota 設定的 4 顆 CPU,因此新的 Pod 會被拒絕建立。
1 | kubectl scale deployment dockertest-deployment --replicas=5 -n dockertest |
在 ReplicaSet 事件中可以看到:
1 | exceeded quota: dockertest-resourcequota, |
這代表目前 Namespace 已經用滿 limits.cpu 配額,因此 ReplicaSet 無法再建立新的 Pod。
LimitRange 與 ResourceQuota 的差異
LimitRange 與 ResourceQuota 都是 Namespace 層級的資源治理工具,但它們負責的範圍不同。
| 項目 | LimitRange | ResourceQuota |
|---|---|---|
| 控制對象 | 單一 Pod 或單一容器 | 整個 Namespace |
| 常見用途 | 設定預設 requests/limits、限制單一容器最小與最大資源 | 限制 Namespace 內所有 Pod 的資源總量 |
| 超出限制時 | Pod 建立請求被拒絕 | 超出總配額的新 Pod 建立請求被拒絕 |
| 是否看 Node 剩餘資源 | 否 | 否 |
| 是否影響 Scheduler 排程 | 間接影響,因為會補上或限制 requests | 間接影響,因為限制可建立的總資源宣告 |
簡單來說,LimitRange 像是單一容器的規格表,避免有人建立過小或過大的容器;ResourceQuota 則像是整個 Namespace 的預算表,避免某個專案把整個叢集資源宣告用光。
常見觀察重點
在這次測試中,可以整理出幾個重要結論:
requests會影響 Pod 是否能被 Scheduler 排到 Node 上limits會限制容器執行時最多能使用多少 CPU 與記憶體- requests 超過 Node 可配置資源時,Pod 會維持
Pending - 超過
LimitRange的單一容器限制時,Pod 建立會直接被拒絕 - 超過
ResourceQuota的 Namespace 總配額時,新的 Pod 建立會被拒絕 LimitRange與ResourceQuota都不等於 Node 實際剩餘資源,它們檢查的是資源宣告是否符合規範
因此,在實務上通常會同時使用三層設定:
- 在 Deployment 中明確設定每個容器的
requests與limits - 在 Namespace 中使用
LimitRange建立預設值與單一容器上下限 - 在 Namespace 中使用
ResourceQuota控制整體資源使用額度
這樣可以讓應用程式部署時有明確的排程依據,也能避免單一服務或單一命名空間過度宣告資源,影響同一個叢集中的其他工作負載。