Skip to content
Vladimir Chavkov
Go back

Flux CD: Complete GitOps Toolkit for Kubernetes

Edit page

Flux CD: Complete GitOps Toolkit for Kubernetes

Flux CD is a set of continuous and progressive delivery solutions for Kubernetes that are open and extensible. As a CNCF graduated project, Flux provides powerful GitOps capabilities for managing Kubernetes clusters. This comprehensive guide covers Flux installation, configuration, and production deployment patterns.

What is Flux CD?

Flux CD is a GitOps toolkit consisting of specialized components:

Core Components

  1. Source Controller: Manages Git repositories, Helm repositories, and S3 buckets
  2. Kustomize Controller: Reconciles Kustomize overlays
  3. Helm Controller: Manages Helm releases
  4. Notification Controller: Handles alerts and webhooks
  5. Image Automation: Automatically updates images

Key Features

Flux vs. ArgoCD

FeatureFlux CDArgoCD
ArchitectureDistributed (multiple controllers)Monolithic + API server
UIExternal (Weave GitOps)Built-in
Multi-tenancyNativeRequires projects
Image automationBuilt-inRequires external tools
HelmHelmRelease CRDNative
KustomizeNativeNative
Progressive deliveryFlagger integrationArgo Rollouts
Learning curveSteeperGentler

Installation

Prerequisites

Terminal window
# Install Flux CLI
# macOS
brew install fluxcd/tap/flux
# Linux
curl -s https://fluxcd.io/install.sh | sudo bash
# Windows (PowerShell)
choco install flux
# Verify installation
flux --version

Check Prerequisites

Terminal window
# Check cluster requirements
flux check --pre
# Check for breaking changes before upgrade
flux check

Bootstrap Flux

GitHub

Terminal window
# Export GitHub token
export GITHUB_TOKEN=<your-token>
# Bootstrap Flux
flux bootstrap github \
--owner=my-org \
--repository=fleet-infra \
--branch=main \
--path=clusters/production \
--personal
# For organization repository
flux bootstrap github \
--owner=my-org \
--repository=fleet-infra \
--team=platform-team \
--path=clusters/production

GitLab

Terminal window
# Export GitLab token
export GITLAB_TOKEN=<your-token>
# Bootstrap Flux
flux bootstrap gitlab \
--owner=my-group \
--repository=fleet-infra \
--branch=main \
--path=clusters/production \
--personal=false

Generic Git

Terminal window
# For any Git provider
flux bootstrap git \
--url=ssh://git@github.com/my-org/fleet-infra \
--branch=main \
--path=clusters/production \
--private-key-file=~/.ssh/flux

What Bootstrap Does

  1. Creates Git repository if it doesn’t exist
  2. Commits Flux component manifests to repository
  3. Configures Flux to sync from repository
  4. Deploys Flux components to cluster
  5. Sets up Git SSH key for authentication

Verify Installation

Terminal window
# Check Flux components
flux check
# List all Flux resources
kubectl get all -n flux-system
# View Flux logs
flux logs --all-namespaces --follow

Repository Structure

Terminal window
fleet-infra/
├── clusters/
│ ├── production/
│ │ ├── flux-system/ # Flux components (managed)
│ │ ├── infrastructure.yaml # Infrastructure sources/releases
│ │ └── apps.yaml # Application sources/releases
│ └── staging/
│ └── ...
├── infrastructure/
│ ├── sources/
│ │ ├── bitnami.yaml
│ │ ├── jetstack.yaml
│ │ └── prometheus.yaml
│ └── controllers/
│ ├── ingress-nginx/
│ ├── cert-manager/
│ └── sealed-secrets/
└── apps/
├── base/
│ └── app1/
│ ├── deployment.yaml
│ ├── service.yaml
│ └── kustomization.yaml
└── production/
└── app1/
├── kustomization.yaml
└── patch.yaml

GitRepository Source

infrastructure/sources/app-repo.yaml
apiVersion: source.toolkit.fluxcd.io/v1
kind: GitRepository
metadata:
name: app-repo
namespace: flux-system
spec:
interval: 1m
url: https://github.com/example/app-repo
ref:
branch: main
secretRef:
name: git-credentials
ignore: |
# exclude all
/*
# include charts directory
!/charts/

SSH Authentication

Terminal window
# Create SSH key
ssh-keygen -t ed25519 -C "flux" -f flux-ssh
# Add to GitHub as deploy key
# Create secret
flux create secret git flux-system \
--url=ssh://git@github.com/my-org/fleet-infra \
--private-key-file=flux-ssh

HTTPS with Token

Terminal window
# Create secret with token
flux create secret git github-token \
--url=https://github.com/my-org/fleet-infra \
--username=git \
--password=$GITHUB_TOKEN

Kustomize Deployments

Basic Kustomization

clusters/production/apps.yaml
apiVersion: kustomize.toolkit.fluxcd.io/v1
kind: Kustomization
metadata:
name: apps
namespace: flux-system
spec:
interval: 10m
sourceRef:
kind: GitRepository
name: flux-system
path: ./apps/production
prune: true
wait: true
timeout: 5m
validation: client
healthChecks:
- apiVersion: apps/v1
kind: Deployment
name: app1
namespace: default

Multi-Source Kustomization

apiVersion: kustomize.toolkit.fluxcd.io/v1
kind: Kustomization
metadata:
name: app1
namespace: flux-system
spec:
interval: 5m
sourceRef:
kind: GitRepository
name: app-repo
path: ./apps/app1/overlays/production
prune: true
dependsOn:
- name: infrastructure
patches:
- patch: |
apiVersion: apps/v1
kind: Deployment
metadata:
name: app1
spec:
replicas: 5
target:
kind: Deployment
name: app1
postBuild:
substitute:
cluster_name: "production"
domain: "example.com"
substituteFrom:
- kind: ConfigMap
name: cluster-vars

Helm Releases

HelmRepository

infrastructure/sources/bitnami.yaml
apiVersion: source.toolkit.fluxcd.io/v1beta2
kind: HelmRepository
metadata:
name: bitnami
namespace: flux-system
spec:
interval: 1h
url: https://charts.bitnami.com/bitnami

HelmRelease

infrastructure/controllers/nginx.yaml
apiVersion: helm.toolkit.fluxcd.io/v2beta1
kind: HelmRelease
metadata:
name: ingress-nginx
namespace: ingress-nginx
spec:
interval: 30m
chart:
spec:
chart: ingress-nginx
version: '4.x'
sourceRef:
kind: HelmRepository
name: bitnami
namespace: flux-system
interval: 12h
releaseName: ingress-nginx
install:
remediation:
retries: 3
crds: CreateReplace
upgrade:
remediation:
retries: 3
crds: CreateReplace
values:
controller:
replicaCount: 3
service:
type: LoadBalancer
resources:
limits:
cpu: 500m
memory: 512Mi
requests:
cpu: 250m
memory: 256Mi
valuesFrom:
- kind: ConfigMap
name: ingress-values
valuesKey: values.yaml

Helm from Git

apiVersion: source.toolkit.fluxcd.io/v1
kind: GitRepository
metadata:
name: charts-repo
namespace: flux-system
spec:
interval: 5m
url: https://github.com/example/helm-charts
ref:
branch: main
---
apiVersion: helm.toolkit.fluxcd.io/v2beta1
kind: HelmRelease
metadata:
name: my-app
namespace: default
spec:
interval: 5m
chart:
spec:
chart: ./charts/my-app
sourceRef:
kind: GitRepository
name: charts-repo
namespace: flux-system
values:
replicaCount: 3

Image Automation

Image Repository

clusters/production/image-repo.yaml
apiVersion: image.toolkit.fluxcd.io/v1beta2
kind: ImageRepository
metadata:
name: my-app
namespace: flux-system
spec:
image: ghcr.io/example/my-app
interval: 1m
secretRef:
name: ghcr-credentials

Image Policy

clusters/production/image-policy.yaml
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 <2.0.0'
# Or use pattern
# policy:
# pattern: '^main-[a-f0-9]+-(?P<ts>[0-9]+)'
# extract: '$ts'

Image Update Automation

clusters/production/image-update.yaml
apiVersion: image.toolkit.fluxcd.io/v1beta1
kind: ImageUpdateAutomation
metadata:
name: my-app
namespace: flux-system
spec:
interval: 1m
sourceRef:
kind: GitRepository
name: flux-system
git:
checkout:
ref:
branch: main
commit:
author:
email: fluxcdbot@users.noreply.github.com
name: fluxcdbot
messageTemplate: |
Automated image update
Automation name: {{ .AutomationObject }}
Files:
{{ range $filename, $_ := .Updated.Files -}}
- {{ $filename }}
{{ end -}}
Objects:
{{ range $resource, $_ := .Updated.Objects -}}
- {{ $resource.Kind }} {{ $resource.Name }}
{{ end -}}
Images:
{{ range .Updated.Images -}}
- {{.}}
{{ end -}}
update:
path: ./apps/production
strategy: Setters

Image Marker in Manifests

apps/production/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-app
spec:
template:
spec:
containers:
- name: app
image: ghcr.io/example/my-app:1.0.0 # {"$imagepolicy": "flux-system:my-app"}

Notifications

Notification Provider

clusters/production/notification-provider.yaml
apiVersion: notification.toolkit.fluxcd.io/v1beta1
kind: Provider
metadata:
name: slack
namespace: flux-system
spec:
type: slack
channel: flux-notifications
secretRef:
name: slack-webhook
---
apiVersion: v1
kind: Secret
metadata:
name: slack-webhook
namespace: flux-system
stringData:
address: https://hooks.slack.com/services/YOUR/WEBHOOK/URL

Alert

clusters/production/alerts.yaml
apiVersion: notification.toolkit.fluxcd.io/v1beta1
kind: Alert
metadata:
name: on-call-alerts
namespace: flux-system
spec:
providerRef:
name: slack
eventSeverity: error
eventSources:
- kind: GitRepository
name: '*'
- kind: Kustomization
name: '*'
- kind: HelmRelease
name: '*'
suspend: false

Webhook Receiver

clusters/production/receiver.yaml
apiVersion: notification.toolkit.fluxcd.io/v1
kind: Receiver
metadata:
name: github-receiver
namespace: flux-system
spec:
type: github
events:
- "ping"
- "push"
secretRef:
name: webhook-token
resources:
- apiVersion: source.toolkit.fluxcd.io/v1
kind: GitRepository
name: flux-system

Configure webhook in GitHub:

Multi-Cluster Management

Cluster Configuration

Terminal window
# Structure for multiple clusters
fleet-infra/
├── clusters/
│ ├── production-us-east/
│ ├── production-eu-west/
│ └── staging/
└── infrastructure/
├── bases/
└── overlays/
├── production/
└── staging/

Cluster-Specific Kustomization

clusters/production-us-east/infrastructure.yaml
apiVersion: kustomize.toolkit.fluxcd.io/v1
kind: Kustomization
metadata:
name: infrastructure
namespace: flux-system
spec:
interval: 10m
sourceRef:
kind: GitRepository
name: flux-system
path: ./infrastructure/overlays/production
prune: true
postBuild:
substitute:
cluster_region: "us-east-1"
cluster_provider: "aws"
substituteFrom:
- kind: ConfigMap
name: cluster-settings

Flux with Amazon EKS

EKS-Specific Configuration

clusters/eks-production/infrastructure.yaml
apiVersion: kustomize.toolkit.fluxcd.io/v1
kind: Kustomization
metadata:
name: aws-load-balancer-controller
namespace: flux-system
spec:
interval: 1h
sourceRef:
kind: GitRepository
name: flux-system
path: ./infrastructure/aws-load-balancer-controller
prune: true
healthChecks:
- apiVersion: apps/v1
kind: Deployment
name: aws-load-balancer-controller
namespace: kube-system
patches:
- patch: |
- op: replace
path: /spec/template/spec/containers/0/args
value:
- --cluster-name=eks-production
- --aws-region=us-east-1
target:
kind: Deployment
name: aws-load-balancer-controller

IRSA for Flux

Terminal window
# Create IAM role for Flux
eksctl create iamserviceaccount \
--name flux-image-reflector \
--namespace flux-system \
--cluster eks-production \
--attach-policy-arn arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryReadOnly \
--approve

ECR Integration

infrastructure/sources/ecr-credentials.yaml
apiVersion: v1
kind: Secret
metadata:
name: ecr-credentials
namespace: flux-system
type: Opaque
stringData:
username: AWS
password: <ECR_TOKEN>
---
apiVersion: image.toolkit.fluxcd.io/v1beta2
kind: ImageRepository
metadata:
name: my-app
namespace: flux-system
spec:
image: 123456789.dkr.ecr.us-east-1.amazonaws.com/my-app
interval: 1m
secretRef:
name: ecr-credentials

Monitoring Flux

Metrics

# ServiceMonitor for Flux
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
name: flux-system
namespace: flux-system
spec:
endpoints:
- interval: 30s
port: http-prom
selector:
matchLabels:
app: source-controller

Grafana Dashboards

Import official Flux dashboards:

Secrets Management

Sealed Secrets

Terminal window
# Install sealed-secrets controller
flux create source helm sealed-secrets \
--url=https://bitnami-labs.github.io/sealed-secrets \
--interval=1h
flux create helmrelease sealed-secrets \
--source=HelmRepository/sealed-secrets \
--chart=sealed-secrets \
--target-namespace=kube-system \
--create-target-namespace=true
# Create sealed secret
echo -n mypassword | kubectl create secret generic mysecret \
--dry-run=client \
--from-file=password=/dev/stdin \
-o yaml | \
kubeseal -o yaml > mysecret-sealed.yaml

SOPS

Terminal window
# Install SOPS
flux create secret sops age-key \
--namespace=flux-system \
--from-file=age.agekey=/path/to/age.key
# Create encrypted secret
cat <<EOF | sops -e --age <public-key> /dev/stdin > secret.enc.yaml
apiVersion: v1
kind: Secret
metadata:
name: mysecret
stringData:
password: mysecretpassword
EOF

Configure decryption:

# Kustomization with SOPS
spec:
decryption:
provider: sops
secretRef:
name: age-key

Best Practices

Repository Organization

  1. Separate concerns: Infrastructure vs applications
  2. Environment isolation: Separate directories per environment
  3. Base + overlays: Use Kustomize bases and overlays
  4. Helm charts: Keep charts in separate repos

Health Checks

spec:
healthChecks:
- apiVersion: apps/v1
kind: Deployment
name: app1
namespace: default
- apiVersion: apps/v1
kind: StatefulSet
name: database
namespace: default

Dependency Management

spec:
dependsOn:
- name: infrastructure
- name: crds

Suspend Reconciliation

Terminal window
# Suspend specific resource
flux suspend kustomization apps
# Resume
flux resume kustomization apps
# Suspend all
flux suspend kustomization --all

Troubleshooting

Terminal window
# Check all Flux resources
flux get all
# Specific resource types
flux get sources git
flux get kustomizations
flux get helmreleases
# Reconcile immediately
flux reconcile source git flux-system
flux reconcile kustomization apps
# View logs
flux logs --all-namespaces --follow
# Export current state
flux export source git flux-system
flux export kustomization apps
# Trace resource
flux trace deployment/my-app

Conclusion

Flux CD provides a comprehensive, Kubernetes-native GitOps solution with powerful features for managing infrastructure and applications. Its modular architecture, native Kubernetes integration, and extensive tooling make it an excellent choice for teams adopting GitOps practices.


Master GitOps with Flux through our Kubernetes training programs. Contact us for customized training.


Edit page
Share this post on:

Previous Post
Rancher: Complete Kubernetes Management Platform Guide
Next Post
K3s: Lightweight Kubernetes for Production