Skip to content

Startup Boost

Some applications need significantly more CPU during startup than at steady state. JVMs perform class loading and JIT compilation, ML models load weights into memory, and interpreted runtimes compile bytecode. Rather than over-provisioning permanently, StartupBoost applies a temporary CPU multiplier that expires after a configurable duration.

How it works

Startup boost has two apply paths.

CREATE webhook. When a matching policy has a recommendation and initialSizing is on, the mutating webhook writes recommended_cpu * multiplier onto the new pod. Job and CronJob pods are admitted at the steady recommendation only. Boost never applies there because batch pods are not resized in place, so expiry cannot run. Recommend mode CREATE is limited to CronJob and Job owners. In RequestsAndLimits mode the webhook raises the CPU dest with the boosted request only when rec dest is non-zero, so Guaranteed pods still get headroom. A zero rec dest dest-caps leftover dest only and does not invent dest.

In-place resize. After the pod is running, the operator detects a newly created pod whose age (now minus pod.CreationTimestamp) is still within startupBoost.duration. Container start time is not used. It resizes each eligible container's CPU request to recommended_cpu * multiplier. Native sidecars (init containers with restartPolicy: Always) are included. Known sidecar names such as istio-proxy stay excluded via EffectiveExcludedContainers. RequestsAndLimits raises dest with the boosted request only when rec dest is non-zero, the same way CREATE does. A zero rec dest dest-caps leftover dest only.

After a successful apply, the operator writes attune.io/startup-boost-at with a metadata merge patch, so a kubelet status update does not clear the stamp. The same patch writes attune.io/startup-boost-containers, the containers that were boosted or already at the boost target. Expiry resizes only those containers back to the steady-state recommendation. A container that was above the target is not in the list, so expiry does not shrink it. A stamp from an older release has no list and still expires every container. The boost expires when that timestamp plus duration elapses. Container Ready is not checked.

excludeFromHistory is separate from the boost apply. When it is true, CPU samples from the boost window are left out of the percentile. The window starts at attune.io/startup-boost-at when that stamp is set and not before pod creation. A missing or unreadable stamp starts at CreationTimestamp. The cutoff is that start plus duration plus the rate window. Sample timestamps are the end of rate(), so the rate window is part of the cutoff. A sample exactly at the cutoff stays. Nil and false keep today's percentile. Memory samples are unchanged. Deleted pods stay in history until historyWindow, because there is no creation time or stamp to cut on. A recreated pod keeps samples older than its new creation time. A series with no pod label is left unfiltered. Prometheus uses max by (pod, container) for that CPU query so each pod and container is one series. If that query is larger than --max-prometheus-series, each pod is represented before any pod gets a second series, and the series chosen for a pod is the container with fewer series kept. A cap smaller than the number of containers leaves some containers without CPU samples.

If the boosted CPU would exceed maxAllowed or the node's allocatable CPU, the boost is capped. RequestsOnly also dest-caps leftover dest and does not raise dest.

Native sidecars

Init containers with restartPolicy: Always follow the same apply and expiry path as regular containers. Known sidecar names (istio-proxy, and the rest of the built-in list) remain auto-excluded unless you set excludeKnownSidecars: false. See Istio integration.

Configuration

Add startupBoost to the CPU resource config:

apiVersion: attune.io/v1alpha1
kind: AttunePolicy
metadata:
  name: jvm-api
  namespace: production
spec:
  targetRef:
    kind: Deployment
    name: jvm-api
  metricsSource:
    prometheus:
      address: http://prometheus-server.monitoring:80
  cpu:
    percentile: 95
    overhead: "20"
    startupBoost:
      multiplier: "3.0"   # 3x the steady-state recommendation
      duration: 2m         # boost expires 2 minutes after pod creation
    minAllowed: "100m"
    maxAllowed: "8000m"
  memory:
    percentile: 99
    overhead: "30"
  updateStrategy:
    type: Auto
    cooldown: 1h

Parameters

Field Type Constraints Description
multiplier string > 1.0, <= 10.0 Scales the recommended CPU request during startup
duration Duration >= 10s, <= 1h Maximum time the boost remains active
excludeFromHistory bool omitted (false) When true, drop CPU samples from attune.io/startup-boost-at when that stamp is set and not before creation, otherwise from CreationTimestamp, until that start plus duration plus rateWindow. A sample at the cutoff stays. Samples older than creation stay. Nil and false keep today's percentile. Deleted pods stay until historyWindow.

Choosing a multiplier

Workload type Typical multiplier Typical duration
Spring Boot / JVM 2.0 - 3.0 1m - 3m
.NET / ASP.NET Core 1.5 - 2.0 30s - 1m
ML model loading (PyTorch, TensorFlow) 3.0 - 5.0 2m - 5m
Node.js / Python (light init) 1.5 30s

Start conservative (2.0x, 2m) and increase if startup is still slow. Check container startup time in your monitoring to calibrate duration.

Interaction with bounds

The boost is applied after bounds clamping. If the boosted value exceeds the configured maxAllowed, it is capped at maxAllowed. Set maxAllowed high enough to accommodate the boosted value if you want the full multiplier effect. With cpu.controlledValues: RequestsAndLimits, dest is raised with the boosted request only when rec dest is non-zero, so Guaranteed pods keep request equal to dest and still receive headroom. A zero rec dest dest-caps leftover dest only and does not invent dest. RequestsOnly dest-caps leftover dest and does not raise dest.

For example, with a 500m recommendation, 3.0x multiplier, and maxAllowed of 1000m, the boosted request will be 1000m (capped), not 1500m.

Monitoring

The operator tracks startup boost activity through the metric:

attune_startup_boost_total

This counter increments each time a startup boost is applied. Use it to track how often boosts fire and whether duration covers the startup window (expiry is attune.io/startup-boost-at plus duration, not container Ready).

The pre-built Grafana dashboard includes a Startup Boost panel that visualizes this metric.

Limitations

  • StartupBoost only applies to CPU. Memory startup spikes are handled by the standard overhead and percentile configuration.
  • The boost requires the operator to be running when pods start. If the operator is down during a deployment, pods start with their current requests and receive the boost on the next reconcile (if still within the duration window).
  • In-place boost requires a resize-capable mode (Auto, OneShot, or Canary). CREATE webhook boost also applies in Recommend mode when the pod owner is a CronJob or Job, because those pods cannot be resized in place. Observe mode never applies a boost.

See examples/14-startup-boost.yaml for a complete example.