GitOps, the practice of managing infrastructure and applications through Git repositories, has exploded in popularity. At its core, GitOps aims to bring the benefits of version control, collaboration, and declarative configuration to operations. Two of the most prominent tools in this space are Flux and Argo CD. While they share the same fundamental goal, their approaches and feature sets differ significantly, making the choice between them a crucial decision for your GitOps strategy.
Let’s see them in action. Imagine you have a Kubernetes cluster and want to deploy an application defined in a Git repository.
Flux (v2) - The "Push" Model (or rather, pull with a push-like feel)
Flux v2, the current generation, operates on a declarative, Git-as-the-source-of-truth model. It primarily pulls changes from Git into your cluster, but its controller-based architecture can feel more integrated.
Here’s a simplified Git repository structure for Flux:
git-repo/
├── apps/
│ └── my-app.yaml
└── infrastructure/
└── cluster-settings.yaml
And my-app.yaml might look like this:
apiVersion: kustomize.toolkit.fluxcd.io/v1
kind: Kustomization
metadata:
name: my-app
namespace: flux-system
spec:
interval: 10m
path: ./apps/my-app
prune: true
sourceRef:
kind: GitRepository
name: my-git-repo
validation: client
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-app
namespace: default
spec:
replicas: 2
selector:
matchLabels:
app: my-app
template:
metadata:
labels:
app: my-app
spec:
containers:
- name: my-app
image: nginx:1.23.0
You’d then configure Flux to watch this Git repository. Flux controllers, running within your cluster, continuously reconcile the desired state defined in Git with the actual state of your cluster. If you change nginx:1.23.0 to nginx:1.24.0 in my-app.yaml and commit, Flux will detect the change and update your deployment.
Argo CD - The "Pull" Model with a UI-centric approach
Argo CD also follows the GitOps principle of Git as the source of truth. It maintains a clear separation between Git and your Kubernetes cluster, with Argo CD acting as the bridge.
Here’s a typical Argo CD setup:
git-repo/
├── app/
│ └── my-app-manifests/
│ └── deployment.yaml
│ └── service.yaml
└── argocd-apps/
└── my-app.yaml # Argo CD Application resource
And my-app.yaml (Argo CD Application resource):
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: my-app
namespace: argocd
spec:
project: default
source:
repoURL: <your-git-repo-url>
targetRevision: HEAD
path: app/my-app-manifests
destination:
server: https://kubernetes.default.svc
namespace: default
syncPolicy:
automated:
prune: true
selfHeal: true
Argo CD has a dedicated controller that watches your Git repository and compares its contents to the state in your Kubernetes cluster. It offers a rich UI for visualizing the sync status, application health, and resource hierarchy. When you update your deployment.yaml in Git, Argo CD detects the drift and allows you to sync the changes.
The Mental Model: Reconcilers and Declarative State
Both Flux and Argo CD are reconcilers. They continuously compare the desired state (what’s in Git) with the actual state (what’s running in Kubernetes) and take action to make the actual state match the desired state.
-
Flux: It’s a suite of controllers (Kustomize Controller, Helm Controller, Notification Controller, etc.) that run within your cluster. You define "sources" (like Git repositories or Helm repositories) and "kustomizations" or "helm releases" that tell Flux what to deploy from where. It feels more like an integrated part of your cluster’s control plane.
-
Argo CD: It’s a more monolithic application with its own dedicated controller. You define "Applications" which are Argo CD’s way of specifying what to deploy from Git to a specific cluster and namespace. Argo CD is often deployed with a dedicated UI, making it very visible and interactive.
The core problem they solve is operational consistency and automation. Instead of manually running kubectl apply or helm upgrade, you declare your desired state in Git. Your Git history becomes your audit log, and your Git workflow (PRs, reviews) becomes your deployment pipeline.
The Levers You Control:
- Source Repository: The Git repository containing your Kubernetes manifests (YAML, Helm charts, Kustomize overlays).
- Sync Strategy: How and when changes are applied. Manual syncs, automated syncs, sync on Git commit, or scheduled syncs.
- Drift Detection & Auto-Correction: How the tool handles discrepancies between Git and the cluster.
- Target Cluster/Namespace: Where the applications are deployed.
- Application Health Checks: How the tool determines if an application is truly "healthy" after deployment.
- Notifications: How you’re alerted to sync failures or successes.
The Counterintuitive Detail: Health Status Isn’t Always Truth
A common misconception is that when Flux or Argo CD reports an application as "Healthy" or "Synced," it means the application is functioning perfectly. This is not always true. The "health" status is typically determined by Kubernetes readiness and deployment conditions (e.g., pods are running and ready). An application might have all its pods ready but still be functionally broken due to a misconfiguration in its application logic, an issue with an external dependency, or a bug in the application code itself. Relying solely on the GitOps tool’s health status for application correctness is a mistake; you still need robust application-level monitoring and testing.
The next hurdle you’ll face is managing complex application dependencies and multi-cluster deployments.