Home / Stories / Version upgrades
Story · Lifecycle Live

An upgrade that stops at the right version, and tells you why.

Your monitoring stack is eleven major versions behind. A jump straight to the newest release would break it. A bump of one patch at a time would take a year. The assistant reads every changelog in between. It checks which breaking changes actually touch your configuration. Then it proposes the biggest safe step.

Starts fromA HelmRelease (a Flux object that installs a Helm chart), an OCI source or a container image that runs in the cluster.
Looks atChart indexes and registries. GitHub releases and changelogs. Your HelmRelease values. A render of both versions.
You getA draft merge request (MR) with the version bump. It gives the reasoning for the target and the breaking changes that apply. It also says what to check after you merge.
01 · Start from what runs

The cluster, not just the repo.

The daily upgrade scan starts from the live HelmReleases, OCI sources and container images. It links each one back to the file in git that declares it. The assistant treats a release that exists only in git, or only in the cluster, differently from one that is in both.

Here the assistant finds kube-prometheus-stack, pinned at 61.3.2. Your team has tuned its values block over the years.

02 · What is out there

Check the chart repository for every newer release.

The assistant fetches the index.yaml of the chart (or lists OCI tags). It uses your repository credentials where needed. It drops pre-releases. It skips versions that you or we marked known-bad.

Container images get the same treatment through Docker Hub, GHCR and your own registries.

03 · Read the changelogs

Every hop between here and there, oldest first.

Release notes come from GitHub releases. If a project publishes no releases, they come from CHANGELOG.md / UPGRADE.md. The assistant extracts each breaking change and sorts it into a class. The classes are a values rename, a required step, a CRD change and a migration path.

If the assistant cannot fetch a changelog, the MR says so in a banner and the risk goes up. The assistant never reports missing evidence as "no breaking changes".

04 · Does it affect you?

A breaking change only counts if it touches your values.

The assistant checks each finding against your HelmRelease values. It also checks against a render of the chart with those values. Helm never installs the versions in between. So a change that 63 introduces and 64 reverts is irrelevant to a jump past 64.

Required-step changes are hard stops. Your values do not change that.

05 · Pick the boundary

The highest version before the first change that applies.

The rule is simple, and the MR states it. If breaking-change evidence is in range, the assistant stops just before it and quotes the excerpt. If there is none, it goes up to a year of releases in one step.

Here the first stop that applies is 67.0.0, so the target is 66.7.1. That is five major versions in one reviewed MR. The next step becomes its own MR after you merge this one.

06 · Render both versions

See what really changes in the cluster.

The assistant runs helm template at the current and at the target version with your values. It then compares the two outputs. This shows what the version string hides, such as new CRDs, changed selectors and a container that gains an argument.

Changes to load-bearing fields raise the risk, and the MR calls them out. These fields are container specs, Service ports, RBAC and storage.

07 · Ask the API server

Would the cluster accept this? Asked before you review.

The assistant checks the rendered objects against the CRD schemas that the cluster actually serves. It can also send the changed HelmRelease as a server-side dry-run: the API server tests the change but does not apply it. This dry-run is in development. It runs in observe mode, so it records the result but does not change the proposal. The objects that the chart renders are not sent yet. A dedicated identity sends the request, and an admission policy limits that identity to dry-run only. It can ask, but it can never apply.

08 · The proposal

A one-line diff, and everything you need to trust it.

The diff is tiny. The MR body carries the reasoning. It says why the assistant chose this version and not the newest. It lists which breaking changes apply and what to do about them. It lists what the assistant could not evaluate, and what to watch after you merge. The full MR is below.

infrastructure/monitoring/helmrelease_kube-prometheus-stack.yaml
apiVersion: helm.toolkit.fluxcd.io/v2
kind: HelmRelease
metadata:
  name: kube-prometheus-stack
  namespace: monitoring
spec:
  chart:
    spec:
      chart: kube-prometheus-stack
      version: 61.3.2
      sourceRef: { kind: HelmRepository, name: prometheus-community }
  values:
    prometheus:
      prometheusSpec:
        retention: 15d
        serviceMonitorSelectorNilUsesHelmValues: false
    alertmanager: { … 40 lines … }
live: HelmRelease monitoring/kube-prometheus-stack · Ready · chart 61.3.2 · declared in git ✓
prometheus-community/index.yaml · kube-prometheus-stack
  • 61.3.2 current
  • 62.7.0 · 63.1.0 · 64.2.0 · 65.5.1 stable
  • 66.7.1 stable
  • 67.0.0 … 70.4.2 stable
  • 71.0.0-rc.1 pre-release · skipped
  • 72.9.1 newest stable
11 majors behind newest · 1 year window ends at 70.4.2
changelog research · github releases, oldest first
fetched 38 / 38 release notes · 0 gaps
  • 62.0.0 CRD bump, handled by chart hook
  • 63.0.0 values_incompatibility · *SelectorNilUsesHelmValues deprecated
  • 64.0.0 reverts 63.0.0 selector change
  • 65.0.0 · 66.0.0 dependency bumps, no BC
  • 67.0.0 step_required · Prometheus 3 image major
  • 69.0.0 step_required · operator CRD migration
applicability · against your values over (61.3.2, target]
  • 63.0.0 selector deprecation you set 1 of these keys…
  • …but 64.0.0 reverts it moot for any jump past 64
  • 67.0.0 Prometheus 3 step_required · hard stop
# quoted from the 67.0.0 release notes
"This version upgrades Prometheus to 3.x. Review the Prometheus
 3 migration guide before upgrading; some flags and feature
 flags were removed."
target selection
61.3.2now
63moot
64reverts
66.7.1target
67stop
69stop
72.9.1newest
helm template · 61.3.2 vs 66.7.1 · your values
Deployment/monitoring/kube-prometheus-stack-operator
-        image: quay.io/prometheus-operator/prometheus-operator:v0.75.2
+        image: quay.io/prometheus-operator/prometheus-operator:v0.79.2
Prometheus/monitoring/kube-prometheus-stack-prometheus
-  version: v2.53.1
+  version: v2.55.1
CustomResourceDefinition (6)                     schema updated
ServiceMonitor (14)                              unchanged
Service ports · RBAC · PVC templates              unchanged
no load-bearing field changes outside the expected image bumps
Rendered objects66.7.1 + values
CRD schemasas served by cluster
API serverdryRun=All
admission · identity limited to dry-run by policy
✓ 212 objects schema-valid
✓ server-side dry-run: accepted
  a real apply by this identity is refused by admission policy
Draft !241 · Upgrade kube-prometheus-stack 61.3.2 → 66.7.1
      chart: kube-prometheus-stack
-     version: 61.3.2
+     version: 66.7.1
category:upgradesource:upgraderisk:mediumxrev::LGTM
↓ the full merge request is below

The merge request you get.

This example is illustrative, but it has exactly the shape of the real thing. The assistant writes these section headings and this target rule today.

Draft

Upgrade kube-prometheus-stack 61.3.2 → 66.7.1

from gitops-ai/upgrade-kube-prometheus-stack-66.7.1 into main · 1 file · +1 −1
category:upgradesource:upgraderisk:mediumxrev::LGTM
OverviewBreaking changesValidationChanges
Summary

This MR upgrades the kube-prometheus-stack chart in monitoring from 61.3.2 to 66.7.1. The newest published version is 72.9.1. This MR stops at 66.7.1 on purpose.

Why 66.7.1?

Stopped at 66.7.1 because of a breaking change in 67.0.0 (step_required):

This version upgrades Prometheus to 3.x. Review the Prometheus 3 migration guide before upgrading; some flags and feature flags were removed.

The 63.0.0 selector deprecation matches a key set in this HelmRelease, but 64.0.0 reverts it, so it does not apply to a jump past 64.

Why not 72.9.1?

To cross 67.0.0, you need the Prometheus 3 checks listed under Next step. A follow-up MR will propose 66.7.1 → 68.x after you merge this one and it is healthy.

Could not evaluate

Nothing. The assistant fetched 38 of 38 release notes. The render pair and the dry-run completed.

VersionClassApplies to this release?
62.0.0CRD updateHandled by the chart's CRD upgrade job. No action.
63.0.0values_incompatibilityMoot: reverted in 64.0.0, never installed.
65.0.0dependency major (grafana subchart)Not applicable: grafana.enabled: false.
67.0.0step_requiredHard stop. Outside this MR.
Checked before this MR was opened
  • Render diff 61.3.2 → 66.7.1 with the values of this release. It shows image bumps for the operator and Prometheus, and 6 CRD schema updates. It shows no Service / RBAC / PVC changes.
  • 212 rendered objects valid against the CRD schemas served by the cluster.
  • Server-side dry-run accepted by the API server.
After merge, expect
  • flux get hr -n monitoring kube-prometheus-stack shows 66.7.1, Ready.
  • The operator pod restarts once. Prometheus and Alertmanager restart one pod at a time.
  • The Targets page shows the same number of active targets as before. No ServiceMonitor is dropped.
  • No new PrometheusOperatorRejectedResources alerts in the first 30 minutes.
Rollback

Revert this MR. The CRDs of the chart are backward compatible within this range.

   chart:
     spec:
       chart: kube-prometheus-stack
-      version: 61.3.2
+      version: 66.7.1
       sourceRef:
         kind: HelmRepository
         name: prometheus-community
R
independent reviewer second opinion, no pipeline context

Read the 62–67 release notes again. Confirmed the 63/64 revert pair and the 67 stop. The render diff matches the claimed scope. LGTM.

Not every upgrade is a version string.

The same research drives the cases where a bump alone would upgrade nothing, or would break something.

Bump that changes nothingA StatefulSet with updateStrategy: OnDelete keeps running the old image after a chart bump. The MR says so. It lists the rollout steps for each pod. For Vault, you delete the pod, then unseal it, one pod at a time.
Prerequisites before undraftingIf a named external step must happen first, the MR stays a draft. It has a numbered "complete before undrafting" banner at the top.
Moved or abandoned chartsSome charts moved to a new repository. Some projects were archived or froze their public images. For these, the assistant proposes a repoint or a migration. It does not propose a dead-end bump.
Staged upgradesIf no safe intermediate hop exists, you get an issue with the evidence. The evidence can include sibling releases that are already ahead, CRD stored versions and a render contract. You do not get a risky MR.
Known-bad releasesThe assistant skips versions with known regressions. The MR lists what it skipped and why.
Honest about gapsIf the assistant cannot fetch the changelogs, the MR carries an "unverified breaking changes" banner and higher risk. The assistant never reads silence as safety.

Where this stands.

Live
  • Helm charts (Flux v1 and v2), OCI sources, container images
  • Changelog research, applicability against your values, boundary targeting
  • Render diff at both versions, CRD schema validation
  • 150+ upgrades merged since April 2026, 25+ of them major
In development
  • Server-side dry-run of the HelmRelease (observe mode, result not yet used) and of the objects the chart renders
  • Direct OCI tag discovery for charts without an index
Roadmap
  • Argo CD Applications as upgrade targets
  • Ansible role and collection versions
← Previous storyMonitoring & Grafana dashboards