题干与适用场景
平台团队希望在不重建 Pod 的情况下调整 CPU 与内存。请设计 Kubernetes 原地 Pod 调整流程,说明何时容器必须重启、如何处理资源不足,以及怎样观测和回滚。
Kubernetes 1.33 将容器原地调整提升为 Beta;1.36 的 Pod 级资源调整也处于 Beta。请求修改运行中 Pod 的 CPU 和内存资源,kubelet 根据 resizePolicy、节点容量与 cgroup 状态执行或延迟处理,避免把“修改规格”误解为“永不重启”。
面试官考察点
重点包括:区分 Pod 级资源上限与容器资源、resizePolicy 的 CPU/内存语义、Pending/InProgress 状态、不可行与延迟重试、调度器与 kubelet 的职责、QoS 与优先级,以及灰度和回滚边界。
30 秒回答框架
“我会把原地调整设计成声明式请求加状态机。控制器更新资源规格,kubelet 检查节点可行性并更新 PodResizePending 或 PodResizeInProgress;CPU 通常可以不重启,内存是否重启由容器的 resizePolicy 决定。不可行请求要保留原因并按优先级重试,不能假装已经生效。平台需要观测 observedGeneration、实际 cgroup、重启次数和 QoS 变化,并以小批量灰度和反向 patch 回滚。”
分步骤深入解答
第一步:定义资源模型
容器资源决定单个容器的请求与限制;Pod 级资源在支持的版本中提供聚合边界。Pod 级限制是所有容器使用量的上界,但单个容器限制不能超过 Pod 级限制。API 设计必须明确修改的是 spec.containers[*].resources 还是 spec.resources。
第二步:建立声明式调整流程
平台接收目标资源和原因,写入 Pod 的资源字段,保存原值、操作者和变更代次。API 层不直接操作节点 cgroup;kubelet 观察新的 generation,完成可行性检查和执行,并把结果写回状态。
第三步:处理重启策略
容器可按资源分别配置重启策略:
resizePolicy:
- resourceName: cpu
restartPolicy: NotRequired
- resourceName: memory
restartPolicy: RestartContainerNotRequired 尝试在运行中应用;RestartContainer 允许通过重启使新值生效。对于 restartPolicy: Never 的 Pod,所有容器资源都必须使用 NotRequired,否则请求无效。
第四步:设计可行性与延迟状态
节点无法提供目标资源时,kubelet 设置 PodResizePending,原因可以是 Infeasible 或 Deferred;成功处理时进入 PodResizeInProgress。控制器应读取状态而不是只看 API spec,并通过 observedGeneration 确认状态对应的请求代次。
第五步:处理 CPU 与内存差异
CPU 调整通常可更新 cgroup 配额而不重启应用。内存缩容可能受到当前工作集限制,部分运行时需要重启才能安全应用;不能以 CPU 的无重启行为推断内存。控制器应按资源读取策略并为每种结果提供明确事件。
第六步:协调调度与 QoS
原地调整不等于节点重新调度。扩大请求可能需要节点容量,延迟请求应按 PriorityClass、QoS 类别和等待时长重试。调整后要重新计算 QoS、资源配额和监控告警,避免突破 namespace 配额或让 Guaranteed 工作负载被低估。
第七步:观测实际生效值
同时采集期望 spec、status 条件、observedGeneration、容器实际 cgroup 配额、重启次数、OOM、CPU throttling 与内存工作集。若状态显示完成但 cgroup 未变化,应把它视为失败并阻止下一次调整,而不是继续叠加 patch。
第八步:灰度、限速与回滚
按工作负载和节点池分批执行,限制并发调整数,设置 Pending 超时和最大重试次数。异常时恢复保存的旧资源;若内存策略导致重启,先摘除流量并验证就绪,再扩大灰度。所有请求都要支持幂等键,避免控制器重复提交。
设计取舍与边界
无重启连续性还是资源确定性
原地调整减少服务中断,但延迟和节点容量会让结果异步。对延迟敏感服务可保守使用小步调整;对批处理可接受重启以换取确定性。
Pod 级边界还是容器级精度
Pod 级资源适合表达共享上限,容器级资源适合保护关键容器。两者同时存在时,平台必须校验容器限制不超过 Pod 上限,并在 UI 和审计中显示有效边界。
自动重试还是人工批准
可行性暂时不足适合有限重试;涉及内存重启、QoS 变化或生产高峰时,应要求批准或维护窗口,不能无限自动重试。
失败演练与演进计划
节点资源不足
提交超过节点容量的扩容请求,确认状态为 Infeasible 或 Deferred,验证重试不会修改已生效的旧值。
内存调整触发重启
为内存设置 RestartContainer,观察流量摘除、容器重启、就绪恢复和事件顺序,确认控制器不会把重启误报为业务故障。
代次竞争
快速提交两个不同目标,确认旧 generation 的完成状态不会覆盖新目标,并且最终状态的 observedGeneration 与实际 cgroup 一致。
常见误区与追问
误区一:原地调整保证永不重启
追问:什么会触发重启?容器的 resizePolicy 可以要求重启,尤其是内存变化;Pod 级资源调整本身没有独立重启策略,但容器策略仍生效。
误区二:只更新 spec 就算完成
追问:如何确认成功?检查状态条件、observedGeneration、实际 cgroup、容器事件和重启次数,不能只读期望字段。
误区三:节点不足时持续 patch
追问:正确做法是什么?保留 Pending 原因,按优先级和等待时长有限重试,并提供迁移、缩小目标或人工批准路径。
延伸追问与参考答案
为什么 CPU 和内存要分开设计?
CPU 配额通常能在线改变;内存缩容受工作集和运行时约束,可能需要重启。统一接口仍应保留按资源的策略和状态。
如何防止重复调整覆盖新目标?
用资源版本或 generation 做条件更新,控制器只接受最新目标,状态通过 observedGeneration 与实际 cgroup 对账。
何时不应使用原地调整?
需要强隔离、节点无法稳定提供容量、应用不能承受重启或资源变化会破坏运行时假设时,应采用新 Pod 滚动替换并保留原地功能作为受控优化。