Flux v2 Reference: GitRepository, Kustomization, HelmRelease, Image Automation & SOPS
Flux v2 (FluxCD) is a CNCF-graduated GitOps tool that continuously reconciles your Kubernetes cluster state with a Git repository. It uses a controller-based architecture rather than ArgoCD’s server-and-agent approach.
1. Flux vs ArgoCD
When to choose Flux, when to choose ArgoCD
| Feature | Flux v2 | ArgoCD |
|---|---|---|
| Architecture | Set of independent controllers (modular) | Server + agent + UI (monolithic) |
| UI | No built-in UI (use Weave GitOps or CLI) | Built-in web UI |
| Multi-tenancy | Native (per-namespace controllers) | AppProject + RBAC |
| Multi-cluster | Single cluster per Flux install | Can manage multiple clusters from one ArgoCD |
| Bootstrap | flux bootstrap github — one command |
Separate install + app creation |
| Secret management | SOPS + age/gpg built-in | Vault plugin or Sealed Secrets |
| Helm support | HelmRelease CRD | Application with Helm source |
| Notifications | notification-controller built-in | Webhook + email |
# Rule of thumb: # ArgoCD: teams that want a UI, single control plane for many clusters # Flux: pure GitOps, no UI, better multi-tenancy, SOPS secrets # Both: excellent choices, often co-exist in large orgs
2. Bootstrap & CLI
Install Flux and connect it to your Git repo
# Install flux CLI: brew install fluxcd/tap/flux # macOS curl -s https://fluxcd.io/install.sh | bash # Linux flux --version flux check --pre # verify prerequisites (K8s version, etc.) # Bootstrap to GitHub (creates flux-system namespace + pushes manifests to repo): export GITHUB_TOKEN=ghp_xxx flux bootstrap github --owner=myorg --repository=fleet-infra \ # repo to store Flux manifests (created if missing) --branch=main --path=clusters/my-cluster \ # path in repo where Flux will write its manifests --personal # use personal account (omit for org) # Bootstrap to GitLab: export GITLAB_TOKEN=glpat-xxx flux bootstrap gitlab --owner=mygroup --repository=fleet-infra --branch=main --path=clusters/my-cluster # After bootstrap, Flux manages itself — changes to flux-system/ folder in repo are auto-applied # Verify installation: flux get all # all Flux objects and their status flux get kustomizations # kustomization controllers flux get helmreleases # Helm releases managed by Flux kubectl get pods -n flux-system # 5 controllers should be running
3. GitRepository + Kustomization
Core sources and sync configuration
# GitRepository: defines the source (what to sync from)
apiVersion: source.toolkit.fluxcd.io/v1
kind: GitRepository
metadata:
name: my-app
namespace: flux-system
spec:
interval: 1m # check for new commits every minute
url: https://github.com/myorg/my-app
ref:
branch: main # or: tag: v1.0.0 / semver: ">=1.0.0"
secretRef:
name: github-credentials # Secret with username + password/token (for private repos)
# Kustomization: defines what to deploy from the source
apiVersion: kustomize.toolkit.fluxcd.io/v1
kind: Kustomization
metadata:
name: my-app
namespace: flux-system
spec:
interval: 5m # re-apply every 5m even without git changes (drift correction)
path: "./k8s/overlays/production" # path in the GitRepository to reconcile
sourceRef:
kind: GitRepository
name: my-app
prune: true # delete resources removed from Git
targetNamespace: production # force all resources into this namespace
healthChecks: # wait for these to be healthy before marking done
- apiVersion: apps/v1
kind: Deployment
name: my-app
namespace: production
postBuild: # variable substitution
substituteFrom:
- kind: ConfigMap
name: cluster-vars # ${CLUSTER_NAME} → value from ConfigMap
# Check sync status:
flux get kustomizations -A
flux describe kustomization my-app -n flux-system
flux reconcile kustomization my-app --with-source # force immediate sync
4. HelmRelease
Deploy Helm charts with GitOps — values in Git, not helm upgrade
# HelmRepository source:
apiVersion: source.toolkit.fluxcd.io/v1beta2
kind: HelmRepository
metadata:
name: bitnami
namespace: flux-system
spec:
interval: 1h
url: https://charts.bitnami.com/bitnami
# HelmRelease: the actual deployment
apiVersion: helm.toolkit.fluxcd.io/v2beta2
kind: HelmRelease
metadata:
name: redis
namespace: production
spec:
interval: 5m
chart:
spec:
chart: redis # chart name in the repo
version: "18.x.x" # semver range — Flux upgrades automatically
sourceRef:
kind: HelmRepository
name: bitnami
namespace: flux-system
values:
auth:
enabled: true
existingSecret: redis-auth # reference existing Secret
replica:
replicaCount: 2
valuesFrom:
- kind: ConfigMap
name: redis-config # merge values from a ConfigMap
- kind: Secret
name: redis-secrets # and a Secret
valuesKey: values.yaml # key within the Secret
# Monitor HelmRelease status:
flux get helmreleases -A
flux describe helmrelease redis -n production
flux reconcile helmrelease redis -n production # force upgrade
5. Image Automation
Auto-update image tags when new container images are pushed
# Install image automation controllers (not installed by default):
flux bootstrap github ... --components-extra=image-reflector-controller,image-automation-controller
# ImageRepository: poll a container registry for new tags
apiVersion: image.toolkit.fluxcd.io/v1beta2
kind: ImageRepository
metadata:
name: my-app
namespace: flux-system
spec:
image: registry.example.com/myorg/my-app
interval: 1m
secretRef:
name: registry-credentials
# ImagePolicy: define which tags to accept
apiVersion: image.toolkit.fluxcd.io/v1beta2
kind: ImagePolicy
metadata:
name: my-app
namespace: flux-system
spec:
imageRepositoryRef:
name: my-app
policy:
semver:
range: ">=1.0.0" # only accept semver releases, not pre-releases
# or: range: "^1.0.0" # only 1.x.x
# or: alphabetical: {order: asc} for date-tagged images
# ImageUpdateAutomation: write the new tag back to Git
apiVersion: image.toolkit.fluxcd.io/v1beta1
kind: ImageUpdateAutomation
metadata:
name: flux-system
namespace: flux-system
spec:
interval: 1m
sourceRef:
kind: GitRepository
name: flux-system
git:
checkout:
ref: {branch: main}
commit:
author: {email: fluxbot@example.com, name: "Flux Bot"}
messageTemplate: "chore: update image tags"
push:
branch: main
# Mark the Deployment with a policy annotation:
spec:
template:
spec:
containers:
- name: my-app
image: registry.example.com/myorg/my-app:1.2.3 # {"$imagepolicy": "flux-system:my-app"}
# When new tag matches policy, Flux updates this line and commits to Git
6. SOPS Secrets
Encrypt secrets in Git — Flux decrypts at apply time
# SOPS (Secrets OPerationS) encrypts secrets in-place in YAML files
# Flux natively supports decrypting SOPS secrets during apply
# Generate an age key:
age-keygen -o age.agekey
cat age.agekey | grep public # copy the public key
# Create the Flux decryption secret:
kubectl create secret generic sops-age --namespace=flux-system --from-file=age.agekey
# Configure Flux Kustomization to use the secret:
spec:
decryption:
provider: sops
secretRef:
name: sops-age
# Encrypt a Kubernetes Secret with SOPS:
# .sops.yaml (place in repo root):
creation_rules:
- path_regex: .*/secrets/.*\.yaml
age: age1xxxx... # your public key
# Encrypt:
sops --encrypt --in-place k8s/secrets/my-secret.yaml
# All values under data: are encrypted in-place
# The YAML structure (keys) remain visible, only values are encrypted
# Safe to commit to Git — only Flux (with the age key) can decrypt
# Flux automatically decrypts during kustomize build + apply
flux reconcile kustomization my-app --with-source
flux-system — it never needs to leave the cluster.
Track Flux CD, ArgoCD, and GitOps tool releases.
ReleaseRun monitors Kubernetes, Docker, and 13+ DevOps technologies.
Related: ArgoCD & GitOps Reference | Kustomize Reference | Helm Reference
🔍 Free tool: K8s YAML Security Linter — paste your Flux-managed K8s manifests here to check for 12 security misconfigurations before GitOps sync.
Founded
2023 in London, UK
Contact
hello@releaserun.com