LearnDevOps
DevOps03. GitOps·EXPERT·6 min read

8. FluxCD

FluxCD

TL;DR

  • Flux is a set of composable Kubernetes controllers, each implementing one GitOps concern (source, kustomization, helm, notification); no separate application server or web UI by default.
  • The Source Controller is the foundation: it fetches and caches sources; other controllers consume its cached artifacts rather than fetching independently.
  • Kustomize Controller is for your own manifests with overlays; Helm Controller is for third-party Helm charts; using each for its intended purpose avoids forcing one to do the other’s job.
  • HelmRelease resources must pin exact chart versions, not version ranges; version ranges silently pull breaking changes without an auditable Git commit.
  • Flux’s controller-native architecture fits teams already fluent in Kubernetes operators; ArgoCD’s dedicated-app architecture better suits teams wanting a dedicated UI and centralized management.

Core Concepts

Composable GitOps controllers

Flux comprises focused, single-purpose controllers communicating through Kubernetes CRDs:

  • Source Controller — fetches and caches sources (Git repos, Helm repos, OCI artifacts, S3)
  • Kustomize Controller — applies Kustomize-based overlays
  • Helm Controller — manages HelmRelease resources
  • Notification Controller — sends notifications on reconciliation events
  • Image Automation Controller — watches container registries and updates manifests

This is the defining architectural difference from ArgoCD (a monolithic app with integrated API, RBAC, web UI). Everything in Flux is inspectable and debuggable via standard kubectlkubectl get gitrepository, kubectl describe kustomization — the same operational muscle memory any Kubernetes operator user already has.

Source Controller: the foundation

The Source Controller fetches and caches source artifacts and exposes them as Kubernetes objects that other controllers reference. This decouples “getting the source” from “applying it”: the Kustomize and Helm controllers don’t fetch from Git themselves; they consume what the Source Controller already retrieved and cached. This keeps fetch logic centralized and consistent.

apiVersion: source.toolkit.fluxcd.io/v1
kind: GitRepository
metadata:
  name: app-config
spec:
  interval: 1m
  url: https://github.com/myorg/app-config
  ref:
    branch: main
  secretRef:
    name: github-credentials

Kustomize Controller

Applies Kustomize overlays — base configuration plus environment-specific patches. This fits naturally for a team’s own manifests where overlay-based customization (same base, per-environment patches for replicas, resource limits) is the intended pattern.

apiVersion: kustomize.toolkit.fluxcd.io/v1
kind: Kustomization
metadata:
  name: app-overlays
spec:
  interval: 10m
  sourceRef:
    kind: GitRepository
    name: app-config
  path: ./overlays/prod
  prune: true
  wait: true

Helm Controller and version discipline

Manages HelmRelease resources: declarative Helm chart installation and reconciliation. Natural for third-party software already packaged as Helm charts. Critical discipline: pin exact chart versions, not ranges. A version range allows upstream updates within that range to be applied silently on the next reconciliation, potentially introducing breaking changes without an auditable Git commit.

# ❌ Loose — can silently pick up breaking changes
spec:
  chart:
    spec:
      chart: postgres-operator
      version: "15.x"  # Allows 15.0 through 15.9, but one may break the app

# ✅ Pinned — every change is auditable
spec:
  chart:
    spec:
      chart: postgres-operator
      version: "15.2.1"  # Exact version only

Cross-controller dependencies

The dependsOn field sequences reconciliation across controllers. A Kustomization can depend on another Kustomization or on a HelmRelease; Flux derives apply order from the dependency graph.

apiVersion: kustomize.toolkit.fluxcd.io/v1
kind: Kustomization
metadata:
  name: app-with-deps
spec:
  dependsOn:
  - name: database-helm-release
  sourceRef:
    kind: GitRepository
    name: app-config

Flux vs ArgoCD vs Traditional Gitops

Aspect Flux ArgoCD Traditional CI/CD
Architecture Kubernetes controllers Dedicated app server + UI Pipeline engine
Debugging kubectl describe, CRD status Web UI + CLI Pipeline logs + artifacts
Operational model Kubernetes-native Separate RBAC/access model Push-based pipeline
Multi-cluster Per-cluster Flux installation Centralized control plane Per-cluster pipelines
Learning curve Steeper for non-Kubernetes teams Easier for ops generalists Depends on platform
Version pinning enforcement Can be enforced via policy Can be enforced via policy Artifact registry only

Configuration Reference

# Complete Flux setup: GitRepository → Source → Kustomization
apiVersion: source.toolkit.fluxcd.io/v1
kind: GitRepository
metadata:
  name: config
  namespace: flux-system
spec:
  interval: 30s
  url: https://github.com/myorg/config
  ref:
    branch: main
  secretRef:
    name: github-token

---
apiVersion: kustomize.toolkit.fluxcd.io/v1
kind: Kustomization
metadata:
  name: app
  namespace: flux-system
spec:
  sourceRef:
    kind: GitRepository
    name: config
  path: ./app/
  interval: 10m
  prune: true
  wait: true

---
apiVersion: helm.toolkit.fluxcd.io/v2
kind: HelmRelease
metadata:
  name: postgresql
spec:
  interval: 5m
  chart:
    spec:
      chart: postgresql
      version: "15.2.1"  # EXACT version
      sourceRef:
        kind: HelmRepository
        name: bitnami
  values:
    global:
      postgresql:
        auth:
          password: changeme
# Debugging
flux get all                      # show reconciliation status of all Flux objects
flux get source git              # list GitRepository objects
kubectl describe kustomization app-overlays
kubectl logs -n flux-system deployment/source-controller -f

Common Pitfalls

  • Pitfall: HelmRelease silently picks up a breaking chart upgrade; no Git commit to point to. Why: Version range in spec.chart.spec.version allows updates within that range. Fix: Pin exact chart versions; treat Helm version pinning with the same discipline as application dependency pinning.

  • Pitfall: Third-party Helm charts converted to Kustomize manifests manually; constant drift from upstream chart updates. Why: Force-fitting Helm into Kustomize instead of using the purpose-built Helm Controller. Fix: Use Helm Controller for charts that ship as Helm packages; save Kustomize for your own manifests.

  • Pitfall: Team chose ArgoCD without evaluating whether existing Kubernetes-operator fluency favored Flux. Why: Flux wasn’t evaluated as a fit for the team’s existing operational model. Fix: Explicitly evaluate both based on team skills; Flux is a better fit for teams already fluent in Kubernetes operators.

  • Pitfall: Source Controller credential or connectivity issues silently block every downstream controller; misdiagnosed as Kustomize or Helm issues. Why: Shared dependency wasn’t identified as the root cause. Fix: Monitor Source Controller health and credentials; confirm it’s fetching sources successfully before debugging downstream controllers.

  • Pitfall: flux reconcile re-applies resources even though nothing in Git changed. Why: Source Controller is re-fetching and re-caching due to expired credentials or network issues. Fix: Monitor Source Controller logs and credentials; ensure consistent access to the source repository.

Interview Questions

  • Explain why Flux’s controller-native architecture appeals to teams already fluent in Kubernetes operators, and when you’d choose ArgoCD instead. — Tests understanding of the operational-fit trade-off, not just architectural differences.

  • A HelmRelease picked up a breaking chart change that broke the application. What happened, and how do you prevent it? — Tests whether exact version pinning is the immediate, correct answer.

  • When and why would you use the Kustomize Controller versus the Helm Controller? — Tests whether the own-manifests-versus-third-party-charts distinction is applied correctly.

  • The Source Controller is the foundation every other controller depends on. What does that mean operationally? — Tests whether the shared-dependency architecture and its failure modes are understood.

  • Flux requires more Kubernetes knowledge than some alternatives. Is that a drawback or a feature? — Tests whether the fit-for-purpose evaluation is nuanced.

🔒 Locked
Sign in and unlock the full syllabus to keep reading.
Sign in to continue
Knowledge check
5 scenario questions on this topic
Take the quiz →
Related in 03. GitOps
6. GitOps Fundamentals
EXPERT
7. ArgoCD
EXPERT
9. Progressive Delivery
EXPERT