K8s 1.35 原地扩缩容 GA:改 requests/limits 不用重建 Pod,但内存缩容仍可能要重启
Kubernetes v1.35 于 2025-12-17 发布,共 60 项增强:17 项 stable、19 项 beta、22 项 alpha。其中与日常运维关系最直接的一项是 In-place update of Pod resources 达到 GA(KEP #1287,SIG Node)。
改 resources 不再触发 Pod 重建
GA 之后,直接修改运行中 Pod 的 resources.requests 与 resources.limits 即可调整 CPU 和内存,不需要删除重建 Pod,也不需要重启容器。此前的原地更新只覆盖基础设施层面的 requests/limits 记录,现在真正落到容器的 cgroup 限制上,可以做无中断的垂直扩缩。
apiVersion: v1
kind: Pod
metadata:
name: resize-demo
spec:
containers:
- name: app
image: nginx
resources:
requests:
cpu: 500m
memory: 256Mi
limits:
cpu: "1"
memory: 512Mi
resizePolicy:
- resourceName: cpu
restartPolicy: NotRequired
- resourceName: memory
restartPolicy: RestartContainer
resizePolicy 按资源维度声明:NotRequired 表示原地调整,RestartContainer 表示需要重启容器才能生效。CPU 通常可以设为 NotRequired,因为调整 CPU 份额可以即时生效;内存则更复杂。
内存缩容的边界:resizePolicy 与容器当前用量
缩容内存受两个条件约束:
resizePolicy中该资源的restartPolicy;- 容器当前的实际内存用量。
调低内存 limit 时,如果新 limit 低于容器当前已用量,内核无法把已经分配出去的页收回,这个 resize 请求就无法原地完成。此时容器必须重启,才能让新 limit 生效。也就是说,扩内存基本是安全的,缩内存则可能触发重启,取决于当时负载的实际用量。这一点决定了不能把原地缩容当成完全无感的操作来用。
用 generation 确认 kubelet 真的处理了
metadata.generation 在 v1.33 作为 alpha 引入,v1.35 稳定:每次 Pod spec 更新都会递增。与之配套的 status.observedGeneration 表示 kubelet 已经看到并处理到了哪个 generation,Pod 的各个 condition 上也各自带有 observedGeneration。
kubectl get pod resize-demo \
-o jsonpath='{.metadata.generation} {.status.observedGeneration}'
两个值相等,说明 kubelet 已经处理完这次 spec 变更;不相等说明还在处理,或者被卡住了。判断原地扩缩容是否真正完成,直接比较这两个值即可,此外还要检查 condition 上的 observedGeneration,避免只看到 API 对象已更新就误以为 cgroup 已经改好。
用 patch 改运行中的 Pod
kubectl patch pod resize-demo --subresource resize --type=merge -p '
{"spec":{"containers":[
{"name":"app","resources":{
"requests":{"cpu":"800m","memory":"256Mi"},
"limits":{"cpu":"2","memory":"512Mi"}}}
]}}'
注意这里改的是 Pod 本身,而不是工作负载模板。Deployment 的 spec.template 里改 resources 仍然走滚动更新,Pod 照样重建,原地扩缩容不会改变这条路径。
还没 GA 的部分
Pod 级 resources(KEP #5419)仍是 alpha,不能当作可用能力依赖。它和容器级 resources 是两个不同的字段层级,本文的结论只对容器级生效。
与 HPA、VPA、ResourceQuota 的关系
- HPA 调整的是副本数,不涉及单个 Pod 的 resources,原地扩缩容对它没有影响。v1.35 里 HPA 另有一项 beta:可按资源设置 tolerance(默认开启)。
- VPA 会修改 Pod 的 resources,原地扩缩容正是它避免重建 Pod 的路径,但内存缩容同样受上面两个条件约束。
- ResourceQuota 按 requests/limits 记账。原地扩容后,Pod 的 requests 合计不能超过命名空间配额,超出的更新会被 apiserver 直接拒绝,不会进入 resize 流程。
其它与本次发布相关的变更
- Pod certificates(KEP #4317)Beta:kubelet 生成密钥、通过 PodCertificateRequest 申请证书并写入 Pod 文件系统,apiserver 在 admission 时强制节点限制。
- Node declared features(KEP #5328)Alpha:Node 通过
.status.declaredFeatures上报支持的特性,供 scheduler/admission 使用。 PreferSameNodetrafficDistribution 新增;原PreferClose改名PreferSameZone,保留兼容。- Job API 新增
managedBy(stable),用于 MultiKueue 等外部控制器同步 Job 状态。 - Downward API 暴露节点拓扑标签(beta):
topology.kubernetes.io/zone、topology.kubernetes.io/region可注入为环境变量或 projected volume,升级后每个 Pod 会多出若干标签。 - 存储版本迁移原生支持(beta 默认开启)。
- KYAML beta 默认开启,可用
KUBECTL_KYAML=false关闭。 - Pod user namespaces 支持。
- image volume 类型默认启用,需要 containerd 2.1+。
- Kubelet 对已缓存镜像做凭据校验(beta 默认开启,
KubeletEnsureSecretPulledImages可关,imagePullCredentialsVerificationPolicy配置严格程度)。 - 容器级
restartPolicy/restartPolicyRules(beta 默认开启)。 - Gang scheduling:Workload API 与 PodGroup(alpha)。
- 受限 impersonation(alpha,ConstrainedImpersonation)。
/flagz与/statusz支持 JSON 输出。- cgroups v1 支持默认禁用。