调整分配给容器的 CPU 和内存资源
Kubernetes v1.33 [beta]
(enabled by default: true)本页面说明了如何在不重新创建 Pod 的情况下,更改分配给容器的 CPU 和内存资源请求与限制。
传统上,更改 Pod 的资源需求需要删除现有 Pod 并创建一个替代 Pod, 这通常由工作负载控制器管理。 而就地 Pod 调整功能允许在运行中的 Pod 内变更容器的 CPU 和内存分配,从而可能避免干扰应用。
关键概念:
- 期望资源(Desired Resources):容器的
spec.containers[*].resources
字段表示容器的期望资源,对于 CPU 和内存是可变的。 - 实际资源(Actual Resources):
status.containerStatuses[*].resources
字段反映当前运行容器实际配置的资源。 对于尚未启动或重新启动的容器,该字段表示其下次启动时分配的资源。 - 触发调整(Triggering a Resize):你可以通过更新 Pod 规约中的
requests
和limits
来请求调整。 这通常通过kubectl
、kubectl apply
或kubectl edit
操作 Pod 的resize
子资源来完成。 当期望资源与已分配资源不一致时,Kubelet 会尝试调整容器资源。 - 已分配资源(Allocated Resources,进阶):
status.containerStatuses[*].allocatedResources
字段用于记录由 Kubelet 确认的资源值,主要用于内部调度逻辑。 在大多数监控和验证场景中,建议关注status.containerStatuses[*].resources
字段。
如果某个节点上存在处于挂起或未完成调整状态的 Pod(见下文 Pod 调整状态), 调度器会在进行调度决策时, 使用容器的期望请求、已分配请求和实际请求三者中的最大值。
准备开始
你必须拥有一个 Kubernetes 的集群,且必须配置 kubectl 命令行工具让其与你的集群通信。 建议运行本教程的集群至少有两个节点,且这两个节点不能作为控制平面主机。 如果你还没有集群,你可以通过 Minikube 构建一个你自己的集群,或者你可以使用下面的 Kubernetes 练习环境之一:
你的 Kubernetes 服务器版本必须不低于版本 1.33.要获知版本信息,请输入 kubectl version
.
你需要在控制平面和集群中的所有节点上启用 InPlacePodVerticalScaling
特性门控。
要使用 --subresource=resize
参数,kubectl
客户端版本需至少为 v1.32。
Pod 大小调整状态
Kubelet 会通过更新 Pod 的状态状况来反映调整请求的当前状态:
type: PodResizePending
:Kubelet 当前无法立即执行该请求。message
字段会说明原因:reason: Infeasible
:请求的资源在当前节点上不可行(例如请求超出节点总资源)。reason: Deferred
:请求的资源当前无法满足,但未来可能满足(例如其他 Pod 被移除后), Kubelet 会重试调整。
type: PodResizeInProgress
:Kubelet 已接受调整并分配了资源,但调整仍在进行中。
这一状态通常很短暂,但也可能因资源类型或运行时行为而延长。 执行过程中的任何错误都会在message
字段中报告,同时带有reason: Error
。
容器调整策略
容器可以在资源需求中指定可选的 resizePolicy
数组。
该数组中的每一项定义了某种资源在就地调整期间应如何处理。
你可以通过在容器规约中设置 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 v1.33,原地调整 Pod 资源大小存在以下限制:
- 资源类型:只能调整 CPU 和内存资源。
- 内存减少:除非内存的
resizePolicy
为RestartContainer
,否则内存限制不能减少。 内存请求通常可以减少。
- QoS 类:Pod 的原始服务质量(QoS)类 (Guaranteed、Burstable 或 BestEffort)在创建时确定,不能通过调整大小来更改。 调整后的资源值仍必须遵守原始 QoS 类的规则:
- Guaranteed:调整后,CPU 和内存的请求必须继续等于限制。
- Burstable:CPU 和内存的请求和限制不能同时变为相等 (因为这会将其更改为 Guaranteed)。
- BestEffort:不能添加资源要求(
requests
或limits
) (因为这会将其更改为 Burstable 或 Guaranteed)。
- 资源移除:一旦设置了资源请求和限制,就不能完全移除; 只能更改为不同的值。
- 操作系统: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 类启动。验证其初始状态:
# 等待 Pod 运行
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
。
kubectl pod resize-demo --subresource resize -- \
'{"spec":{"containers":[{"name":"pause", "resources":{"requests":{"cpu":"800m"}, "limits":{"cpu":"800m"}}}]}}'
# 替代方法:
# 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 pod resize-demo --subresource resize -- \
'{"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"
毫核),这很可能超出节点容量。
# 尝试使用过大的 CPU 请求进行补丁
kubectl pod resize-demo --subresource resize -- \
'{"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"
)。- Pod 添加了一个
type: PodResizePending
和reason: Infeasible
的条件。 - 状况的
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