Upgrading¶
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.24 to v0.1.25¶
v0.1.25 is a GitOps reliability patch. Existing policy YAML keeps working.
Apply CRDs on Helm upgrade¶
Helm does not update CRDs on helm upgrade. This release adds
status.gitopsPR (driftFingerprint, lastAttempt, url) so skip
state survives a Flux or Argo apply that replaces
metadata.annotations. Without the new CRD, the API server prunes
that status object and only annotations remain.
Before helm upgrade, apply:
kubectl apply --server-side --force-conflicts -f \
https://github.com/attune-io/attune/releases/latest/download/crds.yaml
Raw dist/install.yaml / dist/crds.yaml installs already include the
field.
Empty GitOps PRs after upgrade¶
0.1.22 stored last-attempt and PR URL but not a drift fingerprint. After cooldown, 0.1.24 could open another empty PR for the same table. 0.1.25 adopts the live table when a PR URL exists and no fingerprint is stored, and it does not write last-attempt on dry-run (so the first live cycle can still open). See GitOps integration.
v0.1.22 to v0.1.23¶
v0.1.23 is a reliability patch. Existing policies keep working without YAML edits.
Requeue jitter is skipped during data collection¶
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.
Fleet report savings stay finite¶
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.21 to v0.1.22¶
v0.1.22 ships scale defaults and capacity safety that were previously only on
main. Review before upgrading from v0.1.21.
Default PromQL pod aggregation is Max¶
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 Avg
See Scaling: PromQL aggregation and
Scaling: large fleets for operator flags related to large fleets
(maxPodsInMetricsQuery, maxProfileSamples, informer field strip).
Default max concurrent reconciles is 2¶
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.
Request increases fail closed when node status is unavailable¶
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.
Batch throttle chunking (no config change)¶
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.20 to v0.1.21¶
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.
Safe by default (no action required)¶
| 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 |
Behavior that can change without new fields¶
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.
Opt-in features worth enabling deliberately¶
| 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 |
Operator / install notes¶
- 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>
v1alpha1 Field Renames (v0.1.0)¶
Five CRD fields were renamed to align with ecosystem conventions. Existing
AttunePolicy, AttuneDefaults, and AttuneNamespaceDefaults
resources must be updated before applying the new CRDs.
Field mapping¶
| 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 |
Overhead conversion examples¶
| 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 |
Automated migration¶
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.yaml
Helm values migration¶
If 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"