Back to blog

GitOps in Practice: Argo CD, Flux, and Declarative Delivery

May 29, 2026 12 min read Kubexer Team
GitOpsArgo CDFluxCD

GitOps has become one of those terms that means everything and nothing. Stripped of the hype, it is a precise idea: the desired state of your system lives in Git, and an in-cluster controller continuously reconciles the running cluster to match it. Not "we deploy from a pipeline." The key word is continuously — a controller is always watching, always correcting drift. This post covers what that actually buys you, and how the two dominant tools, Argo CD and Flux, implement it.

The four principles

  1. Declarative. The whole system is described declaratively — manifests, Helm charts, Kustomize overlays — not imperative scripts.
  2. Versioned and immutable. That desired state is stored in Git, giving you history, review, and a single source of truth.
  3. Pulled automatically. An agent inside the cluster pulls approved changes — you do not push kubectl apply from a laptop or a CI runner with cluster credentials.
  4. Continuously reconciled. The agent constantly compares desired vs actual and converges them, healing manual drift.

Why the reconciliation loop matters

Traditional CI/CD pushes: a pipeline runs kubectl apply or helm upgrade and then forgets. If someone later edits a Deployment by hand, the cluster silently diverges from what is in Git, and nobody notices until an incident. GitOps inverts this. The controller treats Git as the truth and the cluster as something to be corrected toward it. Hand-edit a replica count, and a self-healing GitOps controller will put it back. Your cluster state stops being a mystery because Git always describes it.

The security benefit is just as large: cluster credentials never leave the cluster. CI builds an image and writes a manifest change to Git; it never needs kube-admin access. The blast radius of a leaked CI token shrinks dramatically.

Argo CD: the application-centric model

Argo CD organizes everything around the Application — a CRD that points at a Git repo path and a destination cluster/namespace:

apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: api
  namespace: argocd
spec:
  project: default
  source:
    repoURL: https://github.com/acme/manifests
    path: apps/api/overlays/prod
    targetRevision: main
  destination:
    server: https://kubernetes.default.svc
    namespace: api
  syncPolicy:
    automated:
      prune: true
      selfHeal: true

Argo CD shines on its UI and visualization. It renders the full resource tree of an Application, shows sync status (in-sync / out-of-sync) and health per object, and makes a diff between Git and live state a click away. selfHeal reverts manual drift; prune deletes resources removed from Git. For teams that value seeing their deployments, Argo CD is hard to beat. It also has ApplicationSet for templating many Applications across clusters or environments.

Flux: the composable, controller-native model

Flux is a set of focused controllers rather than one app. You declare sources (a Git repo, a Helm repo, an OCI registry) and reconcilers (a Kustomization or a HelmRelease) that act on them:

apiVersion: source.toolkit.fluxcd.io/v1
kind: GitRepository
metadata:
  name: manifests
  namespace: flux-system
spec:
  interval: 1m
  url: https://github.com/acme/manifests
  ref:
    branch: main
---
apiVersion: kustomize.toolkit.fluxcd.io/v1
kind: Kustomization
metadata:
  name: api
  namespace: flux-system
spec:
  interval: 10m
  path: ./apps/api/overlays/prod
  prune: true
  sourceRef:
    kind: GitRepository
    name: manifests

Flux feels more Kubernetes-native and composable. It has no mandatory UI, integrates cleanly with Kustomize and Helm, and its image-automation controllers can watch a registry and write image bumps back to Git for you. Teams that prefer a CLI-and-CRD workflow, or want GitOps as a set of building blocks, tend to favor Flux.

Argo CD vs Flux: how to choose

  • Want a strong UI and an application-centric mental model? Argo CD.
  • Want minimal, composable controllers and a GitOps-as-plumbing approach? Flux.
  • Need multi-cluster app templating at scale? Argo CD's ApplicationSet is mature; Flux does it too with more assembly.
  • Want built-in image-update automation? Flux's image controllers are first-class; Argo CD typically pairs with Argo Image Updater.

Both are CNCF graduated projects, both are production-proven, and the choice is rarely wrong — many organizations are happy with either. Some even run both in different teams.

Operational gotchas

  • HPA vs selfHeal. If a GitOps controller manages a Deployment's replicas and an HPA also adjusts it, they fight. Omit replicas from the Git manifest so the controller stops reconciling that field.
  • Pruning surprises. prune: true deletes anything removed from Git. A bad refactor can delete live resources — review diffs before merging.
  • CRD ordering. A resource can fail to apply because its CRD is not installed yet. Use sync waves (Argo CD) or dependsOn (Flux) to order things.
  • Drift you cannot see. A controller can be reconciling happily while a sub-resource is degraded. You still need to inspect the managed-resource tree, not just the top-level sync status.

Seeing your GitOps state

The recurring operational question with GitOps is "what does this Application or Kustomization actually own, and is all of it healthy?" The answer lives in each resource's status — the tree of objects it manages. Being able to inspect that tree, check sync and health at a glance, and trigger a sync, refresh, reconcile, or suspend without dropping to argocd or flux CLIs makes day-two operations far calmer. Kubexer surfaces Argo CD and Flux resources as first-class, typed views — with their managed-resource trees and those actions built in — when it detects either tool in a cluster, so GitOps fits into the same cockpit as the rest of your resources.

Wrapping up

GitOps is a control loop, not a deployment script: Git holds desired state, a controller continuously converges the cluster to it, and credentials stay in-cluster. Argo CD leads with visualization and an app-centric model; Flux leads with composable, native controllers. Pick the one whose mental model fits your team, keep replicas out of Git when an HPA is in play, review your prune diffs, and let the reconciler do the boring work of keeping reality in sync with intent.