Flux CD, when bootstrapped onto a Kubernetes cluster via GitHub, isn’t just about syncing manifests; it’s about turning your Git repository into the authoritative source of truth for your cluster’s state, with Flux acting as the relentless, event-driven reconciliation engine.

Here’s Flux CD in action, managing a simple Nginx deployment. First, we need a Git repository. Let’s assume you have one at https://github.com/your-username/your-flux-repo.

Inside this repo, we’ll create a directory structure. A common pattern is:

├── clusters
│   └── my-cluster
│       ├── flux-system
│       │   └── gotk-sync.yaml
│       └── apps
│           └── nginx-deployment.yaml
└── infrastructure
    └── ...

The nginx-deployment.yaml would look like this:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
  namespace: default
spec:
  replicas: 2
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.25.3
        ports:
        - containerPort: 80

And gotk-sync.yaml would define how Flux syncs this repository:

apiVersion: v1
kind: Namespace
metadata:
  name: flux-system
---
apiVersion: source.toolkit.fluxcd.io/v1beta2
kind: GitRepository
metadata:
  name: flux-system
  namespace: flux-system
spec:
  interval: 1m
  url: ssh://git@github.com/your-username/your-flux-repo.git
  ref:
    branch: main
---
apiVersion: kustomize.toolkit.fluxcd.io/v1beta2
kind: Kustomization
metadata:
  name: flux-system
  namespace: flux-system
spec:
  interval: 1m
  path: ./clusters/my-cluster
  sourceRef:
    kind: GitRepository
    name: flux-system
  prune: true

To bootstrap this, you’d run:

flux bootstrap github \
  --owner=your-username \
  --repository=your-flux-repo \
  --branch=main \
  --path=./clusters/my-cluster \
  --personal

This command does several things:

  1. Creates a flux-system namespace.
  2. Installs the Flux controllers (Source Controller, Kustomize Controller, etc.) into your cluster.
  3. Creates a GitRepository custom resource pointing to your GitHub repo.
  4. Creates a Kustomization custom resource telling Flux to apply manifests from the clusters/my-cluster path in your repo.
  5. Generates SSH deploy keys and commits them back to your GitHub repository (or uses a Personal Access Token if --personal is omitted and you’re using HTTPS).

Once bootstrapped, if you change nginx-deployment.yaml (e.g., increase replicas to 3) and push it to main, Flux will detect the change and update your cluster. You can watch this happen:

kubectl get pods -l app=nginx -w

You’ll see Flux delete the old pods and create new ones to match the desired state.

The core problem Flux solves is the drift between your intended infrastructure state (defined in Git) and the actual state of your Kubernetes cluster. Without it, you’re manually applying YAMLs or relying on CI/CD pipelines that only push changes, not continuously reconcile. Flux, on the other hand, constantly monitors your Git repo and your cluster, ensuring they stay in sync.

Internally, the Flux controllers work in a loop. The Source Controller periodically fetches the Git repository. The Kustomize Controller (or Helm Controller, etc.) then takes that fetched source, applies any specified transformations (like Kustomization overlays), and compares the result with the live state in Kubernetes. If there’s a difference, it makes the necessary API calls to bring the cluster in line with the desired state.

The interval field on GitRepository and Kustomization resources dictates how often Flux checks for changes. A shorter interval means faster reconciliation but more API calls.

The prune: true on the Kustomization resource is crucial. It tells Flux to garbage-collect resources that are no longer defined in your Git repository. If you delete nginx-deployment.yaml from Git and push, Flux will delete the Nginx deployment from your cluster.

What most people don’t realize is that the GitRepository and Kustomization resources themselves are Kubernetes resources. You can kubectl apply them, kubectl edit them, and even manage them using Flux itself once it’s bootstrapped. This creates a powerful meta-loop where Flux can manage its own configuration, bootstrapping a cluster with a single Git commit that defines both the Flux installation and the initial desired state.

The next logical step is to manage multiple applications and environments, which involves understanding Flux’s Application and Kustomization custom resources for deploying user applications, and potentially exploring multi-tenancy patterns.

Want structured learning?

Take the full Flux course →