Skip to content

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
SOPS is the recommended secret management approach for Flux. The age private key lives in a K8s Secret in 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