Apply strategies¶
The apply strategy is how the agent puts a change onto a workload in auto-patch. Set it with
spec.apply.strategy in a policy, or per workload with the annotation kerf.getkerf.dev/strategy.
| Strategy | What the agent does | Restarts pods |
|---|---|---|
in-place (default) |
Resizes the running pods through the resize subresource. The webhook gives new pods the same values. The pod template is not touched. |
Only if the container's resizePolicy says so |
rollout |
Patches the pod template, which starts a rolling restart. | Yes |
deferred |
Holds the change until a maintenance window opens, then applies it as a rollout. | Yes, inside the window |
In-place¶
The agent patches each pod's resources and waits for the kubelet to apply them. Because the pod template stays as it is, there is no rollout and no drift for GitOps (GitOps).
A resize can be refused or stall. The agent then falls back to a rollout:
- Infeasible: the node can never fit the new values. The fallback is immediate.
- Deferred by the kubelet: the node cannot fit them yet. The fallback happens after
spec.apply.fallbackAfter(default10m).
A fallback sets the strategy of the RightsizingRecommendation to rollout, records a fallback event, and sticks
until the configured strategy changes. In-place is not used where it cannot work:
- A node with swap blocks in-place memory changes, and a node you list in the agent's
unsupportedNodeSelectors(for example a static CPU or Memory Manager policy) blocks every in-place change. The change is blocked with the reasonUnsupportedNode. - Memory of a JVM or Python container needs
resizePolicy: RestartContaineror a rollout (JVM-aware memory). - An in-place resize cannot remove a limit. A removal reaches new pods through the webhook, or a rollout.
Rollout¶
The agent writes the pod template with server-side apply under the field manager kerf. It owns only the CPU and
memory fields of the resources in auto-patch. When a workload leaves auto-patch, the agent releases them. HPA
coordination always uses a rollout (HPA coordination).
Deferred and maintenance windows¶
With deferred, a change that passes the guardrails waits for a maintenance window. The status of the
RightsizingRecommendation shows phase Deferred and status.nextWindow, and a blocked event with the reason
OutsideMaintenanceWindow is recorded. When the window opens, the agent checks the guardrails again and applies the
change as a rollout. With no maintenance window configured, the change waits.
spec:
apply:
strategy: deferred
maintenanceWindows:
- schedule: "0 2 * * 0" # Sundays at 02:00 ...
duration: 3h # ... for three hours
timeZone: Europe/Berlin
- start: "2026-12-20T00:00:00Z"
end: "2026-12-21T00:00:00Z"
A window is either recurring (schedule, a 5-field cron expression, plus duration; timeZone defaults to UTC)
or one-off (start and end). A policy can list up to 16. An invalid maintenance window counts as closed.
Freeze windows¶
A freeze window blocks every strategy. While one is open, the agent applies nothing, does not release field
ownership, and records blocked with the reason FreezeWindow. Health-watch rollbacks still run, and
an in-place resize that was already submitted is watched to the end, but no new resize starts.
spec:
apply:
freezeWindows:
- schedule: "0 18 * * 5" # Fridays at 18:00 ...
duration: 62h # ... until Monday 08:00
timeZone: Europe/Berlin
Freeze windows use the same format as maintenance windows. An invalid freeze window counts as open, so it errs on the side of not changing anything. Two things freeze in addition to the policy and cannot be overridden by it:
- the cluster-wide
freezeof the agent chart (freeze.now: trueorfreeze.windows); - a pause in Admin → Automation, for one cluster or the whole fleet (reason
Paused).
Which strategy to use¶
| Situation | Use |
|---|---|
| Most workloads on a cluster that supports in-place resize | in-place |
| A workload that must change with a restart, or a node that cannot resize in place | rollout |
| A workload that may only be restarted in an agreed window | deferred with maintenanceWindows |
| No change at all during a period | freezeWindows, on top of any strategy |
Single replicas and OnDelete StatefulSets¶
A change must not leave a single-replica workload without a Ready pod. A workload counts as single-replica if it is a Deployment or StatefulSet with one replica, or if a PodDisruptionBudget allows no disruption of its pods.
- An in-place resize that does not restart a container is safe, so it goes in.
- An in-place resize that restarts a container (
resizePolicy: RestartContainer) is blocked. - A rollout is safe only for a Deployment or DaemonSet with
maxSurgeof at least 1 andmaxUnavailableof 0. ARecreateDeployment and a StatefulSet never qualify. - A blocked change records
SingleReplicaUnsafe. To accept a short disruption, annotate the workload withkerf.getkerf.dev/allow-disruption: "true".
A StatefulSet with updateStrategy: OnDelete only changes a pod when the pod is deleted. After a rollout patches
the template, the agent replaces the outdated pods itself:
- highest ordinal first, one pod at a time by default (
onDelete.maxPodDeletesPerRun); - only when every pod is Ready and has been for 30 seconds (
onDelete.settle), and the health watch reports no breach; - through the eviction API, so PodDisruptionBudgets apply. A refusal is recorded as
PodDisruptionBudget, and the agent retries.