Flux CD
GitOps toolkit for Kubernetes with modular components and native image automation
Flux is a CNCF graduated project that provides a set of continuous and progressive delivery solutions for Kubernetes. It keeps clusters in sync with sources of configuration and automates updates when new code is deployed.
What you'll learn
- Flux architecture and controllers
- Installation and bootstrapping
- Source management (Git, Helm, OCI)
- Kustomization and HelmRelease resources
- Image automation and policies
- Notifications and alerting
Related tools
- Flagger for progressive delivery
- Kustomize for configuration
- Helm for package management
- SOPS for secret encryption
Why Flux?#
Flux brings a modular, composable GitOps architecture to Kubernetes:
| Feature | Benefit |
|---|---|
| CNCF Graduated | Production-ready, community-driven |
| Modular Design | Use only the components you need |
| Native Image Automation | Automatic image updates with policies |
| Multi-tenancy | Built-in tenant isolation |
| OCI Support | Store configs in container registries |
| SOPS Integration | Native secret decryption |
Architecture#
1┌─────────────────────────────────────────────────────────────────┐2│ Flux Components │3│ │4│ ┌─────────────────────────────────────────────────────────┐ │5│ │ Source Controller │ │6│ │ ┌───────────┐ ┌───────────┐ ┌───────────┐ │ │7│ │ │GitRepo │ │HelmRepo │ │OCIRepo │ │ │8│ │ └───────────┘ └───────────┘ └───────────┘ │ │9│ └──────────────────────────┬──────────────────────────────┘ │10│ │ │11│ ┌──────────────────────────▼──────────────────────────────┐ │12│ │ Kustomize / Helm Controller │ │13│ │ ┌─────────────────┐ ┌─────────────────┐ │ │14│ │ │ Kustomization │ │ HelmRelease │ │ │15│ │ └─────────────────┘ └─────────────────┘ │ │16│ └──────────────────────────┬──────────────────────────────┘ │17│ │ │18│ ┌──────────────────────────▼──────────────────────────────┐ │19│ │ Notification Controller │ │20│ │ ┌───────────┐ ┌───────────┐ ┌───────────┐ │ │21│ │ │ Provider │ │ Alert │ │ Receiver │ │ │22│ │ └───────────┘ └───────────┘ └───────────┘ │ │23│ └─────────────────────────────────────────────────────────┘ │24│ │25│ ┌─────────────────────────────────────────────────────────┐ │26│ │ Image Automation Controllers │ │27│ │ ┌─────────────────────┐ ┌─────────────────────┐ │ │28│ │ │ ImageRepository │ │ ImagePolicy │ │ │29│ │ └─────────────────────┘ └─────────────────────┘ │ │30│ │ ┌─────────────────────┐ │ │31│ │ │ ImageUpdateAuto │ │ │32│ │ └─────────────────────┘ │ │33│ └─────────────────────────────────────────────────────────┘ │34└─────────────────────────────────────────────────────────────────┘Controllers#
Source Controller Fetches artifacts from Git repositories, Helm repositories, S3-compatible buckets, and OCI registries.
Kustomize Controller Builds and applies Kustomize overlays. Supports variable substitution and SOPS decryption.
Helm Controller Manages Helm chart releases with support for values files, dependencies, and drift detection.
Notification Controller Handles inbound webhooks and outbound notifications to Slack, Teams, PagerDuty, and more.
Image Reflector Controller Scans container registries and reflects image metadata.
Image Automation Controller Updates Git repositories with new image versions based on policies.
Installation#
Using Flux CLI#
1#!/bin/bash2# Flux installation script34# Install Flux CLI5curl -s https://fluxcd.io/install.sh | sudo bash67# Verify installation8flux --version910# Pre-flight checks11flux check --pre1213# Bootstrap Flux with GitHub14flux bootstrap github \15 --owner=company \16 --repository=flux-config \17 --branch=main \18 --path=clusters/production \19 --personal \20 --components-extra=image-reflector-controller,image-automation-controller2122# Verify Flux is running23flux check2425# Get reconciliation status26flux get all2728echo "Flux installed and bootstrapped successfully"Bootstrap with GitLab#
1flux bootstrap gitlab \2 --owner=company \3 --repository=flux-config \4 --branch=main \5 --path=clusters/production \6 --token-authBootstrap with Existing Repository#
1flux bootstrap git \2 --url=ssh://[email protected]/company/fleet-infra \3 --branch=main \4 --path=clusters/production \5 --private-key-file=/path/to/private/keySource Management#
GitRepository#
1apiVersion: source.toolkit.fluxcd.io/v12kind: GitRepository3metadata:4 name: application-repo5 namespace: flux-system6spec:7 interval: 1m8 url: https://github.com/company/application.git9 ref:10 branch: main11 secretRef:12 name: github-auth13 ignore: |14 # Exclude CI/CD files15 /.github/16 /.gitlab-ci.yml17 /JenkinsfileHelmRepository#
1apiVersion: source.toolkit.fluxcd.io/v12kind: HelmRepository3metadata:4 name: bitnami5 namespace: flux-system6spec:7 interval: 30m8 url: https://charts.bitnami.com/bitnami910---11apiVersion: source.toolkit.fluxcd.io/v112kind: HelmRepository13metadata:14 name: ingress-nginx15 namespace: flux-system16spec:17 interval: 30m18 url: https://kubernetes.github.io/ingress-nginxOCIRepository#
1apiVersion: source.toolkit.fluxcd.io/v1beta22kind: OCIRepository3metadata:4 name: company-charts5 namespace: flux-system6spec:7 interval: 5m8 url: oci://ghcr.io/company/charts9 ref:10 semver: ">=1.0.0"11 secretRef:12 name: ghcr-authBucket (S3-compatible)#
1apiVersion: source.toolkit.fluxcd.io/v1beta22kind: Bucket3metadata:4 name: config-bucket5 namespace: flux-system6spec:7 interval: 5m8 provider: aws9 bucketName: my-config-bucket10 region: us-east-111 secretRef:12 name: aws-credentialsKustomization#
Basic Kustomization#
1apiVersion: kustomize.toolkit.fluxcd.io/v12kind: Kustomization3metadata:4 name: applications5 namespace: flux-system6spec:7 interval: 10m8 path: ./apps/production9 prune: true10 sourceRef:11 kind: GitRepository12 name: application-repo1314 # Health checks for deployed resources15 healthChecks:16 - apiVersion: apps/v117 kind: Deployment18 name: payment-service19 namespace: payments20 - apiVersion: apps/v121 kind: Deployment22 name: user-service23 namespace: users2425 # Timeout for health checks26 timeout: 5m2728 # Retry on failure29 retryInterval: 2mKustomization with Dependencies#
1apiVersion: kustomize.toolkit.fluxcd.io/v12kind: Kustomization3metadata:4 name: applications5 namespace: flux-system6spec:7 interval: 10m8 path: ./apps/production9 prune: true10 sourceRef:11 kind: GitRepository12 name: application-repo1314 # Wait for dependencies15 dependsOn:16 - name: infrastructure17 - name: cert-manager1819 # Post-build variable substitution20 postBuild:21 substitute:22 CLUSTER_NAME: production23 ENVIRONMENT: prod24 substituteFrom:25 - kind: ConfigMap26 name: cluster-config27 - kind: Secret28 name: cluster-secretsKustomization with SOPS Decryption#
1apiVersion: kustomize.toolkit.fluxcd.io/v12kind: Kustomization3metadata:4 name: applications5 namespace: flux-system6spec:7 interval: 10m8 path: ./apps/production9 prune: true10 sourceRef:11 kind: GitRepository12 name: application-repo1314 # Decryption with SOPS15 decryption:16 provider: sops17 secretRef:18 name: sops-ageMulti-tenant Kustomization#
1apiVersion: kustomize.toolkit.fluxcd.io/v12kind: Kustomization3metadata:4 name: tenants5 namespace: flux-system6spec:7 interval: 5m8 path: ./tenants9 prune: true10 sourceRef:11 kind: GitRepository12 name: application-repo1314 # Service account impersonation for multi-tenancy15 serviceAccountName: flux-reconciler1617 # Validation and enforcement18 validation: client19 force: falseHelmRelease#
Basic HelmRelease#
1apiVersion: helm.toolkit.fluxcd.io/v22kind: HelmRelease3metadata:4 name: payment-service5 namespace: payments6spec:7 interval: 30m8 timeout: 10m910 chart:11 spec:12 chart: payment-service13 version: ">=1.0.0 <2.0.0"14 sourceRef:15 kind: HelmRepository16 name: company-charts17 namespace: flux-system18 interval: 5m1920 # Installation configuration21 install:22 createNamespace: true23 remediation:24 retries: 32526 # Upgrade configuration27 upgrade:28 remediation:29 retries: 330 remediateLastFailure: true31 cleanupOnFail: true3233 # Rollback configuration34 rollback:35 timeout: 5m36 cleanupOnFail: true3738 # Test configuration39 test:40 enable: true41 timeout: 5m4243 # Values44 values:45 replicaCount: 34647 image:48 repository: ghcr.io/company/payment-service49 tag: v1.2.35051 resources:52 requests:53 cpu: 100m54 memory: 128Mi55 limits:56 cpu: 500m57 memory: 512Mi5859 ingress:60 enabled: true61 className: nginx62 hosts:63 - host: payments.example.com64 paths:65 - path: /66 pathType: Prefix6768 autoscaling:69 enabled: true70 minReplicas: 371 maxReplicas: 1072 targetCPUUtilizationPercentage: 70HelmRelease with Drift Detection#
1apiVersion: helm.toolkit.fluxcd.io/v22kind: HelmRelease3metadata:4 name: payment-service5 namespace: payments6spec:7 interval: 30m8 chart:9 spec:10 chart: payment-service11 sourceRef:12 kind: HelmRepository13 name: company-charts14 namespace: flux-system1516 # Drift detection17 driftDetection:18 mode: enabled19 ignore:20 - paths: ["/spec/replicas"]21 target:22 kind: Deployment2324 values:25 replicaCount: 3HelmRelease with External Values#
1apiVersion: helm.toolkit.fluxcd.io/v22kind: HelmRelease3metadata:4 name: payment-service5 namespace: payments6spec:7 interval: 30m8 chart:9 spec:10 chart: payment-service11 sourceRef:12 kind: HelmRepository13 name: company-charts14 namespace: flux-system1516 # Values from external sources17 valuesFrom:18 - kind: ConfigMap19 name: payment-service-config20 valuesKey: values.yaml21 - kind: Secret22 name: payment-service-secrets23 valuesKey: secrets.yaml2425 # Dependency on other HelmReleases26 dependsOn:27 - name: postgresql28 namespace: databases29 - name: redis30 namespace: cachingHelmRelease with OCI Chart#
1apiVersion: helm.toolkit.fluxcd.io/v22kind: HelmRelease3metadata:4 name: monitoring-stack5 namespace: monitoring6spec:7 interval: 1h89 chartRef:10 kind: OCIRepository11 name: kube-prometheus-stack12 namespace: flux-system1314 values:15 prometheus:16 prometheusSpec:17 retention: 30d18 storageSpec:19 volumeClaimTemplate:20 spec:21 storageClassName: gp322 resources:23 requests:24 storage: 100Gi2526 grafana:27 adminPassword: ${GRAFANA_ADMIN_PASSWORD}Image Automation#
ImageRepository#
1apiVersion: image.toolkit.fluxcd.io/v1beta22kind: ImageRepository3metadata:4 name: payment-service5 namespace: flux-system6spec:7 image: ghcr.io/company/payment-service8 interval: 5m9 secretRef:10 name: ghcr-authImagePolicy#
1# Production: only stable releases2apiVersion: image.toolkit.fluxcd.io/v1beta23kind: ImagePolicy4metadata:5 name: payment-service-production6 namespace: flux-system7spec:8 imageRepositoryRef:9 name: payment-service10 policy:11 semver:12 range: ">=1.0.0 <2.0.0"13 filterTags:14 pattern: '^v(?P<version>[0-9]+\.[0-9]+\.[0-9]+)$'15 extract: '$version'1617---18# Staging: latest including pre-releases19apiVersion: image.toolkit.fluxcd.io/v1beta220kind: ImagePolicy21metadata:22 name: payment-service-staging23 namespace: flux-system24spec:25 imageRepositoryRef:26 name: payment-service27 policy:28 alphabetical:29 order: desc30 filterTags:31 pattern: '^main-[a-f0-9]+-(?P<ts>[0-9]+)$'32 extract: '$ts'ImageUpdateAutomation#
1apiVersion: image.toolkit.fluxcd.io/v1beta22kind: ImageUpdateAutomation3metadata:4 name: application-automation5 namespace: flux-system6spec:7 interval: 30m89 sourceRef:10 kind: GitRepository11 name: application-repo1213 git:14 checkout:15 ref:16 branch: main17 commit:18 author:19 email: [email protected]20 name: FluxBot21 messageTemplate: |22 chore: update images2324 Automated image update:25 {{range .Changed.Changes}}26 - {{.OldValue}} -> {{.NewValue}}27 {{end}}28 push:29 branch: main3031 update:32 path: ./apps33 strategy: SettersImage Update Markers in Manifests#
1# apps/production/payment-service/deployment.yaml2apiVersion: apps/v13kind: Deployment4metadata:5 name: payment-service6 namespace: payments7spec:8 replicas: 39 selector:10 matchLabels:11 app: payment-service12 template:13 metadata:14 labels:15 app: payment-service16 spec:17 containers:18 - name: payment-service19 # {"$imagepolicy": "flux-system:payment-service-production"}20 image: ghcr.io/company/payment-service:v1.2.321 ports:22 - containerPort: 8080Notifications#
Providers#
1apiVersion: notification.toolkit.fluxcd.io/v1beta32kind: Provider3metadata:4 name: slack-alerts5 namespace: flux-system6spec:7 type: slack8 channel: flux-notifications9 secretRef:10 name: slack-webhook1112---13apiVersion: notification.toolkit.fluxcd.io/v1beta314kind: Provider15metadata:16 name: github-status17 namespace: flux-system18spec:19 type: github20 address: https://github.com/company/application21 secretRef:22 name: github-token2324---25apiVersion: notification.toolkit.fluxcd.io/v1beta326kind: Provider27metadata:28 name: pagerduty29 namespace: flux-system30spec:31 type: pagerduty32 secretRef:33 name: pagerduty-keyAlerts#
1apiVersion: notification.toolkit.fluxcd.io/v1beta32kind: Alert3metadata:4 name: flux-alerts5 namespace: flux-system6spec:7 providerRef:8 name: slack-alerts9 eventSeverity: info10 eventSources:11 - kind: GitRepository12 name: '*'13 - kind: Kustomization14 name: '*'15 - kind: HelmRelease16 name: '*'17 exclusionList:18 - ".*no new revision.*"1920---21apiVersion: notification.toolkit.fluxcd.io/v1beta322kind: Alert23metadata:24 name: critical-alerts25 namespace: flux-system26spec:27 providerRef:28 name: pagerduty29 eventSeverity: error30 eventSources:31 - kind: Kustomization32 name: '*'33 namespace: production34 - kind: HelmRelease35 name: '*'36 namespace: productionWebhook Receiver#
1apiVersion: notification.toolkit.fluxcd.io/v12kind: Receiver3metadata:4 name: github-webhook5 namespace: flux-system6spec:7 type: github8 events:9 - push10 secretRef:11 name: github-webhook-secret12 resources:13 - kind: GitRepository14 name: application-repo15 namespace: flux-systemSecret Management with SOPS#
SOPS Configuration#
1# .sops.yaml2creation_rules:3 - path_regex: .*\.enc\.yaml$4 encrypted_regex: ^(data|stringData)$5 age: age1...public-key...67 - path_regex: clusters/production/.*8 encrypted_regex: ^(data|stringData)$9 age: >-10 age1...production-key...,11 age1...backup-key...1213 - path_regex: clusters/staging/.*14 encrypted_regex: ^(data|stringData)$15 age: age1...staging-key...Encrypted Secret#
1# secrets/database.enc.yaml2apiVersion: v13kind: Secret4metadata:5 name: database-credentials6 namespace: payments7type: Opaque8stringData:9 username: ENC[AES256_GCM,data:...,type:str]10 password: ENC[AES256_GCM,data:...,type:str]11sops:12 age:13 - recipient: age1...14 enc: |15 -----BEGIN AGE ENCRYPTED FILE-----16 ...17 -----END AGE ENCRYPTED FILE-----18 lastmodified: "2024-01-15T10:30:00Z"19 version: 3.8.1SOPS Key Secret#
1# Create SOPS key secret2age-keygen -o age.agekey34kubectl create secret generic sops-age \5 --namespace=flux-system \6 --from-file=age.agekey=age.agekeyRepository Structure#
Recommended Layout#
1flux-repo/2├── apps/3│ ├── base/4│ │ ├── payment-service/5│ │ │ ├── deployment.yaml6│ │ │ ├── service.yaml7│ │ │ └── kustomization.yaml8│ │ └── user-service/9│ └── overlays/10│ ├── development/11│ ├── staging/12│ └── production/13│14├── infrastructure/15│ ├── base/16│ │ ├── cert-manager/17│ │ ├── ingress-nginx/18│ │ └── monitoring/19│ └── overlays/20│ ├── development/21│ ├── staging/22│ └── production/23│24├── clusters/25│ ├── development/26│ │ ├── flux-system/27│ │ ├── apps.yaml28│ │ └── infrastructure.yaml29│ ├── staging/30│ └── production/31│ ├── flux-system/32│ ├── apps.yaml33│ ├── infrastructure.yaml34│ └── notifications.yaml35│36└── tenants/37 ├── team-payments/38 │ ├── rbac.yaml39 │ └── namespace.yaml40 └── team-users/Cluster Configuration#
1# clusters/production/apps.yaml2apiVersion: kustomize.toolkit.fluxcd.io/v13kind: Kustomization4metadata:5 name: apps6 namespace: flux-system7spec:8 interval: 10m9 sourceRef:10 kind: GitRepository11 name: flux-system12 path: ./apps/overlays/production13 prune: true14 dependsOn:15 - name: infrastructureBest Practices#
Flux Configuration#
- Use interval appropriately - Balance between responsiveness and API load
- Enable pruning - Remove resources not in Git
- Set health checks - Verify deployments before marking as ready
- Use dependencies - Ensure correct deployment order
Security#
- SOPS for secrets - Never commit plain secrets
- RBAC isolation - Use separate service accounts per tenant
- Network policies - Restrict Flux controller network access
- Audit logging - Enable notification alerts for all changes
Performance#
- Repository caching - Reduce Git operations
- Selective reconciliation - Only reconcile changed paths
- Resource limits - Set appropriate controller limits
- Parallel reconciliation - Configure controller concurrency
Flux vs ArgoCD#
| Aspect | Flux | ArgoCD |
|---|---|---|
| UI | Weave GitOps (separate) | Built-in rich UI |
| Image Updates | Native ImagePolicy | Argo Image Updater |
| Architecture | Modular controllers | Monolithic |
| Multi-tenancy | Built-in isolation | Project-based |
| Learning Curve | Steeper | Gentler |
| Resource Usage | Lower | Higher |