Installing Helm Charts with Flux
Flux manages Helm charts through two custom resources: a HelmRepository that points at a chart registry, and a HelmRelease that declares what to install from it. Once those manifests are in Git and wired into a Kustomization, Flux handles installs, upgrades, and drift correction automatically.
The trial-first workflow
Section titled “The trial-first workflow”Pushing untested Helm values to Git and waiting for Flux to reconcile is slow. Install the chart imperatively first, confirm it works, capture the values, then migrate to Flux.
helm install → test → helm get values → helm uninstall → flux create --export → commitThis is the normal pattern. Flux is for maintaining desired state, not exploratory work.
1. Install and test
Section titled “1. Install and test”Add the repository and install the chart into its target namespace:
helm repo add prometheus-community https://prometheus-community.github.io/helm-chartshelm repo update
helm install kube-prometheus prometheus-community/kube-prometheus-stack \ -n monitoring --create-namespace --version 82.15.0Verify the pods come up:
kubectl get pods -n monitoringkubectl get svc -n monitoringPort-forward Grafana to confirm it’s functional:
kubectl port-forward -n monitoring svc/kube-prometheus-grafana 3000:80While the trial is running, tune any settings you need — memory limits, resource requests, persistence options. Use helm upgrade to apply them:
helm upgrade kube-prometheus prometheus-community/kube-prometheus-stack \ -n monitoring \ --set prometheus.prometheusSpec.resources.requests.memory=512Mi \ --set prometheus.prometheusSpec.resources.limits.memory=1Gi2. Export the working values
Section titled “2. Export the working values”Once you’re happy, export the values before you remove the release:
helm get values kube-prometheus -n monitoring -o yaml > /tmp/values.exported.yamlFlux needs this file. The -a flag includes chart defaults — omit it so the export only captures what you changed.
3. Remove the trial release
Section titled “3. Remove the trial release”helm uninstall kube-prometheus -n monitoringRemove it so Flux can recreate it from Git. If you leave the release in place, Flux will attempt to adopt it — that works when releaseName and namespaces match, but it’s cleaner to start fresh.
4. Generate Flux manifests
Section titled “4. Generate Flux manifests”Use flux create with --export to generate YAML without applying it:
mkdir -p infrastructure/base/monitoring/
flux create source helm prometheus-community \ --url=https://prometheus-community.github.io/helm-charts \ --interval=1h \ --export > infrastructure/base/monitoring/helmrepository.yaml
flux create helmrelease kube-prometheus \ --source=HelmRepository/prometheus-community \ --chart=kube-prometheus-stack \ --chart-version=82.15.0 \ --release-name=kube-prometheus \ --target-namespace=monitoring \ --interval=5m \ --values=/tmp/values.exported.yaml \ --export > infrastructure/base/monitoring/helmrelease.yamlThe resulting helmrepository.yaml looks like this:
apiVersion: source.toolkit.fluxcd.io/v1kind: HelmRepositorymetadata: name: prometheus-community namespace: flux-systemspec: interval: 1h0m0s url: https://prometheus-community.github.io/helm-chartsAnd helmrelease.yaml:
apiVersion: helm.toolkit.fluxcd.io/v2kind: HelmReleasemetadata: name: kube-prometheus namespace: flux-systemspec: chart: spec: chart: kube-prometheus-stack reconcileStrategy: ChartVersion sourceRef: kind: HelmRepository name: prometheus-community version: 82.15.0 interval: 5m0s releaseName: kube-prometheus storageNamespace: monitoring targetNamespace: monitoring values: prometheus: prometheusSpec: resources: limits: memory: 1Gi requests: memory: 512MiThe HelmRelease lives in flux-system but deploys into monitoring via targetNamespace. The releaseName and storageNamespace fields match what Helm used imperatively, so Flux’s release identity is consistent.
5. Wire into a Kustomization
Section titled “5. Wire into a Kustomization”Flux bootstrap only watches clusters/local/. Add a Flux Kustomization there that points at the monitoring manifests:
apiVersion: kustomize.toolkit.fluxcd.io/v1kind: Kustomizationmetadata: name: infrastructure namespace: flux-systemspec: interval: 10m sourceRef: kind: GitRepository name: flux-system path: ./infrastructure/base/monitoring prune: trueAlso add a kustomization.yaml in infrastructure/base/monitoring/ so Kustomize knows which files to include:
apiVersion: kustomize.config.k8s.io/v1beta1kind: Kustomizationresources: - helmrepository.yaml - helmrelease.yaml6. Commit and reconcile
Section titled “6. Commit and reconcile”git add infrastructure/base/monitoring/ clusters/local/infrastructure.yamlgit commit -m "Add kube-prometheus-stack via Flux"git pushFlux pulls from the remote — it has no access to your local working copy. Trigger an immediate reconcile after pushing:
flux reconcile source git flux-systemflux reconcile kustomization flux-systemThe chain: flux-system reads clusters/local/, finds infrastructure.yaml, follows the path to infrastructure/base/monitoring/, and applies the HelmRepository and HelmRelease.
Verifying the result
Section titled “Verifying the result”flux get kustomizationsflux get helmreleases -Akubectl get pods -n monitoringA healthy install looks like:
NAME REVISION SUSPENDED READY MESSAGEinfrastructure main@sha1:99348924 False True Applied revision: main@sha1:99348924
NAMESPACE NAME REVISION SUSPENDED READY MESSAGEflux-system kube-prometheus 82.15.0 False True Helm install succeeded for release monitoring/kube-prometheus.v1 with chart kube-prometheus-stack@82.15.0To force reconciliation of a specific release:
flux reconcile helmrelease kube-prometheus -n flux-systemSuspending Flux during experiments
Section titled “Suspending Flux during experiments”Flux’s drift correction will revert any manual helm install that conflicts with what’s in Git. If you need to experiment on something Flux already manages, suspend it first:
flux suspend kustomization flux-system# ... experiment ...flux resume kustomization flux-system