FluxCD Cheat Sheet
Overview
FluxCD is a set of continuous and progressive delivery solutions for Kubernetes that are open and extensible. It implements GitOps principles to automatically deploy applications and infrastructure changes from Git repositories to Kubernetes clusters, providing declarative, version-controlled, and auditable deployments.
⚠️ Note: Free and open-source. Part of the CNCF (Cloud Native Computing Foundation).
Installation
Prerequisites
# Required tools
kubectl version --client
git --version
curl --version
# Verify Kubernetes cluster access
kubectl cluster-info
kubectl get nodes
# Check cluster permissions
kubectl auth can-i create namespaces
kubectl auth can-i create customresourcedefinitions
Flux CLI Installation
# Linux/macOS
curl -s https://fluxcd.io/install.sh | sudo bash
# macOS with Homebrew
brew install fluxcd/tap/flux
# Windows with Chocolatey
choco install flux
# Windows with Scoop
scoop bucket add flux https://github.com/fluxcd/scoop-bucket
scoop install flux
# Verify installation
flux version --client
Bootstrap Flux
# GitHub bootstrap
export GITHUB_TOKEN=<your-token>
export GITHUB_USER=<your-username>
flux bootstrap github \
--owner=$GITHUB_USER \
--repository=fleet-infra \
--branch=main \
--path=./clusters/my-cluster \
--personal
# GitLab bootstrap
export GITLAB_TOKEN=<your-token>
flux bootstrap gitlab \
--owner=$GITLAB_USER \
--repository=fleet-infra \
--branch=main \
--path=./clusters/my-cluster
# Generic Git bootstrap
flux bootstrap git \
--url=ssh://git@example.com/my-org/my-fleet \
--branch=main \
--path=clusters/my-cluster
Manual Installation
# Install Flux components manually
flux install --export > flux-system.yaml
kubectl apply -f flux-system.yaml
# Verify installation
flux check
kubectl get pods -n flux-system
Core Components
Source Controller
# GitRepository source
apiVersion: source.toolkit.fluxcd.io/v1beta2
kind: GitRepository
metadata:
name: podinfo
namespace: flux-system
spec:
interval: 1m
ref:
branch: master
url: https://github.com/stefanprodan/podinfo
---
# HelmRepository source
apiVersion: source.toolkit.fluxcd.io/v1beta2
kind: HelmRepository
metadata:
name: bitnami
namespace: flux-system
spec:
interval: 1m
url: https://charts.bitnami.com/bitnami
---
# Bucket source (S3, GCS, Azure Blob)
apiVersion: source.toolkit.fluxcd.io/v1beta2
kind: Bucket
metadata:
name: artifacts
namespace: flux-system
spec:
interval: 1m
provider: aws
bucketName: my-artifacts
endpoint: s3.amazonaws.com
region: us-east-1
Kustomize Controller
# Kustomization
apiVersion: kustomize.toolkit.fluxcd.io/v1beta2
kind: Kustomization
metadata:
name: podinfo
namespace: flux-system
spec:
interval: 5m
path: "./kustomize"
prune: true
sourceRef:
kind: GitRepository
name: podinfo
validation: client
healthChecks:
- apiVersion: apps/v1
kind: Deployment
name: podinfo
namespace: default
timeout: 2m
Helm Controller
# HelmRelease
apiVersion: helm.toolkit.fluxcd.io/v2beta1
kind: HelmRelease
metadata:
name: nginx-ingress
namespace: flux-system
spec:
interval: 5m
chart:
spec:
chart: nginx-ingress
version: "4.0.6"
sourceRef:
kind: HelmRepository
name: bitnami
namespace: flux-system
values:
service:
type: LoadBalancer
metrics:
enabled: true
upgrade:
remediation:
retries: 3
Notification Controller
# Provider (Slack)
apiVersion: notification.toolkit.fluxcd.io/v1beta1
kind: Provider
metadata:
name: slack
namespace: flux-system
spec:
type: slack
channel: general
secretRef:
name: slack-webhook
---
# Alert
apiVersion: notification.toolkit.fluxcd.io/v1beta1
kind: Alert
metadata:
name: on-call-webhook
namespace: flux-system
spec:
providerRef:
name: slack
eventSeverity: info
eventSources:
- kind: GitRepository
name: '*'
- kind: Kustomization
name: '*'
GitOps Workflow
Repository Structure
# Recommended GitOps repository structure
fleet-infra/
├── apps/
│ ├── base/
│ │ ├── podinfo/
│ │ │ ├── kustomization.yaml
│ │ │ ├── deployment.yaml
│ │ │ └── service.yaml
│ │ └── nginx/
│ └── production/
│ ├── kustomization.yaml
│ └── podinfo-patch.yaml
├── infrastructure/
│ ├── controllers/
│ │ ├── kustomization.yaml
│ │ └── ingress-nginx.yaml
│ └── configs/
│ ├── kustomization.yaml
│ └── cluster-config.yaml
└── clusters/
└── production/
├── flux-system/
│ ├── gotk-components.yaml
│ ├── gotk-sync.yaml
│ └── kustomization.yaml
├── apps.yaml
└── infrastructure.yaml
Multi-Environment Setup
# clusters/staging/apps.yaml
apiVersion: kustomize.toolkit.fluxcd.io/v1beta2
kind: Kustomization
metadata:
name: apps
namespace: flux-system
spec:
interval: 10m
sourceRef:
kind: GitRepository
name: flux-system
path: ./apps/staging
prune: true
validation: client
---
# clusters/production/apps.yaml
apiVersion: kustomize.toolkit.fluxcd.io/v1beta2
kind: Kustomization
metadata:
name: apps
namespace: flux-system
spec:
interval: 10m
sourceRef:
kind: GitRepository
name: flux-system
path: ./apps/production
prune: true
validation: client
healthChecks:
- apiVersion: apps/v1
kind: Deployment
name: podinfo
namespace: podinfo
Progressive Delivery
# Canary deployment with Flagger
apiVersion: flagger.app/v1beta1
kind: Canary
metadata:
name: podinfo
namespace: test
spec:
targetRef:
apiVersion: apps/v1
kind: Deployment
name: podinfo
progressDeadlineSeconds: 60
service:
port: 9898
targetPort: 9898
gateways:
- public-gateway.istio-system.svc.cluster.local
hosts:
- app.example.com
analysis:
interval: 1m
threshold: 5
maxWeight: 50
stepWeight: 10
metrics:
- name: request-success-rate
thresholdRange:
min: 99
interval: 1m
- name: request-duration
thresholdRange:
max: 500
interval: 30s
CLI Commands
Basic Commands
# Check Flux installation
flux check
# Get system status
flux get all
# Get sources
flux get sources all
flux get sources git
flux get sources helm
# Get Kustomizations
flux get kustomizations
# Get Helm releases
flux get helmreleases
# Suspend/resume reconciliation
flux suspend kustomization podinfo
flux resume kustomization podinfo
Source Management
# Create Git source
flux create source git podinfo \
--url=https://github.com/stefanprodan/podinfo \
--branch=master \
--interval=1m \
--export > podinfo-source.yaml
# Create Helm source
flux create source helm bitnami \
--url=https://charts.bitnami.com/bitnami \
--interval=1m
# Update source
flux reconcile source git podinfo
# Delete source
flux delete source git podinfo
Kustomization Management
# Create Kustomization
flux create kustomization podinfo \
--target-namespace=default \
--source=podinfo \
--path="./kustomize" \
--prune=true \
--interval=5m
# Reconcile Kustomization
flux reconcile kustomization podinfo
# Get Kustomization status
flux get kustomization podinfo
# Suspend Kustomization
flux suspend kustomization podinfo
Helm Management
# Create Helm release
flux create helmrelease nginx-ingress \
--source=HelmRepository/bitnami \
--chart=nginx-ingress \
--target-namespace=ingress-nginx \
--create-target-namespace=true
# Upgrade Helm release
flux reconcile helmrelease nginx-ingress
# Get Helm release status
flux get helmreleases
# Delete Helm release
flux delete helmrelease nginx-ingress
Advanced Configuration
Multi-Tenancy
# Tenant namespace and RBAC
apiVersion: v1
kind: Namespace
metadata:
name: tenant-a
labels:
toolkit.fluxcd.io/tenant: tenant-a
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: tenant-a-reconciler
namespace: tenant-a
subjects:
- kind: ServiceAccount
name: kustomize-controller
namespace: flux-system
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: cluster-admin
---
# Tenant Kustomization
apiVersion: kustomize.toolkit.fluxcd.io/v1beta2
kind: Kustomization
metadata:
name: tenant-a-apps
namespace: flux-system
spec:
interval: 5m
sourceRef:
kind: GitRepository
name: tenant-a-repo
path: "./apps"
prune: true
targetNamespace: tenant-a
serviceAccountName: tenant-a-reconciler
Secret Management
# Sealed Secrets integration
apiVersion: bitnami.com/v1alpha1
kind: SealedSecret
metadata:
name: mysecret
namespace: default
spec:
encryptedData:
password: AgBy3i4OJSWK+PiTySYZZA9rO43cGDEQAx...
---
# External Secrets Operator
apiVersion: external-secrets.io/v1beta1
kind: SecretStore
metadata:
name: vault-backend
namespace: default
spec:
provider:
vault:
server: "https://vault.example.com"
path: "secret"
version: "v2"
auth:
kubernetes:
mountPath: "kubernetes"
role: "example"
---
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
name: vault-secret
namespace: default
spec:
refreshInterval: 15s
secretStoreRef:
name: vault-backend
kind: SecretStore
target:
name: example-secret
creationPolicy: Owner
data:
- secretKey: password
remoteRef:
key: secret/data/database
property: password
Image Automation
# Image repository
apiVersion: image.toolkit.fluxcd.io/v1beta2
kind: ImageRepository
metadata:
name: podinfo
namespace: flux-system
spec:
image: ghcr.io/stefanprodan/podinfo
interval: 1m
---
# Image policy
apiVersion: image.toolkit.fluxcd.io/v1beta2
kind: ImagePolicy
metadata:
name: podinfo
namespace: flux-system
spec:
imageRepositoryRef:
name: podinfo
policy:
semver:
range: 5.0.x
---
# Image update automation
apiVersion: image.toolkit.fluxcd.io/v1beta1
kind: ImageUpdateAutomation
metadata:
name: flux-system
namespace: flux-system
spec:
interval: 30m
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 -}}
push:
branch: main
update:
path: "./clusters/my-cluster"
strategy: Setters
Monitoring and Observability
Prometheus Metrics
# ServiceMonitor for Flux controllers
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
name: flux-system
namespace: flux-system
spec:
selector:
matchLabels:
app.kubernetes.io/part-of: flux
endpoints:
- port: http-prom
interval: 15s
path: /metrics
---
# Grafana dashboard ConfigMap
apiVersion: v1
kind: ConfigMap
metadata:
name: flux-grafana-dashboard
namespace: monitoring
labels:
grafana_dashboard: "1"
data:
flux-cluster.json: |
{
"dashboard": {
"title": "Flux Cluster Stats",
"panels": [
{
"title": "Reconciliation Duration",
"type": "graph",
"targets": [
{
"expr": "gotk_reconcile_duration_seconds{kind=\"Kustomization\"}"
}
]
}
]
}
}
Alerting Rules
# PrometheusRule for Flux alerts
apiVersion: monitoring.coreos.com/v1
kind: PrometheusRule
metadata:
name: flux-alerts
namespace: flux-system
spec:
groups:
- name: flux
rules:
- alert: FluxReconciliationFailure
expr: max(gotk_reconcile_condition{type="Ready",status="False"}) by (exported_namespace, name, kind) + on(exported_namespace, name, kind) (max(gotk_reconcile_condition{type="Ready",status="False"}) by (exported_namespace, name, kind)) > 0
for: 10m
labels:
severity: critical
annotations:
summary: "Flux reconciliation failure"
description: "{{ $labels.kind }}/{{ $labels.name }} in {{ $labels.exported_namespace }} has been failing for more than 10 minutes."
- alert: FluxSuspendedResource
expr: max(gotk_suspend_status) by (exported_namespace, name, kind) > 0
for: 1h
labels:
severity: warning
annotations:
summary: "Flux resource suspended"
description: "{{ $labels.kind }}/{{ $labels.name }} in {{ $labels.exported_namespace }} has been suspended for more than 1 hour."
Logging Configuration
# Fluent Bit configuration for Flux logs
apiVersion: v1
kind: ConfigMap
metadata:
name: fluent-bit-config
namespace: flux-system
data:
fluent-bit.conf: |
[SERVICE]
Flush 1
Log_Level info
Daemon off
Parsers_File parsers.conf
[INPUT]
Name tail
Path /var/log/containers/*flux*.log
Parser docker
Tag flux.*
Refresh_Interval 5
[OUTPUT]
Name es
Match flux.*
Host elasticsearch.logging.svc.cluster.local
Port 9200
Index flux-logs
Security and RBAC
Service Account Configuration
# Custom service account for Flux
apiVersion: v1
kind: ServiceAccount
metadata:
name: flux-custom
namespace: flux-system
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: flux-custom
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: cluster-admin
subjects:
- kind: ServiceAccount
name: flux-custom
namespace: flux-system
---
# Use custom service account in Kustomization
apiVersion: kustomize.toolkit.fluxcd.io/v1beta2
kind: Kustomization
metadata:
name: apps
namespace: flux-system
spec:
serviceAccountName: flux-custom
interval: 10m
sourceRef:
kind: GitRepository
name: flux-system
path: ./apps
Network Policies
# Network policy for Flux system
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: flux-system
namespace: flux-system
spec:
podSelector:
matchLabels:
app.kubernetes.io/part-of: flux
policyTypes:
- Ingress
- Egress
ingress:
- from:
- namespaceSelector:
matchLabels:
name: monitoring
ports:
- protocol: TCP
port: 8080
egress:
- to: []
ports:
- protocol: TCP
port: 443
- protocol: TCP
port: 80
- to:
- namespaceSelector: {}
ports:
- protocol: TCP
port: 6443
Pod Security Standards
# Pod Security Policy for Flux
apiVersion: policy/v1beta1
kind: PodSecurityPolicy
metadata:
name: flux-psp
spec:
privileged: false
allowPrivilegeEscalation: false
requiredDropCapabilities:
- ALL
volumes:
- 'configMap'
- 'emptyDir'
- 'projected'
- 'secret'
- 'downwardAPI'
- 'persistentVolumeClaim'
runAsUser:
rule: 'MustRunAsNonRoot'
seLinux:
rule: 'RunAsAny'
fsGroup:
rule: 'RunAsAny'
Troubleshooting
Common Issues
# Check Flux system status
flux check
# Get events for debugging
kubectl get events -n flux-system --sort-by='.lastTimestamp'
# Check controller logs
kubectl logs -n flux-system deployment/source-controller
kubectl logs -n flux-system deployment/kustomize-controller
kubectl logs -n flux-system deployment/helm-controller
# Debug reconciliation
flux reconcile source git flux-system --verbose
flux reconcile kustomization flux-system --verbose
# Check resource conditions
kubectl describe gitrepository flux-system -n flux-system
kubectl describe kustomization apps -n flux-system
Performance Tuning
# Tune controller resource limits
apiVersion: apps/v1
kind: Deployment
metadata:
name: kustomize-controller
namespace: flux-system
spec:
template:
spec:
containers:
- name: manager
resources:
limits:
cpu: 1000m
memory: 1Gi
requests:
cpu: 100m
memory: 64Mi
args:
- --events-addr=http://notification-controller.flux-system.svc.cluster.local./
- --watch-all-namespaces=true
- --log-level=info
- --log-encoding=json
- --enable-leader-election
- --concurrent=10 # Increase concurrency
- --kube-api-qps=50 # Increase API QPS
- --kube-api-burst=100 # Increase API burst
Debugging Git Authentication
# Test Git connectivity
flux create source git test-repo \
--url=https://github.com/your-org/your-repo \
--branch=main \
--interval=1m \
--secret-ref=git-credentials
# Check secret format
kubectl get secret git-credentials -n flux-system -o yaml
# For SSH keys
kubectl create secret generic git-credentials \
--from-file=identity=/path/to/private/key \
--from-file=identity.pub=/path/to/public/key \
--from-file=known_hosts=/path/to/known_hosts \
-n flux-system
# For HTTPS with token
kubectl create secret generic git-credentials \
--from-literal=username=git \
--from-literal=password=your-token \
-n flux-system
Best Practices
Repository Organization
# Separate concerns
fleet-infra/ # Infrastructure and platform
├── clusters/ # Cluster-specific configurations
├── infrastructure/ # Shared infrastructure components
└── tenants/ # Tenant-specific configurations
app-manifests/ # Application manifests
├── base/ # Base configurations
├── overlays/ # Environment-specific overlays
└── releases/ # Helm releases
Security Best Practices
# 1. Use least-privilege RBAC
# 2. Enable Pod Security Standards
# 3. Use network policies
# 4. Scan images for vulnerabilities
# 5. Use sealed secrets or external secret management
# 6. Enable audit logging
# 7. Regular security updates
# 8. Monitor for drift and unauthorized changes
Performance Optimization
# 1. Tune reconciliation intervals based on needs
# 2. Use health checks for critical deployments
# 3. Implement proper resource limits
# 4. Use dependency ordering with depends-on
# 5. Monitor controller resource usage
# 6. Use horizontal pod autoscaling for controllers
# 7. Optimize Git repository structure
# 8. Use shallow clones for large repositories
Disaster Recovery
# 1. Backup Flux configuration
kubectl get gitrepository,kustomization,helmrelease -A -o yaml > flux-backup.yaml
# 2. Document bootstrap procedure
# 3. Test recovery procedures regularly
# 4. Use multiple Git repositories for redundancy
# 5. Monitor cluster state drift
# 6. Implement automated backup strategies
# 7. Document rollback procedures
# 8. Test cross-cluster migrations
Integration Examples
ArgoCD Migration
# Convert ArgoCD Application to Flux Kustomization
# ArgoCD Application:
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: podinfo
spec:
source:
repoURL: https://github.com/stefanprodan/podinfo
path: kustomize
targetRevision: master
destination:
server: https://kubernetes.default.svc
namespace: default
# Equivalent Flux resources:
apiVersion: source.toolkit.fluxcd.io/v1beta2
kind: GitRepository
metadata:
name: podinfo
spec:
url: https://github.com/stefanprodan/podinfo
ref:
branch: master
interval: 1m
---
apiVersion: kustomize.toolkit.fluxcd.io/v1beta2
kind: Kustomization
metadata:
name: podinfo
spec:
sourceRef:
kind: GitRepository
name: podinfo
path: ./kustomize
targetNamespace: default
interval: 5m
Tekton Integration
# Tekton Pipeline to update Flux
apiVersion: tekton.dev/v1beta1
kind: Pipeline
metadata:
name: update-flux-image
spec:
params:
- name: image-tag
type: string
- name: git-repo
type: string
tasks:
- name: update-manifest
taskSpec:
params:
- name: image-tag
- name: git-repo
steps:
- name: update
image: alpine/git
script: |
#!/bin/sh
git clone $(params.git-repo) /workspace
cd /workspace
sed -i 's|image: .*|image: myapp:$(params.image-tag)|' apps/myapp/deployment.yaml
git add .
git commit -m "Update image to $(params.image-tag)"
git push