容器的稳态 CPU 消耗通常不高,但启动阶段可能完全不同:Spring Boot 要扫描类路径并完成 JIT,Node.js 要解析模块依赖,Python 服务则可能需要导入 PyTorch、NumPy 等大型依赖。按照稳态负载设置 CPU request,启动时容易被限速;按照启动峰值配置,又会让 CPU 在服务就绪后长期闲置。
GKE 预览版的 CPU Startup Boost 把这两个阶段拆开处理:容器启动时临时提高 CPU request,readinessProbe 通过后再原地降回基线,不需要重启容器。
为什么仅仅调大 CPU request 不是好办法
在 Kubernetes 中,CPU request 不只是一个资源备注。调度器会用它决定 Pod 放在哪个节点,平台也会据此预留容量。如果一个 Java 服务稳态只需要 500m CPU,却因为启动阶段的短时峰值长期申请 2 核,那么副本越多,浪费越明显。
反过来,如果只申请 500m,CPU 密集型初始化可能拖慢冷启动,进一步引发:
readinessProbe超时,Pod 迟迟不能接收流量;- 扩容速度跟不上突发请求;
- 发布期间新副本接管流量过慢;
- 初始化 CPU 峰值影响基于 CPU 的 HPA 判断。
CPU Startup Boost 的目标并不是永久增加容量,而是为启动阶段提供一个有边界的临时加速窗口。官方给出的效果是,合适的工作负载可将初始化时间最多缩短约 2 倍;实际收益仍取决于应用启动过程是否真的受 CPU 限制。
它如何在不重启容器的情况下回收 CPU
这项能力集成在 GKE 的 Vertical Pod Autoscaler(VPA)中,并建立在 Kubernetes In-place Pod Resize(IPPR)之上。IPPR 允许控制平面和 kubelet 修改运行中容器的资源配置,而不必删除并重新创建 Pod。
一次完整生命周期可以拆成三个阶段:
- 准入阶段:VPA admission webhook 拦截 Pod 创建请求,根据倍数或固定数量计算启动 CPU,并写入提升后的 request 和跟踪注解。
- 启动阶段:Pod 带着更高的 CPU 配额被调度和初始化,用于类加载、模块解析、JIT 或缓存预热。
- 回落阶段:
readinessProbe成功后,再等待可选的durationSeconds,VPA updater 发起原地 resize,将 CPU request 降回基线。
这里最关键的信号是 readiness。如果探针只检查进程是否存在,而没有反映应用是否真正完成初始化,CPU 可能过早回落;如果探针长期失败,提升后的资源也可能保持得比预期更久。
可直接改造的 VPA 配置
使用前需要满足以下条件:
- GKE 版本为
1.36.0-gke.4447000或更高; - 支持 Standard 和 Autopilot 集群;
- Autopilot 默认启用 VPA;Standard 集群需要先启用 VPA;
- 工作负载由 Deployment、StatefulSet 等标准控制器管理;
- 应用配置了可靠的
readinessProbe。
下面假设集群中已有名为 java-app 的 Deployment,容器清单中的稳态 CPU request 已经按真实运行需求设置。保存为 java-app-startup-boost.yaml:
apiVersion: autoscaling.k8s.io/v1
kind: VerticalPodAutoscaler
metadata:
name: java-app-startup-boost
namespace: default
spec:
targetRef:
apiVersion: apps/v1
kind: Deployment
name: java-app
updatePolicy:
updateMode: "Off"
startupBoost:
cpu:
type: "Factor"
factor: 2
durationSeconds: 10
应用配置:
kubectl apply -f java-app-startup-boost.yaml
kubectl rollout restart deployment/java-app
kubectl rollout status deployment/java-app
这个策略在启动时将 CPU request 提高到基线的 2 倍。探针通过后继续保持 10 秒,然后原地降回基线。updateMode: "Off" 表示不让 VPA 持续改写稳态资源,适合已经手工确定 request、只想解决冷启动问题的团队。
如果还希望 VPA 持续优化稳态资源,可以改为:
updatePolicy:
updateMode: "InPlaceOrRecreate"
startupBoost:
cpu:
type: "Factor"
factor: 3
durationSeconds: 5
这时需要接受一个边界:VPA 会在启动阶段之外继续调整资源,并在无法原地完成某些变更时采用重建策略。上线前应在测试环境验证它与 PodDisruptionBudget、滚动发布和容量规划的配合。
多容器 Pod 则适合按容器配置。例如只提升业务容器,不提升日志或服务网格 sidecar:
apiVersion: autoscaling.k8s.io/v1
kind: VerticalPodAutoscaler
metadata:
name: api-gateway-startup-boost
namespace: default
spec:
targetRef:
apiVersion: apps/v1
kind: Deployment
name: api-gateway
updatePolicy:
updateMode: "Off"
resourcePolicy:
containerPolicies:
- containerName: "web-app"
mode: "Off"
startupBoost:
cpu:
type: "Quantity"
quantity: "2"
durationSeconds: 5
应用前把 api-gateway 和 web-app 分别改成实际的 Deployment 名称与容器名称。该示例使用固定数量方式,在启动期间为目标容器提供 2 vCPU 的提升配置,而不是把所有 sidecar 一并放大。
如何确认提升和回落确实发生了
先找到目标 Pod,并查看 VPA 写入的注解与资源状态:
POD_NAME=$(kubectl get pods -l app=java-app -o jsonpath='{.items[0].metadata.name}')
kubectl get pod "$POD_NAME" -o yaml
在输出中搜索 CPU Startup Boost 的跟踪注解、原始基线和提升后的 CPU request:
kubectl get pod "$POD_NAME" -o yaml | grep -i -A5 -B2 startupBoost
然后检查原地调整事件:
kubectl get events \
--field-selector reason=InPlaceResizedByVPA \
--sort-by=.lastTimestamp
出现 InPlaceResizedByVPA 事件,说明 VPA 已在 Pod 就绪后执行原地降配。还应结合应用日志和监控比较以下指标:
- Pod 创建到 readiness 成功的时间;
- 启动阶段 CPU throttling;
- readiness probe 失败次数;
- 扩容期间的请求延迟和错误率;
- 节点可分配 CPU 是否足以承载并发启动的多个 boosted Pod。
上生产前需要控制的几个变量
不要把倍数设得过大。 单个 Pod 提升 3 倍看似简单,但滚动发布或突发扩容时,几十个 Pod 会同时申请额外 CPU。节点没有足够容量时,结果可能从“启动慢”变成“Pod 无法调度”。
让 readiness 代表真正可服务。 数据库连接、核心缓存和必要模型尚未加载完成时,不要提前返回成功。durationSeconds 通常应保持较短;与 HPA 配合时,可以从 0 到 10 秒开始测试,避免 HPA 把初始化峰值误认为持续业务负载。
区分主容器和 sidecar。 日志代理、指标采集器和服务网格代理未必需要相同的启动倍数。多容器策略能减少不必要的容量占用。
注意 Autopilot 的资源比例要求。 CPU 提升后,Pod 仍需符合平台要求的 CPU 与内存比例。基线内存配置必须能与启动阶段的 CPU 配置共同满足约束。
建议先选择一个冷启动明显、启动过程受 CPU 限制的无状态服务做灰度实验。记录调整前后的启动耗时、节流时间和调度等待时间,再决定倍数与冷却时间。CPU Startup Boost 最适合解决“短时 CPU 密集、稳态资源较低”的启动模式;如果瓶颈实际来自镜像拉取、数据库迁移、外部 API 或模型下载,单纯增加 CPU 不会消除这些等待。