DevCloudLab More courses at DevCloudLab.com →
FLUX CD · SECTION 3 · LECTURE 9

DevCloudLab

Automating Helm Release upgrades

Section 3, Lecture 9, from the Flux CD course by DevCloudLab.


Correction: near the start (about 0:27) the video says that changing the chart version with every change “could be meaningful in many cases”. It should say the opposite: in a development environment, bumping the chart version on every change is not practical in many cases. That is the problem this lecture solves.

What you’ll learn

Overview

This lecture explores how Flux CD automates Helm chart upgrades using two different mechanisms, and how to pause either of them:

  1. Revision-based updates: for a chart whose source is a Git repository, update the Helm release whenever the chart’s source files change, with no version bump needed.
  2. Version-based updates: for a chart pulled from a Helm repository (HTTP or OCI), update when a new chart version is published, bounded by a semantic-versioning constraint.

You will also learn how to force a pod restart when a ConfigMap changes, using a checksum annotation, and how to hold a release still with suspend.

The one rule that decides which mechanism you get. reconcileStrategy applies to Git-sourced charts. version applies to Helm-repository-sourced charts: Flux ignores spec.chart.spec.version when the source reference is a GitRepository or a Bucket. Pick the source first, then the mechanism.

Key Concepts

Reconcile strategy

The reconcileStrategy field lives under spec.chart.spec in a HelmRelease and decides when Flux CD produces a new chart artifact:

Semantic versioning (SemVer)

Semantic versioning uses three components: MAJOR.MINOR.PATCH

In Flux CD, a constraint such as >=9.0.0 <10.0.0 lets the release take every 9.x release published and stop before the next major.

ConfigMap checksum annotation

Changing a ConfigMap does not restart the pods that mount it. That is Kubernetes behaviour, not a Flux CD limitation. The usual fix is to make the pod template itself change whenever the ConfigMap does:

checksum/config: 

Put it under spec.template.metadata.annotations in the Deployment template, alongside the existing labels:, not in place of them: the Service and the Deployment’s own selector match on those labels.

The suspend parameter

suspend: true at the spec level of a HelmRelease stops Flux CD reconciling it at all. No chart is resolved, no upgrade is attempted, whatever the source publishes. Set it back to false, or delete the field, and the next reconciliation catches up in one step.

Common commands

Git operations

# Check out the main branch and pull latest changes
git checkout main
git pull

# Create a new branch for your changes
git checkout -b branch-name

# Commit and push changes
git add -A
git commit -m "Your commit message"
git push --set-upstream origin branch-name

# Merge the branch back into main. Flux only watches the branch it was
# bootstrapped on, so work that stays on a feature branch never reaches it
git checkout main
git merge branch-name
git push origin main

Flux CD operations

# Reconcile Flux CD to pick up changes immediately
flux reconcile kustomization flux-system --with-source

# The state of a Helm release, including whether it is suspended
flux get helmrelease <name> -n <namespace>

# Check Helm release status with Helm itself
helm list
helm list | grep <release-name>

# Get details of a specific Helm release
helm status <release-name>

# Uninstall a Helm release
helm uninstall <release-name> -n <namespace>

Helm chart operations

# Package a Helm chart
helm package path/to/chart

# Log in to an OCI registry before pushing to it
helm registry login -u <your-username> registry.example.com

# Push a packaged chart to an OCI registry
helm push chart-name-version.tgz oci://registry.example.com/path

# Show a chart's values
helm show values <chart>

# Show a chart's metadata, resolving a version constraint
helm show chart oci://registry.example.com/path/mychart --version '>=9.0.0 <10.0.0'

Complete example manifests

Replace <your-gitlab-username> with your own GitLab username wherever it appears below.

Nginx HelmRelease with the Revision strategy (Git source)

apiVersion: helm.toolkit.fluxcd.io/v2
kind: HelmRelease
metadata:
  name: nginx
  namespace: default
spec:
  interval: 1m
  chart:
    spec:
      chart: ./charts/nginx
      version: 0.1.0
      reconcileStrategy: Revision
      sourceRef:
        kind: GitRepository
        name: flux-system
        namespace: flux-system
  values:
    indexHtml: |-
      <!doctype html>
      <html>
      <head>
        <title>Welcome to the page</title>
      </head>
      <body>
        <h1>Changing a ConfigMap should restart the pod</h1>
        <h2>This is the second line in the Welcome page</h2>
      </body>
      </html>

name: flux-system is the GitRepository that flux bootstrap creates. Unless you have added another source of your own, it is the only one in the cluster.

Nginx deployment template with the checksum annotation

apiVersion: apps/v1
kind: Deployment
metadata:
  name: 
spec:
  replicas: 
  selector:
    matchLabels:
      app: 
  template:
    metadata:
      annotations:
        checksum/config: 
      labels:
        app: 
    spec:
      containers:
      - name: nginx
        image: ":"
        ports:
        - name: http
          containerPort: 80
        volumeMounts:
        - name: html
          mountPath: /usr/share/nginx/html
      volumes:
      - name: html
        configMap:
          name: -html

Nginx ConfigMap template

apiVersion: v1
kind: ConfigMap
metadata:
  name: -html
data:
  index.html: |

The HelmRelease above sets indexHtml, this template reads it, and the annotation in the Deployment hashes this rendered file. That is the whole chain: change the value, the ConfigMap changes, the checksum changes, the pod restarts.

MySQL: a public OCI Helm repository and a version range

apiVersion: source.toolkit.fluxcd.io/v1
kind: HelmRepository
metadata:
  name: mysql
  namespace: default
spec:
  type: oci
  interval: 5m0s
  url: oci://registry-1.docker.io/bitnamicharts
---
apiVersion: helm.toolkit.fluxcd.io/v2
kind: HelmRelease
metadata:
  name: mysql
  namespace: default
spec:
  interval: 1m
  chart:
    spec:
      chart: mysql
      version: '>=9.0.0 <10.0.0'
      sourceRef:
        kind: HelmRepository
        name: mysql
        namespace: default
      interval: 1m
  values:
    # Bitnami moved its images out of the free Docker Hub catalog in 2025, so
    # older charts point at tags that no longer resolve. The images are still
    # published under bitnamilegacy.
    global:
      security:
        allowInsecureImages: true
    image:
      repository: bitnamilegacy/mysql
    primary:
      persistence:
        enabled: false
    auth:
      username: "myuser"
      password: "mypassword"
      database: "mydatabase"

With that constraint, Flux resolves the newest chart inside major 9 (at the time of recording, 9.23.0). Versions 10.0.0 and later exist in the same registry and are skipped, which is the entire point of the constraint.

Apache: a private OCI Helm repository and suspend

apiVersion: helm.toolkit.fluxcd.io/v2
kind: HelmRelease
metadata:
  name: apache
  namespace: default
spec:
  interval: 1m
  suspend: true
  chart:
    spec:
      chart: apache
      version: '>= 0.1.0 < 1.0.0'
      sourceRef:
        kind: HelmRepository
        name: gitlab
        namespace: default
      interval: 1m

The gitlab HelmRepository it refers to is the private OCI registry from the earlier lecture:

apiVersion: source.toolkit.fluxcd.io/v1
kind: HelmRepository
metadata:
  name: gitlab
  namespace: default
spec:
  type: oci
  interval: 5m0s
  url: oci://registry.gitlab.com/<your-gitlab-username>/myfluxrepo-2026
  secretRef:
    name: gitlab-credentials

Publishing a new chart version to it is two commands:

helm package .
helm push apache-0.1.1.tgz oci://registry.gitlab.com/<your-gitlab-username>/myfluxrepo-2026

While suspend: true is in place, that new version sits in the registry and nothing happens. Change it to suspend: false (or remove the field), commit, and the release moves to 0.1.1 on the next reconciliation.

Further reading


DevCloudLab

Built by DevCloudLab
Hands-on cloud-native courses: Kubernetes, GitOps, CI/CD and the cloud.
Visit DevCloudLab.com →