Skip to main content
RunBook Academy

Git, CI/CD & GitOpsLXXVIII · FluxHelm

HelmRelease controller — reconciling Helm charts with versioned values

Advanced⏱ ~27 mingitfluxhelm

What you'll learn

  • Describe what helm-controller does and which CRD it owns
  • Read a HelmRelease spec and identify the chart source, values, and lifecycle fields
  • Configure valuesFrom to source values from ConfigMaps and Secrets
  • Use `flux create helmrelease` to manage a HelmRelease against a HelmRepository or OCIRepository source

Prerequisites

Verified against Git 2.55.x teaching target; 2.40+ minimum · GitHub Actions continuous service; Aug 2026 documentation baseline · Argo CD v3.5.x teaching target; v3.0+ minimum · Flux v2.9.x · Sigstore Cosign v3.1.x · SLSA v1.2 · OCI Distribution Specification v1.1 · Git LFS v3.7.1 · Kubernetes (cross-course target) 1.36.x

Not yet marked complete on this device.

helm-controller reconciles Helm charts inside Flux the same way kustomize-controller reconciles Kustomize directories. It owns the HelmRelease CRD, consumes a chart source, renders the chart with declared values, and drives the Helm lifecycle.

What helm-controller does

The controller watches HelmRelease CRDs. For each one it performs four phases per reconcile:

  1. Resolve chart. Look up the source CRD in spec.chart.spec.sourceRef, fetch the artifact, locate the chart.
  2. Resolve values. Combine inline spec.values, files in spec.valuesFrom, and chart defaults.
  3. Reconcile release. Install if missing; upgrade if present; optionally rollback on upgrade failure.
  4. Report status. Write the release revision and status into the HelmRelease’s status section.
flowchart LR
    HR["HelmRelease CRD"] --> HC["helm-controller"]
    HC --> C["Resolve chart source"]
    C --> V["Resolve values"]
    V --> R["Render with helm template"]
    R --> D["Diff against live release"]
    D -->|"release missing"| IN["helm install"]
    D -->|"diff present"| UP["helm upgrade"]
    D -->|"diff empty"| OK["Ready=True"]
    UP --> K8s["Cluster"]
    IN --> K8s

The release status comes from Helm itself, not from kstatus-based health checks. A HelmRelease that is Ready=True means the Helm release is deployed.

The HelmRelease spec

A HelmRelease against a HelmRepository:

apiVersion: helm.toolkit.fluxcd.io/v2beta2
kind: HelmRelease
metadata:
  name: ingress-nginx
  namespace: ingress
spec:
  releaseName: ingress-nginx
  chart:
    spec:
      chart: ingress-nginx
      version: "4.10.x"
      sourceRef:
        kind: HelmRepository
        name: ingress-nginx
        namespace: flux-system
  interval: 10m0s
  values:
    controller:
      replicaCount: 3
  valuesFrom:
    - kind: ConfigMap
      name: ingress-nginx-config
      valuesKey: values.yaml
      targetPath: values.yaml
  upgrade:
    cleanupOnFail: true
  driftDetection:
    mode: enabled
  • spec.chart.spec.chart and spec.chart.spec.version
    • chart name and semver range.
  • spec.chart.spec.sourceRef - the source CRD (HelmRepository, OCIRepository, or GitRepository).
  • spec.interval - reconcile cadence. Default is 10m0s.
  • spec.values - inline values merged with chart defaults.
  • spec.valuesFrom - values sourced from Kubernetes resources (ConfigMap or Secret).
  • spec.upgrade.remediation.retries - retry budget for upgrade failures.
  • spec.driftDetection.mode - enabled re-renders the chart on every reconcile and compares against the live state.

Creating a HelmRelease

flux create helmrelease ingress-nginx \
  --source=HelmRepository/ingress-nginx \
  --chart=ingress-nginx \
  --chart-version="4.10.x" \
  --values=controller.replicaCount=3 \
  --values-from=ConfigMap/ingress-nginx-config/values.yaml \
  --export

--source takes Kind/name. --values repeats per override; --values-from per referenced ConfigMap or Secret. --export prints the YAML.

flux get helmreleases
flux get helmrelease ingress-nginx --status
flux reconcile helmrelease ingress-nginx

flux get helmrelease --status includes the release revision, chart revision, and last-applied values.

Rollback and the install/upgrade lifecycle

helm-controller tracks every Helm revision it installs or upgrades. When a release’s health degrades, the controller does not automatically rollback - that is a deliberate decision the team owns.

flux helm rollback ingress-nginx 3

flux helm rollback $RELEASE $REVISION triggers a Helm rollback to the named revision. The next reconcile reports Ready=True against the rolled-back state.

Under the hood

helm-controller runs the actual Helm binary inside its pods. It shells out to helm install, helm upgrade, helm rollback, and helm test. This is what guarantees parity with the Helm the rest of the ecosystem uses.

Production discipline

  1. spec.chart.spec.version is pinned or semver-bounded. Pin to a patch range like "4.10.x".
  2. spec.valuesFrom is the source for every secret. No secret in spec.values.
  3. spec.driftDetection.mode=enabled is paired with a policy that disallows out-of-band helm upgrade in the namespace.

Cross-course references

  • Kubernetes for Production Sysadmins - Part XXXI (Ingress and Service Mesh) covers ingress-nginx.

Quiz

Knowledge check · 4 questions

  1. Q1. Which spec field in a HelmRelease references external values stored in a Kubernetes ConfigMap or Secret?

  2. Q2. Setting `spec.driftDetection.mode=enabled` causes helm-controller to automatically revert any out-of-band `helm upgrade` applied to the same release.

  3. Q3. Name the three CRD kinds that can be used as `spec.chart.spec.sourceRef`, and identify which one resolves a chart stored in a classic Helm chart registry.

  4. Q4. Diagnose why the HelmRelease for ingress-nginx is reporting Ready=False, reason=InstallFailed, and recommend the fix.

    A team runs `flux get helmreleases` and sees ingress-nginx reporting Ready=False, reason=InstallFailed. The team runs `flux logs` against helm-controller and sees: `Error: failed to render template: template: ingress-nginx/templates/controller-deployment.yaml:42: function 'lookup' not defined`. The chart's `values.yaml` calls the `lookup` template function, which requires Helm v3.7+. The cluster's helm-controller runs Helm v3.6.

Passing score: 75%. Answers are checked in this browser.