FluxCD
FluxCD is DIT's GitOps tool for continuous delivery to Kubernetes. It automatically synchronizes the desired state defined in Git repositories with the actual state of Kubernetes clusters.
What is GitOps?
GitOps is an operational framework that applies DevOps best practices—such as version control, collaboration, compliance, and CI/CD—to infrastructure automation.
Core Principles
- Declarative Configuration – The entire system is described declaratively in Git
- Versioned and Immutable – The desired state is versioned in Git, providing a complete audit trail
- Pulled Automatically – Approved changes are automatically applied to the cluster
- Continuously Reconciled – Agents ensure the actual state matches the desired state
DIT's GitOps Architecture
┌───────────────────────────────────────────────────────────────┐
│ GitHub │
│ ┌─────────────────┐ ┌─────────────────────────────┐ │
│ │ Application Repo│ ──────► │ GitOps Repo │ │
│ │ (source code) │ CI/CD │ (HelmRelease manifests) │ │
│ └─────────────────┘ PR └─────────────────────────────┘ │
└───────────────────────────────────────────────────────────────┘
│
│ FluxCD watches
▼
┌───────────────────────────────────────────────────────────────┐
│ Kubernetes Cluster │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ FluxCD Controllers │ │
│ │ • source-controller (fetches from Git) │ │
│ │ • kustomize-controller (applies manifests) │ │
│ │ • helm-controller (manages Helm releases) │ │
│ │ • notification-controller (sends alerts) │ │
│ └─────────────────────────────────────────────────────────┘ │
└───────────────────────────────────────────────────────────────┘Repository Structure
DIT follows a standardized GitOps repository structure per project/platform:
my-team-gitops/
├── main/
│ ├── development/
│ │ └── kustomization.yaml # References all dev components
│ ├── staging/
│ │ └── kustomization.yaml # References all staging components
│ └── production/
│ └── kustomization.yaml # References all prod components
├── my-api/
│ ├── base/
│ │ ├── kustomization.yaml
│ │ └── release.yaml # Base HelmRelease
│ ├── dev/
│ │ ├── kustomization.yaml
│ │ ├── release.yaml # Dev-specific overrides
│ │ └── image.yaml # Auto-updated image tags
│ ├── staging/
│ │ ├── kustomization.yaml
│ │ ├── release.yaml # Staging-specific overrides
│ │ └── image.yaml # Auto-updated image tags
│ └── production/
│ ├── kustomization.yaml
│ ├── release.yaml # Prod-specific overrides
│ └── image.yaml # Auto-updated image tags
├── rabbitmq/
│ └── ...
├── redis/
│ └── ...
└── README.mdMain Environment Aggregator
The main/ directory aggregates all components for each environment:
# main/development/kustomization.yaml
namespace: my-team
resources:
- ../../api-docs
- ../../certs
- ../../my-api/development
- ../../my-client/development
- ../../rabbitmq/development
- ../../redis/development
- ../../users/developmentHelmRelease Configuration
DIT uses Helm charts managed by FluxCD's Helm Controller. Applications use DIT's common Helm charts stored in the flux-system namespace.
Base Release
The base release.yaml defines the core application configuration:
# my-api/base/release.yaml
---
apiVersion: helm.toolkit.fluxcd.io/v2
kind: HelmRelease
metadata:
name: my-api
spec:
releaseName: my-api
interval: 1h
driftDetection:
mode: warn
chartRef:
kind: HelmChart
name: dit-common-api
namespace: flux-system
values:
replicas: 4
image:
repository: my-team/my-api
securityContext:
runAsUser: 1654
runAsGroup: 1654
resources:
limits:
memory: 750Mi
requests:
cpu: 50m
memory: 750Mi
configs:
MongoDB__DatabaseName: my-team-db
RabbitMQ__HostName: cluster.rabbitmq
RabbitMQ__ExchangeName: my-team
RabbitMQ__Port: 5672
RabbitMQ__VirtualHost: my-team
RemoteServices__UserApiUrl: http://users-api
infisical:
enabled: true
secretsScope:
secretsPath: /my-api
ciliumNetworkPolicy:
enabled: true
ingress:
traefik:
fromEndpoints:
- matchLabels:
app.kubernetes.io/instance: traefik-traefik
io.kubernetes.pod.namespace: traefik
toPorts:
- ports:
- port: "8080"
egress:
kube-dns:
toEndpoints:
- matchLabels:
k8s-app: kube-dns
io.kubernetes.pod.namespace: kube-system
toPorts:
- ports:
- port: "53"
rules:
dns:
- matchPattern: "*"
rabbitmq:
toEndpoints:
- matchLabels:
app.kubernetes.io/component: rabbitmq
app.kubernetes.io/name: cluster
io.kubernetes.pod.namespace: rabbitmq
toPorts:
- ports:
- port: "5672"Base Kustomization
# my-api/base/kustomization.yaml
---
resources:
- release.yamlEnvironment Overlay
Environment overlays patch the base release with environment-specific values:
# my-api/development/kustomization.yaml
---
resources:
- ../base
patches:
- path: release.yaml
- path: image.yaml# my-api/staging/release.yaml
---
apiVersion: helm.toolkit.fluxcd.io/v2
kind: HelmRelease
metadata:
name: my-api
spec:
values:
replicas: 2
configs:
ASPNETCORE_ENVIRONMENT: Staging
Sentry__Environment: staging
Storage__Endpoint: https://s3.dev.krd
CAS__URL: https://auth.dev.krd
infisical:
secretsScope:
envSlug: staging
sealedSecret:
token: AgCXZS4j... # Sealed secret for Infisical token
ciliumNetworkPolicy:
egress:
database:
toEndpoints:
- matchLabels:
app: my-team-mongodb-svc
toPorts:
- ports:
- port: "27017"Auto-Updated Image Tags
The image.yaml file is automatically updated by CI/CD pipelines:
# my-api/development/image.yaml
---
apiVersion: helm.toolkit.fluxcd.io/v2
kind: HelmRelease
metadata:
name: my-api
spec:
values:
###########################################################################################
# the lines below are automatically generated by the auto-deploy action. Do not edit manually.
###########################################################################################
# GITHUB_REPOSITORY: ditkrg/my-team-my-api
global:
image:
tag: dev-843632a
digest: sha256:570965b16c53e7fe6c48d50d8601a8cd2327143dba14412692a5b8fc2c119bf9
annotations:
GITHUB_REPO_URL: https://github.com/ditkrg/my-team-my-api
GITHUB_COMMIT_HASH: 843632abfd85fba907355af9f95755d0d40ce4b3Secrets Management with Infisical
DIT uses Infisical for secrets management, integrated via the Helm chart:
infisical:
enabled: true
secretsScope:
secretsPath: /my-api
envSlug: staging
sealedSecret:
token: AgCXZS4j... # Bitnami Sealed SecretThe Infisical token is stored as a Sealed Secret which is safely committed to Git.
Network Policies with Cilium
All applications must define CiliumNetworkPolicy rules for both ingress and egress traffic:
Ingress Rules
ciliumNetworkPolicy:
enabled: true
ingress:
traefik:
fromEndpoints:
- matchLabels:
app.kubernetes.io/instance: traefik-traefik
io.kubernetes.pod.namespace: traefik
toPorts:
- ports:
- port: "8080"Egress Rules
ciliumNetworkPolicy:
egress:
# DNS resolution
kube-dns:
toEndpoints:
- matchLabels:
k8s-app: kube-dns
io.kubernetes.pod.namespace: kube-system
toPorts:
- ports:
- port: "53"
rules:
dns:
- matchPattern: "*"
# Internal services
rabbitmq:
toEndpoints:
- matchLabels:
app.kubernetes.io/component: rabbitmq
io.kubernetes.pod.namespace: rabbitmq
toPorts:
- ports:
- port: "5672"
# External services (FQDN-based)
sentry:
toFQDNs:
- matchName: example.com
toPorts:
- ports:
- port: "443"DIT Common Helm Charts
DIT maintains shared Helm charts for common application patterns, including:
| Chart | Purpose |
|---|---|
dit-gateway | API gateways, middlewares and routes |
dit-common-api | Backend API services (.NET, Node, Go) |
dit-common-client | Frontend web applications |
These charts are stored in flux-system and referenced via chartRef.
Drift Detection
FluxCD monitors for configuration drift and can warn or auto-correct:
spec:
driftDetection:
mode: enabled # Options: warn, enabled, disabledRollback Procedures
Automatic Rollback
FluxCD performs automatic rollback if health checks fail.
Manual Rollback
To rollback manually:
- Update
image.yamlto a previous working tag:
global:
image:
tag: dev-abc1234 # Previous working version
digest: sha256:...- Commit and push. FluxCD will apply the rollback.
Alternatively, revert the GitOps PR that introduced the change.
Monitoring FluxCD
FluxCD Notifications
FluxCD is configured to send deployment notifications to a dedicated Slack channel for each project. This helps teams stay informed about rollout status, failures, and drift events in real time.
Notification examples include:
- Release applied: When a HelmRelease is updated
- Sync failure: When deployment fails or is rolled back
- Drift detected: When configuration drifts from the desired state in Git
Slack channel configuration is managed in the FluxCD notification controller. If you don't see FluxCD messages, ask the DevOps team to add you to your project's channel.
For more details on notification setup, see the Flux Notifications documentation.
Best Practices
1. Never Edit image.yaml Manually
The image.yaml file is auto-generated by CI/CD. Manual edits will be overwritten.
2. Use Base + Overlay Pattern
Keep shared configuration in base/, environment-specific in overlays.
3. Define Complete Network Policies
All applications must have both ingress and egress rules defined. Default-deny is enforced.
4. Pin Image Digests
Image digests ensure immutability:
global:
image:
tag: v1.2.3
digest: sha256:570965b16c53e7fe6c48d50d8601a8cd2327143dba14412692a5b8fc2c119bf95. Use Sealed Secrets for Sensitive Tokens
Infisical tokens and other secrets must be sealed before committing.
By using FluxCD for GitOps, DIT ensures that all deployments are traceable, reproducible, and follow a consistent approval workflow across all environments.
