GitOps delivery with Argo CD or Flux on Kubernetes

GitOps workflows with Argo CD and Flux: consistency and compliance in Kubernetes

12 min read

Git as the contract of record stops silent drift across clusters. Compare Argo CD and Flux patterns—from install snippets to policy hooks—and adopt guardrails for secrets, observability, and audit-ready rollouts.

Why Kubernetes deployments still drift without GitOps

Modern estates must keep declared desired state aligned across clusters while auditors ask for evidence that every change is traceable. Imperative kubectl-first habits amplify configuration drift, trap knowledge in individuals, and weaken rollback stories. Teams repeatedly hit four gaps: clusters diverging from Git truth, policy and regulator evidence scattered across tickets, self-service without guardrails, and incomplete deployment history when incidents strike.

What GitOps changes with Argo CD or Flux

GitOps anchors declarative manifests in Git as the contract of record. Either Argo CD or Flux continuously reconciles the API server toward that contract so automation replaces manual convergence. You gain continuous sync, versioned rollouts, drift detection with optional self-heal, RBAC tied to Git changes, and immutable history for audits. To land the pattern, standardize repository layout (for example environments/prod and environments/staging), install one operator in-cluster, model applications with Helm, Kustomize, or plain YAML, wire policy engines such as OPA when required, and expose sync health through dashboards and metrics.

Example: Argo CD from install to Application

Argo CD watches Git branches or tags, materializes manifests, then compares live cluster state to desired state. Create the argocd namespace and apply the upstream install manifest. Use port-forward temporarily for the UI while you harden ingress and TLS for production traffic. Model each deployable unit as an Application CR so sync policies, automated pruning, and self-heal stay declarative. For enterprise authentication, front Argo CD with Dex or LDAP so identities align with both Git access controls and in-cluster RBAC.

Bash · namespace and Argo CD install
# Create namespace
kubectl create namespace argocd

# Install Argo CD
kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml
Bash · UI port-forward and initial admin password
# Port-forward to access the UI locally
kubectl port-forward svc/argocd-server -n argocd 8080:443

# Get initial admin password
kubectl -n argocd get secret argocd-initial-admin-secret -o jsonpath="{.data.password}" | base64 -d
YAML · Argo CD Application
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: guestbook
  namespace: argocd
spec:
  project: default
  source:
    repoURL: https://github.com/argoproj/argocd-example-apps.git
    targetRevision: HEAD
    path: guestbook
  destination:
    server: https://kubernetes.default.svc
    namespace: guestbook
  syncPolicy:
    automated:
      prune: true
      selfHeal: true
    syncOptions:
    - CreateNamespace=true
Bash · apply Application manifest
kubectl apply -f application.yaml
YAML · argocd-cm Dex/LDAP snippet
# argocd-cm ConfigMap snippet
data:
  url: https://argocd.example.com
  dex.config: |
    connectors:
    - type: ldap
      id: ldap
      name: LDAP
      config:
        host: ldap.example.com
        port: 389
        insecureNoSSL: true
        baseDN: ou=users,dc=example,dc=com
        username: cn=admin,dc=example,dc=com
        password: secret
        userSearch:
          filter: "(mail=%s)"

Example: Flux bootstrap, Kustomization, and HelmRelease

Flux splits responsibilities across controllers for sources, Kustomize or Helm reconciliation, and notifications. Install the Flux CLI locally, then bootstrap GitHub so the cluster receives credentials scoped to the repository path you intend to reconcile. A cluster-level Kustomization binds a directory in the cloned repo to continuous applies. HelmRelease objects pin chart versions while values overlays remain in Git. Extend the same pattern to policy bundles shipped as OCI artifacts when auditors expect policy-as-code next to workloads.

Bash · Flux CLI install and GitHub bootstrap
# Install Flux CLI
curl -s https://fluxcd.io/install.sh | sudo bash

# Bootstrap Flux on a GitHub repository
flux bootstrap github \
  --owner=<GITHUB_USERNAME> \
  --repository=<REPO_NAME> \
  --branch=main \
  --path=./clusters/my-cluster \
  --personal
YAML · Flux Kustomization
# ./clusters/my-cluster/kustomization.yaml
apiVersion: kustomize.toolkit.fluxcd.io/v1
kind: Kustomization
metadata:
  name: cluster-config
  namespace: flux-system
spec:
  interval: 1m0s
  sourceRef:
    kind: GitRepository
    name: flux-system
  path: ./cluster
  prune: true
  validation: client
  healthChecks:
    - apiVersion: v1
      kind: Pod
      name: coredns
      namespace: kube-system
YAML · Flux HelmRelease
# ./cluster/apps/helmrelease.yaml
apiVersion: helm.toolkit.fluxcd.io/v2
kind: HelmRelease
metadata:
  name: podinfo
  namespace: default
spec:
  interval: 5m
  chart:
    spec:
      chart: podinfo
      sourceRef:
        kind: HelmRepository
        name: podinfo-chart
        namespace: flux-system
      version: 6.x.x
  install:
    remediation:
      retries: 3
  upgrade:
    remediation:
      retries: 3
  values:
    replicaCount: 2
YAML · Flux policies Kustomization
# ./cluster/policies/kustomization.yaml
apiVersion: kustomize.toolkit.fluxcd.io/v1
kind: Kustomization
metadata:
  name: policies
  namespace: flux-system
spec:
  interval: 30s
  sourceRef:
    kind: GitRepository
    name: flux-system
  path: ./policies
  prune: true
  validation: client

Repository, security, observability, and compliance practices

Separate platform-owned cluster add-ons from product microservices using multiple repositories or clear mono-repo directories. Promote changes progressively from development through staging to production with branches, tags, or directory gates instead of surprise mutations in production clusters. Enforce least privilege for Git tokens, service accounts, and controllers; avoid long-lived secrets in plain Git—use external stores with CSI drivers or sealed patterns, and enable commit signing when your security baseline demands non-repudiation. Export Prometheus metrics from controllers, alert on sync failures and health regressions, centralize logs for forensics, back up Git repositories and etcd snapshots where recovery objectives require it, and pair GitOps with admission controllers such as Gatekeeper or Kyverno so policy violations surface before workloads run.

Conclusion: pilot, measure reconcile health, then scale

Whether you choose Argo CD or Flux, the operational win is the same: reproducible rollouts, transparent drift handling, and an audit trail anchored in Git. Start with a pilot workload class, lock sync and RBAC defaults, then expand to additional clusters once metrics show stable reconcile loops and teams trust the workflow.

GitOps still needs disciplined secret handling between Git and the cluster, which we cover in secrets management for DevOps and CI/CD.

Controller sync health only helps when telemetry is actionable, so pair reconcilers with an observability baseline for small platform teams.