This page covers breaking changes and notable behavior shifts between versions. If you are upgrading from an earlier pre-release, apply every section below your current version (newest sections first).
Maintainers: before publishing a release after multi-version product changes,
run the full E2E Nightly matrix on tip of main (see
Releasing: full E2E matrix).
v0.1.23 is a reliability patch. Existing policies keep working without YAML edits.
While Ready is InsufficientData or PrometheusUnavailable, the operator
no longer adds --requeue-jitter (default 2m) on top of the cooldown.
First recommendations and ConfigMap export can land sooner. Jitter still
applies to steady-state cooldown requeues.
estimatedMonthlySavingsUSD adds only finite numbers. Unparseable values
(NaN, Inf, or garbage) increment unparseableSavings and count as 0 in
the USD total. Consumers of report.json should treat that field as
additive.
v0.1.22 ships scale defaults and capacity safety that were previously only on
main. Review before upgrading from v0.1.21.
When metricsSource.podAggregation is unset, Attune now defaults to Max
(max by (container) over the selected series) instead of leaving series
unaggregated. Recommendations then follow the hottest pod for each container
name, and Prometheus query cost stays proportional to containers rather than
replicas.
If you relied on multi-pod sample pools (legacy unaggregated behavior), set explicitly:
spec:
metricsSource:
podAggregation: None # or AvgSee Scaling: PromQL aggregation and
Scaling: large fleets for operator flags related to large fleets
(maxPodsInMetricsQuery, maxProfileSamples, informer field strip).
The operator default for --max-concurrent-reconciles is 2 (was higher in
some earlier builds). Helm clusterSize presets still override this when set.
Large clusters that previously relied on more concurrent reconcilers should set
the flag or a preset explicitly.
If the operator cannot read node status for a pod, it skips request
increases (decreases still allowed) and increments
attune_capacity_skip_total{reason="unavailable"}. This is protective if node
API access or informer lag fails.
Safety observation batches CPU throttle PromQL queries and splits large pod/container sets into chunks of 64. No CRD field changes; Prometheus load for high-replica policies should drop further under rate limiting.
v0.1.21 is a feature release. Existing policies keep working without YAML edits. Most new capabilities are opt-in. Read this section if you run Kubernetes 1.35+, GitOps export, multi-cluster rollups, or memory limit control.
| Area | Behavior |
|---|---|
| GitOps pull request automation | Off unless export.pullRequest.enabled: true |
| Fleet report ConfigMap export | Off unless fleetReport (or Helm equivalent) is enabled |
| Runtime profiles | Only apply when runtimeProfile is set |
| Export schema versioning | Additive fields on recommendation ConfigMaps; consumers can ignore new keys |
Memory limit decreases on Kubernetes 1.35+. On 1.35+, Attune no longer
clamps memory limits the way it did on 1.33/1.34 when the platform allows
live decreases and the policy uses controlledValues: RequestsAndLimits with
decrease allowed. A usage floor still keeps the target limit above recent
usage (default memory.decreaseUsageMarginPercent: 10). On 1.33–1.34, limit
decreases remain clamped as before.
If you rely on “limits never go down in place,” pin an older cluster version,
set memory.allowDecrease: false, use a restrictive
runtime profile, or keep controlledValues: RequestsOnly
(the default).
Capacity and node pressure. Resizes may be skipped more often when nodes are under pressure; metrics and status explain the skip. This is protective, not a CRD break.
| Feature | Where to start |
|---|---|
| GitOps PR automation | GitOps integration |
| Multi-cluster fleet report | Multi-cluster |
| Language runtime profiles | Runtime profiles |
| Deferred / Infeasible UX | Status conditions + troubleshooting |
| SLO PromQL guardrails (unchanged API; guide improved) | SLO guardrails |
- Refresh CRDs with the release install path (
helm upgradeordist/crds.yaml/dist/install.yamlfrom the tag). - Grafana dashboard and PrometheusRule assets gain panels/alerts for GitOps PR outcomes, memory limit decrease safety, capacity skips, and related signals. Re-apply chart or dashboard ConfigMaps if you manage them out of band.
kubectl attune explainsurfaces GitOps PR and runtime profile effective values; upgrade the plugin with the release for matching CLI help.
After upgrade, confirm policies with:
kubectl attune status -A
kubectl attune explain -n <namespace> <policy>Five CRD fields were renamed to align with ecosystem conventions. Existing
AttunePolicy, AttuneDefaults, and AttuneNamespaceDefaults
resources must be updated before applying the new CRDs.
| Old field | New field | Conversion |
|---|---|---|
safetyMargin: "1.2" |
overhead: "20" |
(old - 1) * 100 |
updateStrategy.mode |
updateStrategy.type |
rename only |
bounds.min / bounds.max |
minAllowed / maxAllowed |
rename only |
InPlaceOrEvict |
InPlaceOrRecreate |
rename only |
excludeContainers |
excludedContainers |
rename only |
updateStrategy.maxCpuChangePercent |
cpu.maxChangePercent |
move to cpu section |
updateStrategy.maxMemoryChangePercent |
memory.maxChangePercent |
move to memory section |
| Old safetyMargin | New overhead | Meaning |
|---|---|---|
"1.1" |
"10" |
10% headroom |
"1.15" |
"15" |
15% headroom |
"1.2" |
"20" |
20% headroom (CPU default) |
"1.3" |
"30" |
30% headroom (memory default) |
"1.5" |
"50" |
50% headroom |
Using sed (covers all five renames):
# All five renames in one pass
sed -i \
-e 's/safetyMargin:/overhead:/g' \
-e 's/overhead: "1.1"/overhead: "10"/g' \
-e 's/overhead: "1.15"/overhead: "15"/g' \
-e 's/overhead: "1.2"/overhead: "20"/g' \
-e 's/overhead: "1.25"/overhead: "25"/g' \
-e 's/overhead: "1.3"/overhead: "30"/g' \
-e 's/overhead: "1.5"/overhead: "50"/g' \
-e 's/InPlaceOrEvict/InPlaceOrRecreate/g' \
-e 's/excludeContainers:/excludedContainers:/g' \
manifests/*.yaml
# mode -> type (only in updateStrategy context to avoid false positives)
sed -i '/updateStrategy/,/^[^ ]/{s/mode:/type:/g}' manifests/*.yaml
# bounds.min/max -> minAllowed/maxAllowed (remove nesting manually if used)Using yq (handles overhead conversion and bounds restructuring):
# Export current policies
kubectl get attunepolicies -n production -o yaml > policies.yaml
# Rename safetyMargin to overhead and convert values
yq -i '
.items[].spec.cpu |= (
.overhead = ((.safetyMargin | tonumber - 1) * 100 | tostring) |
del(.safetyMargin)
) |
.items[].spec.memory |= (
.overhead = ((.safetyMargin | tonumber - 1) * 100 | tostring) |
del(.safetyMargin)
)
' policies.yaml
# Apply the new CRDs first, then re-apply policies
kubectl apply -f config/crd/bases/
kubectl apply -f policies.yamlIf you use the Helm chart with custom defaults.cpu.overhead or
defaults.memory.overhead in your values.yaml, update the values:
# Before
defaults:
cpu:
safetyMargin: "1.2"
memory:
safetyMargin: "1.3"
# After
defaults:
cpu:
overhead: "20"
memory:
overhead: "30"