Kubernetes · 3 min read

GitOps with Argo CD and Flux: when it helps and how to start

What GitOps actually changes about Kubernetes delivery, how Argo CD and Flux differ, and a low-risk way to begin.

By KubeCrew · Published

What GitOps changes

GitOps means the desired state of your cluster lives in Git, and software running in the cluster continuously makes reality match it. Instead of a pipeline pushing changes into the cluster with kubectl, a controller inside the cluster pulls from the repository and reconciles.

That small reversal has practical effects. Every change is a commit with an author, a review, and a timestamp. Rolling back is a revert. And because the controller keeps comparing the cluster to Git, manual changes made outside the process are detected, and optionally undone.

Why teams adopt it

  • An audit trail for free: the history of the cluster is the history of the repository.
  • Simple rollback, because the previous known-good state is already in Git.
  • Drift detection and self-healing, so hand-edited resources do not silently diverge.
  • Fewer credentials in CI. The pipeline needs to update a repository, not hold administrator access to every cluster.

Argo CD and Flux in brief

Argo CD and Flux are the two widely used GitOps controllers, and both are graduated projects in the Cloud Native Computing Foundation. They solve the same core problem with different shapes.

  • Argo CD centers on an Application resource and ships with a web UI that shows sync status and the resource tree. It handles multiple clusters well and has ApplicationSets for generating many applications from a template.
  • Flux is a set of focused controllers (source, Kustomize, Helm, notifications, image automation) configured with Kubernetes resources and driven mostly from the command line and Git.

Choosing between them

There is rarely a wrong answer. Teams that want a visual overview for developers and operators often prefer Argo CD. Teams that prefer a lighter, composable, CLI-first toolkit often prefer Flux. Pick one, standardize on it, and put effort into repository structure instead, which matters more than the controller.

Structure the repository on purpose

Keep application source code and environment configuration in separate repositories, or at least separate paths, so that a config change does not require a build and a code change does not accidentally change production. A common layout uses a shared base and per-environment overlays with Kustomize, and promotes a change from staging to production through a pull request.

An Argo CD Application with automated sync
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: web
  namespace: argocd
spec:
  project: default
  source:
    repoURL: https://github.com/example/platform-config.git
    targetRevision: main
    path: apps/web/overlays/production
  destination:
    server: https://kubernetes.default.svc
    namespace: web
  syncPolicy:
    automated:
      prune: true
      selfHeal: true

Handle secrets without committing them

Git is not a place for plain-text secrets. Use an approach that keeps the repository safe to read: encrypt secrets in the repository with a tool such as Sealed Secrets or SOPS, or store them in an external secrets manager and let an operator sync them into the cluster.

Common pitfalls

  • Automated pruning deletes resources that are removed from Git. Enable it deliberately, and start with it off for critical namespaces.
  • Fields managed by other controllers, such as replica counts controlled by an autoscaler, can fight the reconciler unless you configure them to be ignored.
  • Resource ordering matters. Custom resource definitions must exist before the resources that use them, so use the controller's ordering features.
  • Helm values that change outside Git create exactly the drift GitOps is meant to remove. Keep values in the repository.

How to start with low risk

Pick one non-critical application in one namespace. Install the controller, point it at a repository, and begin with manual sync so you can see what it would change. Once the diff is boring, turn on automated sync, then add an alert for applications that stay out of sync. Expand one workload at a time, and leave anything fragile for later.

Next step

Bring us the part that is harder than it should be.

We will help you find the smallest useful next move.

Start a conversation