調整分配給容器的 CPU 和記憶體資源
Kubernetes v1.33 [beta] (預設啟用:true)此頁面介紹瞭如何更改分配給容器的 CPU 和記憶體資源請求和限制,**無需重新建立 Pod**。
傳統上,更改 Pod 的資源需求需要刪除現有 Pod 並建立替代 Pod,這通常由工作負載控制器管理。就地 Pod 調整大小允許在執行中的 Pod 內更改一個或多個容器的 CPU/記憶體分配,同時可能避免應用程式中斷。
關鍵概念
- 期望資源: 容器的
spec.containers[*].resources表示容器的**期望**資源,並且對於 CPU 和記憶體是可變的。 - 實際資源:
status.containerStatuses[*].resources欄位反映了執行中容器**當前配置**的資源。對於尚未啟動或已重新啟動的容器,它反映了下次啟動時分配的資源。 - 觸發調整: 你可以透過更新 Pod 規範中期望的
requests和limits來請求調整大小。這通常透過針對 Pod 的resize子資源使用kubectl patch、kubectl apply或kubectl edit來完成。當期望資源與已分配資源不匹配時,Kubelet 將嘗試調整容器大小。 - 已分配資源(高階):
status.containerStatuses[*].allocatedResources欄位跟蹤 Kubelet 確認的資源值,主要用於內部排程邏輯。對於大多數監控和驗證目的,請重點關注status.containerStatuses[*].resources。
如果節點上有處於待處理或不完整調整大小狀態的 Pod(請參閱下面的Pod 調整大小狀態),排程器在做出排程決策時會使用容器的期望請求、已分配請求和狀態中的實際請求的**最大值**。
準備工作
你需要擁有一個 Kubernetes 叢集,並且 kubectl 命令列工具必須配置為與你的叢集通訊。建議在至少有兩個不作為控制平面主機的節點叢集上執行此教程。如果你還沒有叢集,可以使用 minikube 建立一個,或者使用以下 Kubernetes 演練場之一
你的 Kubernetes 伺服器版本必須在 1.33 或更高。要檢查版本,請輸入 kubectl version。
InPlacePodVerticalScaling 特性門控必須為你的控制平面和叢集中的所有節點啟用。
kubectl 客戶端版本必須至少為 v1.32 才能使用 --subresource=resize 標誌。
Pod 調整大小狀態
Kubelet 更新 Pod 的狀態條件以指示調整大小請求的狀態
type: PodResizePending:Kubelet 無法立即批准請求。message欄位提供瞭解釋。reason: Infeasible:請求的調整大小在當前節點上不可能(例如,請求的資源超出節點擁有的資源)。reason: Deferred:請求的調整大小目前不可能,但以後可能會變得可行(例如,如果其他 Pod 被移除)。Kubelet 將重試調整大小。
type: PodResizeInProgress:Kubelet 已接受調整大小並分配了資源,但更改仍在應用中。這通常很短暫,但根據資源型別和執行時行為可能需要更長時間。執行期間的任何錯誤都會在message欄位中報告(以及reason: Error)。
kubelet 如何重試延遲的調整大小
如果請求的調整大小被**延遲**,kubelet 將定期重新嘗試調整大小,例如當另一個 Pod 被移除或縮容時。如果存在多個延遲的調整大小,它們將按照以下優先順序重試
- 具有更高優先順序的 Pod(基於 PriorityClass)將首先重試其調整大小請求。
- 如果兩個 Pod 具有相同的優先順序,則優先重試 Guaranteed Pod 的調整大小,然後再重試 Burstable Pod 的調整大小。
- 如果其他條件都相同,則處於 Deferred 狀態時間更長的 Pod 將被優先考慮。
較高優先順序的調整大小被標記為待處理不會阻止剩餘待處理的調整大小被嘗試;即使較高優先順序的調整大小再次被延遲,所有剩餘的待處理調整大小仍將重試。
利用 observedGeneration 欄位
Kubernetes v1.34 [beta] (預設啟用:true)- 頂級
status.observedGeneration欄位顯示與 kubelet 已確認的最新 Pod 規範對應的metadata.generation。你可以使用它來確定 kubelet 已處理的最新調整大小請求。 - 在
PodResizeInProgress條件中,conditions[].observedGeneration欄位指示當前正在進行的調整大小啟動時 PodSpec 的metadata.generation。 - 在
PodResizePending條件中,conditions[].observedGeneration欄位指示待處理調整大小的分配上次嘗試時 PodSpec 的metadata.generation。
容器調整大小策略
你可以透過在容器規範中設定 resizePolicy 來控制容器在調整大小時是否應重新啟動。這允許根據資源型別(CPU 或記憶體)進行精細控制。
resizePolicy:
- resourceName: cpu
restartPolicy: NotRequired
- resourceName: memory
restartPolicy: RestartContainer
NotRequired:(預設)將資源更改應用到執行中的容器,而不重新啟動它。RestartContainer:重新啟動容器以應用新的資源值。這對於記憶體更改通常是必需的,因為許多應用程式和執行時無法動態調整其記憶體分配。
如果未為資源指定 resizePolicy[*].restartPolicy,則預設為 NotRequired。
注意
如果 Pod 的整體restartPolicy 為 Never,則所有資源的任何容器 resizePolicy 都必須為 NotRequired。你不能在此類 Pod 中配置需要重新啟動的調整大小策略。示例場景
考慮一個配置了 CPU 的 restartPolicy: NotRequired 和記憶體的 restartPolicy: RestartContainer 的容器。
- 如果只更改 CPU 資源,容器將就地調整大小。
- 如果只更改記憶體資源,容器將重新啟動。
- 如果 CPU 和記憶體資源**同時**更改,容器將重新啟動(由於記憶體策略)。
限制
對於 Kubernetes 1.34,就地調整 Pod 資源大小有以下限制
- 資源型別: 只能調整 CPU 和記憶體資源的大小。
- 記憶體減少: 如果記憶體調整大小重啟策略為
NotRequired(或未指定),kubelet 將盡力防止在減少記憶體限制時發生 oom-kill,但不提供任何保證。在減少容器記憶體限制之前,如果記憶體使用量超過請求的限制,則將跳過調整大小,狀態將保持“進行中”。這被認為是盡力而為的,因為它仍然受到記憶體使用量在檢查後立即飆升的競態條件的影響。 - QoS 等級: Pod 的原始服務質量 (QoS) 等級(Guaranteed、Burstable 或 BestEffort)在建立時確定,並且**不能**透過調整大小更改。調整大小後的資源值仍必須遵守原始 QoS 等級的規則
- Guaranteed:調整大小後,CPU 和記憶體的請求必須繼續等於限制。
- Burstable:CPU 和記憶體的請求和限制不能同時相等(因為這會將其更改為 Guaranteed)。
- BestEffort:不能新增資源需求(
requests或limits)(因為這會將其更改為 Burstable 或 Guaranteed)。
- 容器型別: 不可重啟的初始化容器和臨時容器不能調整大小。Sidecar 容器可以調整大小。
- 資源移除: 資源請求和限制一旦設定就不能完全移除;它們只能更改為不同的值。
- 作業系統: Windows Pod 不支援就地調整大小。
- 節點策略: 由靜態 CPU 或記憶體管理器策略管理的 Pod 不能就地調整大小。
- 交換: 利用交換記憶體的 Pod 無法調整記憶體請求,除非記憶體的
resizePolicy是RestartContainer。
這些限制可能會在未來的 Kubernetes 版本中放寬。
示例 1:不重啟調整 CPU 大小
首先,建立一個設計用於就地 CPU 調整大小和需要重啟的記憶體調整大小的 Pod。
apiVersion: v1
kind: Pod
metadata:
name: resize-demo
spec:
containers:
- name: pause
image: registry.k8s.io/pause:3.8
resizePolicy:
- resourceName: cpu
restartPolicy: NotRequired # Default, but explicit here
- resourceName: memory
restartPolicy: RestartContainer
resources:
limits:
memory: "200Mi"
cpu: "700m"
requests:
memory: "200Mi"
cpu: "700m"
建立 Pod
kubectl create -f pod-resize.yaml
此 Pod 以 Guaranteed QoS 等級啟動。驗證其初始狀態
# Wait a moment for the pod to be running
kubectl get pod resize-demo --output=yaml
觀察 spec.containers[0].resources 和 status.containerStatuses[0].resources。它們應該與清單匹配(700m CPU,200Mi 記憶體)。注意 status.containerStatuses[0].restartCount(應為 0)。
現在,將 CPU 請求和限制增加到 800m。你使用帶有 --subresource resize 命令列引數的 kubectl patch。
kubectl patch pod resize-demo --subresource resize --patch \
'{"spec":{"containers":[{"name":"pause", "resources":{"requests":{"cpu":"800m"}, "limits":{"cpu":"800m"}}}]}}'
# Alternative methods:
# kubectl -n qos-example edit pod resize-demo --subresource resize
# kubectl -n qos-example apply -f <updated-manifest> --subresource resize
注意
--subresource resize 命令列引數要求 kubectl 客戶端版本為 v1.32.0 或更高。舊版本將報告 invalid subresource 錯誤。修補後再次檢查 Pod 狀態
kubectl get pod resize-demo --output=yaml --namespace=qos-example
你應該看到
spec.containers[0].resources現在顯示cpu: 800m。status.containerStatuses[0].resources也顯示cpu: 800m,表示調整大小在節點上成功。status.containerStatuses[0].restartCount仍然是0,因為 CPU 的resizePolicy是NotRequired。
示例 2:重啟調整記憶體大小
現在,透過將**同一** Pod 的記憶體增加到 300Mi 來調整記憶體大小。由於記憶體的 resizePolicy 是 RestartContainer,容器預計會重新啟動。
kubectl patch pod resize-demo --subresource resize --patch \
'{"spec":{"containers":[{"name":"pause", "resources":{"requests":{"memory":"300Mi"}, "limits":{"memory":"300Mi"}}}]}}'
修補後不久檢查 Pod 狀態
kubectl get pod resize-demo --output=yaml
你現在應該觀察到
spec.containers[0].resources顯示memory: 300Mi。status.containerStatuses[0].resources也顯示memory: 300Mi。status.containerStatuses[0].restartCount已增加到1(如果之前發生過重啟,則更多),表示容器已重新啟動以應用記憶體更改。
故障排除:不可行的調整大小請求
接下來,嘗試請求不合理的 CPU 量,例如 1000 個完整核心(寫為 "1000" 而不是 "1000m" 表示毫核),這可能超出節點容量。
# Attempt to patch with an excessively large CPU request
kubectl patch pod resize-demo --subresource resize --patch \
'{"spec":{"containers":[{"name":"pause", "resources":{"requests":{"cpu":"1000"}, "limits":{"cpu":"1000"}}}]}}'
查詢 Pod 的詳細資訊
kubectl get pod resize-demo --output=yaml
你將看到指示問題的更改
spec.containers[0].resources反映了**期望**狀態 (cpu: "1000")。- 一個帶有
type: PodResizePending和reason: Infeasible的條件已新增到 Pod。 - 條件的
message將解釋原因(Node didn't have enough capacity: cpu, requested: 800000, capacity: ...) - 關鍵是,
status.containerStatuses[0].resources仍然會顯示**以前的值**(cpu: 800m,memory: 300Mi),因為不可行的調整大小未被 Kubelet 應用。 - 由於這次失敗的嘗試,
restartCount不會改變。
要解決此問題,你需要再次使用可行的資源值修補 Pod。
清理
刪除 Pod
kubectl delete pod resize-demo