How to Set Up FluxCD for GitOps on Kubernetes from Scratch (2026)
Step-by-step guide to installing FluxCD, bootstrapping it with GitHub, setting up Kustomizations and HelmReleases, and managing multi-environment deployments with GitOps.
FluxCD is a GitOps operator that keeps your Kubernetes cluster in sync with a Git repository. You push a change to Git — Flux detects it, applies it to the cluster. No manual kubectl apply. No direct cluster access for developers. Infrastructure as code, actually enforced.
This guide gets you from zero to a production-ready FluxCD setup.
What You'll Build
By the end of this guide:
- Flux bootstrapped with GitHub repo
- Automatic sync every 1 minute
- HelmRelease for deploying an app via Helm
- Kustomization overlays for dev/staging/production
- Image automation to auto-update image tags on push
Prerequisites
- Kubernetes cluster (EKS, GKE, AKS, or local k3s)
kubectlconfigured and working- GitHub account and personal access token
fluxCLI installed
Step 1: Install the Flux CLI
macOS/Linux:
curl -s https://fluxcd.io/install.sh | sudo bashWindows (via Chocolatey):
choco install fluxVerify:
flux --version
# flux version 2.3.0Step 2: Create a GitHub Repository
Create a new repo on GitHub. This will be your GitOps repo — it holds your Kubernetes manifests, not your application code.
Name it something like my-cluster-config or fleet-infra.
Generate a GitHub Personal Access Token:
- Go to GitHub → Settings → Developer settings → Personal access tokens → Fine-grained tokens
- Give it
Contents: Read and writeandMetadata: Readpermissions on your new repo
Export token as env var:
export GITHUB_TOKEN=ghp_xxxxxxxxxxxxxxxxxxxx
export GITHUB_USER=your-github-usernameStep 3: Check Cluster Compatibility
flux check --preThis verifies your cluster has the required Kubernetes version and API server access. Fix any warnings before proceeding.
Step 4: Bootstrap Flux
Bootstrap installs Flux in your cluster AND commits all Flux manifests to your Git repo. One command does both:
flux bootstrap github \
--owner=$GITHUB_USER \
--repository=my-cluster-config \
--branch=main \
--path=./clusters/my-cluster \
--personalWhat happens:
- Flux creates
flux-systemnamespace in your cluster - Installs source-controller, kustomize-controller, helm-controller, notification-controller
- Commits Flux's own manifests to
clusters/my-cluster/flux-system/in your repo - Flux immediately starts reconciling from that path
Verify:
kubectl get pods -n flux-system
# source-controller-xxx Running
# kustomize-controller-xxx Running
# helm-controller-xxx Running
# notification-controller-xxx Running
flux get allGitOps labs: KodeKloud has a dedicated FluxCD course with hands-on practice in real Kubernetes clusters.
Step 5: Add a GitRepository Source
Tell Flux to watch another repo (your app's Helm charts or manifests):
# Create a GitRepository source
flux create source git my-app \
--url=https://github.com/$GITHUB_USER/my-app \
--branch=main \
--interval=1m \
--export > ./clusters/my-cluster/my-app-source.yamlThis creates:
apiVersion: source.toolkit.fluxcd.io/v1
kind: GitRepository
metadata:
name: my-app
namespace: flux-system
spec:
interval: 1m0s
ref:
branch: main
url: https://github.com/your-user/my-appCommit and push — Flux reconciles within 1 minute.
Step 6: Create a Kustomization
A Kustomization tells Flux which path in the GitRepository to apply:
# clusters/my-cluster/my-app-kustomization.yaml
apiVersion: kustomize.toolkit.fluxcd.io/v1
kind: Kustomization
metadata:
name: my-app
namespace: flux-system
spec:
interval: 5m
path: ./deploy/base # path inside the GitRepository
prune: true # delete resources removed from Git
sourceRef:
kind: GitRepository
name: my-app
targetNamespace: my-app
healthChecks:
- apiVersion: apps/v1
kind: Deployment
name: my-app
namespace: my-app
timeout: 2mprune: true is important — it means if you delete a manifest from Git, Flux deletes it from the cluster. This keeps Git as the single source of truth.
Step 7: Deploy a Helm Chart with HelmRelease
For apps packaged as Helm charts, use HelmRepository + HelmRelease:
Add a Helm chart repository:
# clusters/my-cluster/sources/podinfo-source.yaml
apiVersion: source.toolkit.fluxcd.io/v1
kind: HelmRepository
metadata:
name: podinfo
namespace: flux-system
spec:
interval: 5m
url: https://stefanprodan.github.io/podinfoCreate a HelmRelease:
# clusters/my-cluster/apps/podinfo.yaml
apiVersion: helm.toolkit.fluxcd.io/v2
kind: HelmRelease
metadata:
name: podinfo
namespace: flux-system
spec:
interval: 5m
chart:
spec:
chart: podinfo
version: ">=6.0.0"
sourceRef:
kind: HelmRepository
name: podinfo
namespace: flux-system
targetNamespace: podinfo
install:
createNamespace: true
values:
replicaCount: 2
resources:
requests:
cpu: 100m
memory: 64MiCommit, push, and watch Flux install the Helm chart automatically:
flux get helmreleases -A
watch kubectl get pods -n podinfoStep 8: Multi-Environment Setup with Kustomize Overlays
Structure your repo for multiple environments:
clusters/
├── dev/
│ ├── flux-system/
│ └── apps.yaml # Kustomization pointing to deploy/overlays/dev
├── staging/
│ ├── flux-system/
│ └── apps.yaml
└── production/
├── flux-system/
└── apps.yaml
deploy/
├── base/
│ ├── deployment.yaml
│ ├── service.yaml
│ └── kustomization.yaml
└── overlays/
├── dev/
│ ├── kustomization.yaml
│ └── patch-replicas.yaml # replicas: 1
├── staging/
│ ├── kustomization.yaml
│ └── patch-replicas.yaml # replicas: 2
└── production/
├── kustomization.yaml
└── patch-replicas.yaml # replicas: 5
base/kustomization.yaml:
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- deployment.yaml
- service.yamloverlays/production/kustomization.yaml:
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- ../../base
patches:
- path: patch-replicas.yamlEach cluster runs its own Flux pointing to its overlay path. Changes to base/ propagate to all environments. Environment-specific changes stay isolated in overlays.
Step 9: Image Automation (Auto-update Tags)
Flux can watch a container registry and automatically update image tags in Git when a new image is pushed:
# clusters/my-cluster/image-automation.yaml
---
apiVersion: image.toolkit.fluxcd.io/v1beta2
kind: ImageRepository
metadata:
name: my-app
namespace: flux-system
spec:
image: ghcr.io/my-user/my-app
interval: 1m
---
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"
---
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:
name: FluxBot
email: flux@example.com
messageTemplate: "chore: update images"
push:
branch: main
update:
path: ./clusters/my-cluster
strategy: SettersNow in your deployment YAML, mark the image tag for Flux to update:
image: ghcr.io/my-user/my-app:1.0.0 # {"$imagepolicy": "flux-system:my-app"}Push a new image → Flux updates the tag in Git → Flux applies the updated manifest to cluster. Full GitOps loop with zero manual steps.
Useful Flux Commands
# Force reconcile now (don't wait for interval)
flux reconcile kustomization my-app --with-source
# Check sync status
flux get kustomizations -A
flux get helmreleases -A
flux get sources git -A
# View Flux logs
flux logs --level=error --all-namespaces
# Suspend sync (for maintenance)
flux suspend kustomization my-app
# Resume sync
flux resume kustomization my-appTroubleshooting Common Issues
Kustomization stuck in Reconciling:
flux describe kustomization my-app
# Check for YAML errors or missing resourcesHelmRelease failing:
flux describe helmrelease podinfo
kubectl describe helmrelease podinfo -n flux-system
# Look at "Status.Conditions" for error messagesGit repo not accessible:
flux describe source git my-app
# Check for authentication errors — re-create secret if neededRunning FluxCD on production Kubernetes? Deploy on DigitalOcean Kubernetes — managed K8s with $200 free credits, perfect for GitOps setups.
Stay ahead of the curve
Get the latest DevOps, Kubernetes, AWS, and AI/ML guides delivered straight to your inbox. No spam — just practical engineering content.
Related Articles
Build a Complete CI/CD Pipeline with GitHub Actions + ArgoCD + EKS (2026)
A full project walkthrough — from a simple app to a production-grade GitOps pipeline with automated builds, image scanning, and deployments to AWS EKS using ArgoCD.
ArgoCD vs Flux vs Jenkins — GitOps Comparison 2026
A deep-dive comparison of the three most popular GitOps and CI/CD tools — ArgoCD, Flux CD, and Jenkins. Learn which one fits your team, use case, and Kubernetes setup.
Build a DevSecOps Pipeline with Trivy, SonarQube, and OPA from Scratch (2026)
Step-by-step project walkthrough: add security scanning, code quality gates, and policy enforcement to a GitHub Actions pipeline. Real configs, production-ready.