Flux Tutorial: GitOps on Kubernetes with FluxCD

Flux turns a Git repository into the source of truth for your Kubernetes cluster. This guide walks through installing, bootstrapping, and reconciling real workloads.

Get started - freeLive cloud workspace in your browser · nothing to install
#flux#gitops#kubernetes#fluxcd#cd

What is Flux?

Flux, often written FluxCD, is a continuous-delivery toolkit for Kubernetes that implements the GitOps pattern. Instead of running kubectl apply from a laptop or a CI job that pushes changes into the cluster, you commit your desired state to a Git repository and let Flux pull that state in and keep the cluster converged to it. Every change to your infrastructure becomes a commit, every rollback becomes a revert, and the live cluster state is continuously reconciled against what is declared in source control.

Flux is a graduated project in the Cloud Native Computing Foundation and is built as a small family of controllers rather than a single monolith. This composability is its defining trait: you install only the controllers you need, and everything is driven through Kubernetes custom resources, so the entire system is observable and scriptable with the same kubectl and YAML you already use. The current major version is Flux v2.

How Flux works

Flux 2 is a set of controllers, collectively called the GitOps Toolkit, that run in the flux-system namespace and watch custom resources:

The core loop is reconciliation. Each controller continuously compares the desired state defined in its custom resources against the actual state in the cluster and corrects any drift. If someone manually edits a Deployment that Flux manages, the next reconcile will revert it to match Git. This is the mechanism that makes Git the single source of truth rather than just a backup of your manifests.

The separation between a source and what consumes it is the key mental model. A GitRepository says "where to fetch and how often"; a Kustomization says "which path in that source to apply and into which namespace." One source can feed many Kustomizations, which is how teams split a monorepo into independently reconciled slices.

Installing Flux

First install the flux command-line tool. On macOS or Linux you can use the official install script or Homebrew:

# Official install script
curl -s https://fluxcd.io/install.sh | sudo bash

# Or with Homebrew
brew install fluxcd/tap/flux

# Verify the CLI version
flux --version

Before touching a cluster, run the preflight check. It confirms your kubeconfig points at a reachable cluster and that the Kubernetes version is compatible:

flux check --pre

The recommended way to install the controllers is flux bootstrap. Bootstrapping does more than flux install: it commits the Flux controller manifests into your Git repository at a chosen path, then configures the cluster to reconcile from that path, so Flux ends up managing its own installation. Export a GitHub personal access token with repo administration rights, then bootstrap:

export GITHUB_TOKEN=<your-pat>

flux bootstrap github \
  --token-auth \
  --owner=my-github-username \
  --repository=my-fleet-repo \
  --branch=main \
  --path=clusters/my-cluster \
  --personal

For an organization repository, drop --personal and set --owner to the org name. After bootstrap, the flux-system namespace contains the controllers and a GitRepository plus Kustomization that point back at the clusters/my-cluster path you specified.

Deploying an app with a Kustomization

With Flux running, deploy a workload by declaring a source and a Kustomization. Save the following to clusters/my-cluster/podinfo.yaml in your bootstrapped repo, commit, and push. Flux will pick it up on its next reconcile.

apiVersion: source.toolkit.fluxcd.io/v1
kind: GitRepository
metadata:
  name: podinfo
  namespace: flux-system
spec:
  interval: 1m
  url: https://github.com/stefanprodan/podinfo
  ref:
    branch: master
---
apiVersion: kustomize.toolkit.fluxcd.io/v1
kind: Kustomization
metadata:
  name: podinfo
  namespace: flux-system
spec:
  interval: 5m
  targetNamespace: default
  sourceRef:
    kind: GitRepository
    name: podinfo
  path: ./kustomize
  prune: true
  wait: true
  timeout: 2m

The interval: 1m on the source tells Flux how often to fetch new commits; the interval: 5m on the Kustomization is how often it re-applies and corrects drift. prune: true means that if you delete a manifest from Git, Flux garbage-collects the corresponding object from the cluster. wait: true makes Flux block until the applied resources are healthy.

You can force an immediate sync instead of waiting for the interval, and inspect what Flux is managing:

# Pull and apply right now
flux reconcile source git podinfo
flux reconcile kustomization podinfo --with-source

# See the status of everything Flux manages
flux get all -A

# Temporarily stop reconciliation, then resume
flux suspend kustomization podinfo
flux resume kustomization podinfo

If a Kustomization reports a failure, flux get kustomization podinfo shows the message, and kubectl describe kustomization podinfo -n flux-system gives the full event history. Because the desired state lives in Git, undoing a bad deploy is a commit revert followed by another reconcile.

When to use Flux

Reach for Flux when you want Git to be the authoritative record of what runs in your clusters and you prefer an API- and CLI-first workflow over a bundled dashboard. It works well for fleet management where one repository describes many clusters, for teams that already work mostly in kubectl and YAML, and for pipelines that need GitOps embedded without a heavyweight UI. The controller-per-concern design also lets you adopt incrementally: start with Kustomization reconciliation, add HelmRelease management later, and add image automation only when you need automatic image updates.

Flux is less of a fit if your team specifically wants a rich graphical view of application sync status and history built in, since that is where a UI-centric tool like Argo CD is easier to start with. It is also more than you need for a short-lived test cluster where a plain kubectl apply is enough. But for any environment that lives long enough to drift, GitOps reconciliation keeps the cluster matching what is in Git, and Flux does it with a small, composable footprint.

Frequently asked questions

What is Flux?

Flux (also called FluxCD) is a set of continuous-delivery controllers for Kubernetes built on the GitOps model. It watches a Git repository, OCI artifact, or bucket for declarative manifests and continuously reconciles the cluster to match that desired state. It is a graduated CNCF project.

What is the difference between Flux and Argo CD?

Both are GitOps controllers for Kubernetes. Flux is a composable set of controllers driven entirely by Kubernetes custom resources with no required UI, which makes it easy to script and embed. Argo CD ships with an opinionated web UI and an application abstraction. Flux leans toward a CLI- and API-first workflow.

Does Flux need a Git repository?

Not strictly. Git is the most common source, but Flux can also reconcile from OCI artifacts (OCIRepository), Helm repositories (HelmRepository), and S3-compatible buckets (Bucket). The source-controller fetches from whichever source you define.

How do I update Flux after bootstrapping?

Upgrade the flux CLI, then re-run the same flux bootstrap command against the same repository and path. Flux commits the updated controller manifests to Git and reconciles them onto the cluster, so the upgrade itself flows through GitOps.

Do real production work, free. Live cloud workspaces in your browser - every project you complete lands on your portfolio.

Get started - free
Get started - free