调整分配给容器的 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