--- title: 调整分配给容器的 CPU 和内存资源 content_type: task weight: 30 min-kubernetes-server-version: 1.33 --- {{< feature-state feature_gate_name="InPlacePodVerticalScaling" >}} 本页面说明了如何在**不重新创建 Pod** 的情况下,更改分配给容器的 CPU 和内存资源请求与限制。 传统上,更改 Pod 的资源需求需要删除现有 Pod 并创建一个替代 Pod, 这通常由[工作负载控制器](/zh-cn/docs/concepts/workloads/controllers/)管理。 而就地 Pod 调整功能允许在运行中的 Pod 内变更容器的 CPU 和内存分配,从而可能避免干扰应用。 **关键概念:** - **期望资源(Desired Resources)**:容器的 `spec.containers[*].resources` 字段表示容器的**期望**资源,对于 CPU 和内存是可变的。 - **实际资源(Actual Resources)**:`status.containerStatuses[*].resources` 字段反映当前运行容器**实际配置**的资源。 对于尚未启动或重新启动的容器,该字段表示其下次启动时分配的资源。 - **触发调整(Triggering a Resize)**:你可以通过更新 Pod 规约中的 `requests` 和 `limits` 来请求调整。 这通常通过 `kubectl patch`、`kubectl apply` 或 `kubectl edit` 操作 Pod 的 `resize` 子资源来完成。 当期望资源与已分配资源不一致时,Kubelet 会尝试调整容器资源。 - **已分配资源(Allocated Resources,进阶)**:`status.containerStatuses[*].allocatedResources` 字段用于记录由 Kubelet 确认的资源值,主要用于内部调度逻辑。 在大多数监控和验证场景中,建议关注 `status.containerStatuses[*].resources` 字段。 如果某个节点上存在处于挂起或未完成调整状态的 Pod(见下文 [Pod 调整状态](#pod-resize-status)), {{< glossary_tooltip text="调度器" term_id="kube-scheduler" >}}会在进行调度决策时, 使用容器的期望请求、已分配请求和实际请求三者中的**最大值**。 ## {{% heading "prerequisites" %}} {{< include "task-tutorial-prereqs.md" >}} {{< version-check >}} 你需要在控制平面和集群中的所有节点上启用 `InPlacePodVerticalScaling` [特性门控](/zh-cn/docs/reference/command-line-tools-reference/feature-gates/)。 要使用 `--subresource=resize` 参数,`kubectl` 客户端版本需至少为 v1.32。 ## Pod 大小调整状态 {#pod-resize-status} Kubelet 会通过更新 Pod 的状态状况来反映调整请求的当前状态: * `type: PodResizePending`:Kubelet 当前无法立即执行该请求。`message` 字段会说明原因: * `reason: Infeasible`:请求的资源在当前节点上不可行(例如请求超出节点总资源)。 * `reason: Deferred`:请求的资源当前无法满足,但未来可能满足(例如其他 Pod 被移除后), Kubelet 会重试调整。 * `type: PodResizeInProgress`:Kubelet 已接受调整并分配了资源,但调整仍在进行中。 这一状态通常很短暂,但也可能因资源类型或运行时行为而延长。 执行过程中的任何错误都会在 `message` 字段中报告,同时带有 `reason: Error`。 ## 容器调整策略 {#container-resize-policies} 容器可以在资源需求中指定可选的 `resizePolicy` 数组。 该数组中的每一项定义了某种资源在就地调整期间应如何处理。 你可以通过在容器规约中设置 `resizePolicy`,控制在调整资源时容器是否需要重启。 这样可以针对不同资源类型(CPU 或内存)进行精细化控制。 ```yaml resizePolicy: - resourceName: cpu restartPolicy: NotRequired - resourceName: memory restartPolicy: RestartContainer ``` * `NotRequired`:(默认)在不重启容器的情况下应用资源变更。 * `RestartContainer`:重启容器以应用新的资源值。 对于内存变更,许多应用和运行时无法动态调整内存分配,因此通常需要重启。 如果未为某个资源指定 `resizePolicy[*].restartPolicy`,则默认为 `NotRequired`。 {{< note >}} 如果 Pod 的整体 `restartPolicy` 为 `Never`,则所有容器的 `resizePolicy` 必须对所有资源都设置为 `NotRequired`。 此类 Pod 不允许配置需要重启的调整策略。 {{< /note >}} **示例场景:** 考虑一个容器,其 CPU 的 `restartPolicy` 为 `NotRequired`,内存的 `restartPolicy` 为 `RestartContainer`: * 如果仅更改 CPU 资源,容器将原地调整大小。 * 如果仅更改内存资源,容器将重启。 * 如果**同时**更改 CPU 和内存资源,容器将重启(由于内存策略)。 ## 限制 {#limitations} 对于 Kubernetes v{{< skew currentVersion >}},原地调整 Pod 资源大小存在以下限制: * **资源类型**:只能调整 CPU 和内存资源。 * **内存减少**:除非内存的 `resizePolicy` 为 `RestartContainer`,否则内存限制**不能减少**。 内存请求通常可以减少。 * **QoS 类**:Pod 的原始[服务质量(QoS)类](/zh-cn/docs/concepts/workloads/pods/pod-qos/) (Guaranteed、Burstable 或 BestEffort)在创建时确定,**不能**通过调整大小来更改。 调整后的资源值仍必须遵守原始 QoS 类的规则: * **Guaranteed**:调整后,CPU 和内存的请求必须继续等于限制。 * **Burstable**:CPU 和内存的请求和限制不能**同时**变为相等 (因为这会将其更改为 Guaranteed)。 * **BestEffort**:不能添加资源要求(`requests` 或 `limits`) (因为这会将其更改为 Burstable 或 Guaranteed)。 * **容器类型**:不可重启的{{< glossary_tooltip text="Init 容器" term_id="init-container" >}}和 {{< glossary_tooltip text="临时容器" term_id="ephemeral-container" >}}不能调整大小。 [边车容器](/zh-cn/docs/concepts/workloads/pods/sidecar-containers/)可以调整大小。 * **资源移除**:一旦设置了资源请求和限制,就不能完全移除; 只能更改为不同的值。 * **操作系统**:Windows Pod 不支持原地调整大小。 * **节点策略**:由[静态 CPU 或内存管理器策略](/zh-cn/docs/tasks/administer-cluster/cpu-management-policies/)管理的 Pod 不能原地调整大小。 * **交换内存**:使用[交换内存](/zh-cn/docs/concepts/architecture/nodes/#swap-memory)的 Pod 不能调整内存请求, 除非内存的 `resizePolicy` 为 `RestartContainer`。 这些限制可能会在未来的 Kubernetes 版本中放宽。 ## 示例 1:调整 CPU 而不重启 {#example-1-resizing-cpu-without-restart} 首先,创建一个设计用于原地 CPU 调整和需要重启的内存调整的 Pod。 {{% code_sample file="pods/resource/pod-resize.yaml" %}} 创建 Pod: ```shell kubectl create -f pod-resize.yaml ``` 这个 Pod 以 Guaranteed QoS 类启动。验证其初始状态: ```shell # 等待 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 patch`。 ```shell kubectl patch pod resize-demo --subresource resize --patch \ '{"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 --subresource resize ``` {{< note >}} `--subresource resize` 命令行参数要求 `kubectl` 客户端版本为 v1.32.0 或更高。 较早版本会报告 `invalid subresource` 错误。 {{< /note >}} 在应用补丁后再次检查 Pod 状态: ```shell 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:调整内存并重启 {#example-2-resizing-memory-with-restart} 现在,将**同一个** Pod 的内存增加到 `300Mi`。 由于内存的 `resizePolicy` 是 `RestartContainer`,容器将会重启。 ```shell kubectl patch pod resize-demo --subresource resize --patch \ '{"spec":{"containers":[{"name":"pause", "resources":{"requests":{"memory":"300Mi"}, "limits":{"memory":"300Mi"}}}]}}' ``` 在应用补丁后立即检查 Pod 状态: ```shell kubectl get pod resize-demo --output=yaml ``` 你现在应该观察到: * `spec.containers[0].resources` 显示 `memory: 300Mi`。 * `status.containerStatuses[0].resources` 也显示 `memory: 300Mi`。 * `status.containerStatuses[0].restartCount` 增加到 `1`(如果之前发生过重启,可能会更多), 表明容器已重启以应用内存变更。 ## 故障排查:不可行的调整请求 {#troubleshooting-infeasible-resize-request} 接下来,尝试请求不合理的 CPU 数量,例如 1000 个完整核心(写作 `"1000"` 而不是 `"1000m"` 毫核),这很可能超出节点容量。 ```shell # 尝试使用过大的 CPU 请求进行补丁 kubectl patch pod resize-demo --subresource resize --patch \ '{"spec":{"containers":[{"name":"pause", "resources":{"requests":{"cpu":"1000"}, "limits":{"cpu":"1000"}}}]}}' ``` 查询 Pod 的详细信息: ```shell 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 进行补丁。 ## 清理 {#clean-up} 删除 Pod: ```shell kubectl delete pod resize-demo ``` ## {{% heading "whatsnext" %}} ### 对于应用开发人员 * [为容器和 Pod 分配内存资源](/zh-cn/docs/tasks/configure-pod-container/assign-memory-resource/) * [为容器和 Pod 分配 CPU 资源](/zh-cn/docs/tasks/configure-pod-container/assign-cpu-resource/) * [分配 Pod 级别的 CPU 和内存资源](/zh-cn/docs/tasks/configure-pod-container/assign-pod-level-resources/) ### 对于集群管理员 * [为名字空间配置默认内存请求和限制](/zh-cn/docs/tasks/administer-cluster/manage-resources/memory-default-namespace/) * [为名字空间配置默认 CPU 请求和限制](/zh-cn/docs/tasks/administer-cluster/manage-resources/cpu-default-namespace/) * [为名字空间配置最小和最大内存约束](/zh-cn/docs/tasks/administer-cluster/manage-resources/memory-constraint-namespace/) * [为名字空间配置最小和最大 CPU 约束](/zh-cn/docs/tasks/administer-cluster/manage-resources/cpu-constraint-namespace/) * [为名字空间配置内存和 CPU 配额](/zh-cn/docs/tasks/administer-cluster/manage-resources/quota-memory-cpu-namespace/)