Skip to content

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

  1. Declarative Configuration – The entire system is described declaratively in Git
  2. Versioned and Immutable – The desired state is versioned in Git, providing a complete audit trail
  3. Pulled Automatically – Approved changes are automatically applied to the cluster
  4. 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.md

Main Environment Aggregator

The main/ directory aggregates all components for each environment:

yaml
# main/development/kustomization.yaml
namespace: my-team

resources:
  - ../../api-docs
  - ../../certs
  - ../../my-api/development
  - ../../my-client/development
  - ../../rabbitmq/development
  - ../../redis/development
  - ../../users/development

HelmRelease 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:

yaml
# 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

yaml
# my-api/base/kustomization.yaml
---
resources:
  - release.yaml

Environment Overlay

Environment overlays patch the base release with environment-specific values:

yaml
# my-api/development/kustomization.yaml
---
resources:
  - ../base
patches:
  - path: release.yaml
  - path: image.yaml
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:

yaml
# 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: 843632abfd85fba907355af9f95755d0d40ce4b3

Secrets Management with Infisical

DIT uses Infisical for secrets management, integrated via the Helm chart:

yaml
infisical:
  enabled: true
  secretsScope:
    secretsPath: /my-api
    envSlug: staging
  sealedSecret:
    token: AgCXZS4j...  # Bitnami Sealed Secret

The 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

yaml
ciliumNetworkPolicy:
  enabled: true
  ingress:
    traefik:
      fromEndpoints:
        - matchLabels:
            app.kubernetes.io/instance: traefik-traefik
            io.kubernetes.pod.namespace: traefik
      toPorts:
        - ports:
            - port: "8080"

Egress Rules

yaml
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:

ChartPurpose
dit-gatewayAPI gateways, middlewares and routes
dit-common-apiBackend API services (.NET, Node, Go)
dit-common-clientFrontend 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:

yaml
spec:
  driftDetection:
    mode: enabled  # Options: warn, enabled, disabled

Rollback Procedures

Automatic Rollback

FluxCD performs automatic rollback if health checks fail.

Manual Rollback

To rollback manually:

  1. Update image.yaml to a previous working tag:
yaml
global:
  image:
    tag: dev-abc1234  # Previous working version
    digest: sha256:...
  1. 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:

yaml
global:
  image:
    tag: v1.2.3
    digest: sha256:570965b16c53e7fe6c48d50d8601a8cd2327143dba14412692a5b8fc2c119bf9

5. 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.