Skip to content
Français
Account: not signed in, sync available My learning
Select theme
Français
Lire en français

GitOps: principles, ArgoCD vs Flux and implementation

By updated

Improve this page

GitOps turns Git into the declarative source of truth for the desired state of your systems. In practice: instead of logging into a server to change a configuration or run a deployment by hand, you change a file in a Git repository. A tool called an operator (or controller) watches this repository continuously and applies the changes to your environments automatically.

Every change goes through a pull request, which allows a review before it is applied. The Git history keeps track of who changed what, when and why. When something goes wrong, rolling back means running git revert.

This lesson covers the fundamentals: the four principles, the pull strategy versus the push strategy, the choice between ArgoCD and Flux, a step-by-step implementation, then the success criteria and the pitfalls to avoid.

What you will learn

  • The four GitOps principles and why each one matters
  • The difference between the pull strategy (recommended) and the push strategy
  • How to structure your repositories: app-repo and config-repo
  • How to choose between ArgoCD and Flux for your context
  • The criteria to validate that your implementation is solid
  • The common pitfalls and how to avoid them

Prerequisites

This lesson assumes you know what a commit, a branch and a pull request are in Git, and that you have already handled a Kubernetes manifest (a YAML file that describes a Deployment or a Service). It also builds on the idea of Infrastructure as Code, presented in the Infrastructure as Code guide: describing infrastructure in versioned files rather than configuring it by hand.

Why GitOps: the problem in the field

Before adopting GitOps, most teams deploy their applications imperatively: someone connects to the cluster, runs kubectl apply, and hopes everything works. This approach raises traceability and security problems you may recognise if you already manage Kubernetes environments.

Teams without GitOps often run into these symptoms:

  • Manual deployments: kubectl apply run directly, without traceability
  • Undetected drift: the actual state diverges from the declared state without anyone knowing
  • No simple rollback: rolling back means finding the right configuration again
  • Overly broad access: developers have admin rights on the cluster to deploy
  • Impossible audit: nobody knows who changed what, or when
  • Inconsistent environments: dev, staging and prod drift apart

What are the four GitOps principles?

GitOps rests on four principles defined by the OpenGitOps project, which came out of the CNCF (Cloud Native Computing Foundation) GitOps working group and formalised them in its version 1.0.0. Together, they guarantee a reliable, traceable and reproducible deployment, whatever the tool that applies them.

The GitOps loop: a pull request reviewed and validated by kubeconform becomes a commit on main, the declared state; the operator, ArgoCD or Flux, continuously compares the actual state of the cluster with this declared state and fixes any drift, including the drift created by a manual change.no: fixes the driftyes: nothing to docreates driftwatched continuouslyPull requestreview + kubeconformCommit on maindeclared stateOperatorArgoCD or FluxActual state =declared state?Clusteractual stateManualchange
Source · SVG
Esc to close, + and − to zoom, scroll to move around. 100 %

The diagram sums up the loop these principles describe: the declared state is born from a merged pull request, the operator keeps comparing it with the cluster, and a manual change is just one more drift to fix.

1. Declarative

The desired state is described in declarative files (YAML, HCL for HashiCorp Configuration Language, JSON): the file says what must exist, not the sequence of commands to get there. It is the opposite of an imperative script, which describes a sequence of actions.

Why: a declarative file can be versioned, compared, audited. An imperative script depends on the initial state of the system when it runs, which makes the result unpredictable if that starting point differs.

2. Versioned and immutable

Every change goes through Git: commit, pull request, review, merge. Each applied state matches a precise, immutable commit: it cannot be changed afterwards without leaving a trace.

Why: full history, rollback with git revert, native audit, collaboration through pull requests.

3. Pulled automatically

A software agent watches the repository and pulls the changes without human intervention, rather than receiving a deployment order from an external system.

Why: nothing forgotten, no handling error, a reproducible deployment at every merge. No cluster credential needs to leave the agent's perimeter.

4. Continuously reconciled

The agent continuously compares the actual state with the declared state and fixes drift automatically, without waiting for a human to notice.

Why: if someone changes the cluster by hand, the agent restores the compliant state within seconds or minutes depending on its sync interval. This self-healing is the main operational benefit of GitOps.

Pull or push: who triggers the deployment?

There are two main approaches to applying Git changes to your environments. The difference lies in who initiates the deployment, and this choice directly shapes your attack surface and the access to secure. Do not confuse this choice with deployment strategies such as canary or blue-green: those describe how the new version replaces the old one, pull and push describe who pushes the configuration.

Pull or push. With pull, the GitOps agent installed in the cluster watches the configuration repository, pulls the changes and reconciles the Kubernetes resources. With push, the CI pipeline, which holds admin access to the cluster, applies the changes with kubectl apply.Push strategytriggerskubectl applyGit repositoryCI pipelinewith admin accessResourcesPull strategy (recommended)pulled by the agentapplies and reconcilesGit repositoryconfig-repoGitOps agentin the clusterKubernetesresources
Source · SVG
Esc to close, + and − to zoom, scroll to move around. 100 %

With the pull strategy, an agent installed in the cluster watches Git and applies the changes itself. This reversal changes the security of the setup: cluster access never leaves the cluster.

Its advantages:

  • the CI pipeline needs no access to the cluster;
  • continuous reconciliation fixes drift without intervention;
  • no cluster credential is exposed in the CI.

The reference tools are ArgoCD, Flux and Fleet (Rancher).

Push strategy

With the push strategy, the CI pipeline pushes the changes to the cluster, for example with kubectl apply or helm upgrade at the end of a job. It is the historical CI/CD model.

Its advantages:

  • it is simpler to set up at first;
  • it works outside Kubernetes (VMs, cloud resources).

Its drawbacks:

  • the CI holds privileged access to the cluster, hence a high-value secret;
  • there is no continuous reconciliation: drift is neither detected nor fixed.

ArgoCD or Flux: which operator to choose?

For Kubernetes, the two reference GitOps operators are ArgoCD and Flux. Both projects reached the Graduated level at the CNCF in late 2022 (Flux on 30 November, ArgoCD on 6 December), the foundation's highest maturity level: open governance, audited security, wide production adoption. Both implement the four principles and provide solid continuous reconciliation.

The table below compares the two tools on the criteria that drive the day-to-day choice. Read it column by column: neither is better in absolute terms, each carries a different philosophy.

CriterionArgoCDFlux
User interfaceBuilt-in web interfaceCLI and API; web interfaces offered by third-party projects
ArchitectureCentral server with its componentsSet of modular controllers (GitOps Toolkit)
Multi-clusterOne instance can drive several clustersOne Flux per cluster, or a central cluster driving the others
ApproachOpinionated, centred on the Application objectClose to the native Kubernetes APIs (one CRD per function)
NotificationsBuilt inNotification controller included in the installation
Getting startedAccessible thanks to the interfaceMore technical, everything goes through manifests

How to choose:

  • you are new to GitOps and want immediate visibility: ArgoCD;
  • you prefer a 100 % declarative, controller-oriented approach: Flux;
  • you manage many teams with distinct scopes: both fit, ArgoCD integrates its RBAC and its AppProject more tightly. It is also the natural ground of platform engineering, which builds self-service internal platforms on top of these building blocks.

Both projects are also strengthening supply chain security. ArgoCD can for example verify the GPG signature of commits before syncing, and encrypt with TLS the exchanges between its internal components: two protections against the injection of unauthorised manifests. These features change from one major version to the next: read the changelog of the installed version before going to production.

For GitOps outside Kubernetes (Terraform, Ansible), tools such as Atlantis, the Pulumi Kubernetes Operator or Spacelift apply the same pull-request review logic.

Step-by-step implementation

The five steps below follow the order of a first adoption: you structure the repositories, install the operator, set the workflow, then handle secrets and environments.

Step 1: structure the repositories

Separate the application code and the deployment manifests into two distinct repositories. The first produces an image; the second describes where and how it runs:

app-repo/ # Source code + CI
src/
Dockerfile
.github/workflows/build.yml
config-repo/ # GitOps manifests
base/
kustomization.yaml
deployment.yaml
service.yaml
overlays/
dev/
staging/
prod/

Why two repositories: the application code changes often (feature commits) while deployment configurations follow another rhythm (promotions, releases). Mixing both adds noise to the history and complicates auditing.

Step 2: install the operator

The GitOps operator (ArgoCD or Flux) is installed in the cluster it must watch: it is the one that will then hold the access to the Git repository and to the local Kubernetes API, never the CI. The installation creates a set of controllers that run continuously and must be included in your monitoring like your other critical workloads.

With ArgoCD, through Helm (the Kubernetes package manager), pinning the chart version so that two installations give the same result:

Terminal window
helm repo add argo https://argoproj.github.io/argo-helm
helm install argocd argo/argo-cd --version 10.9.6 \
--namespace argocd --create-namespace

Chart 10.9.6 installs Argo CD v3.5.3. Check that the pods start with kubectl get pods -n argocd: they must all reach the Running state before you configure a first application.

With Flux, through its CLI and the flux bootstrap command (a GitHub token must be available in the GITHUB_TOKEN variable):

Terminal window
flux bootstrap github \
--owner=my-org \
--repository=config-repo \
--branch=main \
--path=clusters/my-cluster

This command creates the configuration repository if it does not exist, commits the manifests of the Flux controllers into it, then deploys them: Flux thus manages itself through GitOps. flux check then confirms that each controller is operational.

Step 3: define the contribution workflow

Once the operator is in place, the contribution workflow describes the path each change follows, from editing a manifest to its application on the cluster. Formalising these steps prevents the informal deployments that bypass review:

  1. the developer changes a manifest in a short-lived branch;
  2. they open a pull request, reviewed and validated automatically by kubeconform (a validator that checks manifests against the Kubernetes schemas);
  3. the pull request is merged into main;
  4. the operator detects the new commit and reconciles the cluster;
  5. a notification reports success or failure.

Step 4: manage secrets

Secrets must never be in plain text in Git. It is the most sensitive point of a GitOps implementation, because a Git repository is meant to be cloned, forked, browsed by several contributors: a plain-text secret survives in the history even after the file is deleted. Three approaches dominate:

ToolPrinciple
Sealed SecretsAsymmetric encryption: the encrypted secret is stored in Git, then decrypted in the cluster by a controller that alone holds the private key
SOPSEncryption of the values of a YAML file with an age or PGP key, or a key managed by a cloud KMS (AWS KMS, GCP KMS, Azure Key Vault)
External SecretsSynchronisation from an external vault (Vault, AWS Secrets Manager): Git only contains the reference, not the value

The secrets management guide details these tools and the criteria to choose between them.

Step 5: configure the environments

Use Kustomize (a tool built into kubectl that applies patches to base manifests without duplicating them) or Helm to manage the differences between environments. Here, the production overlay reuses the base and only changes the number of replicas:

overlays/prod/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- ../../base
patches:
- path: patch-replicas.yaml

The patch only contains what differs from the base, plus what is needed to identify the target resource (kind and metadata.name):

overlays/prod/patch-replicas.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: catalogue
spec:
replicas: 3

kubectl kustomize overlays/prod displays the result: the base catalogue Deployment appears with replicas: 3. The operator points to the overlay of each environment. This approach avoids maintaining near-identical copies of the manifests: only the difference is versioned, which makes every gap explicit and reviewable in a pull request.

Success criteria

Your GitOps implementation is solid when you can tick each of the following points without any permanent exception. Use this list as an audit grid before considering a migration finished.

  • No deployment is done by manual kubectl apply outside incidents
  • Every production change has an associated, merged pull request
  • Rollback is done with git revert, not by acting directly on the cluster
  • Drift is detected and fixed automatically
  • Secrets are never in plain text in the Git repository
  • Developers have no admin access to the production cluster
  • The Git history answers "who changed what, when"
  • The environments (dev, staging, prod) are managed from the same configuration repository

Concrete scenarios

The two scenarios below show how these steps fit together in real situations: a migration from manual deployments, then putting environments that have drifted back in order.

Scenario 1: progressive migration to GitOps

Context: a team develops about ten microservices on Kubernetes. Deployments are done with kubectl apply from workstations. Incidents occur because of inconsistent configurations between staging and production.

Possible approach:

  1. install ArgoCD on the cluster;
  2. migrate two pilot services to validate the workflow;
  3. create the config-repo with the base/overlays structure;
  4. train the team on the pull request and ArgoCD sync workflow;
  5. progressively remove direct kubectl access on the production clusters.

What it changes: every deployment is traced in Git, the environments stay in sync, and rollback happens without knowing the exact command applied during the incident.

Scenario 2: multi-environment management

Context: three environments (dev, staging, prod) whose configurations drift. Production contains "temporary" settings that were never documented.

Possible approach:

  1. audit the actual configurations against the declared ones, environment by environment;
  2. create a single config-repo with one Kustomize overlay per environment;
  3. explicit promotion through pull requests, from dev to staging then to prod;
  4. ArgoCD alerts configured for any detected drift.

What it changes: the differences between environments become explicit, versioned in Git, and any deviation is visible then fixed automatically.

Common pitfalls

Some pitfalls come back systematically during a first GitOps adoption, often because they only show up once the system is in production. Knowing them in advance avoids discovering them during an incident.

PitfallImpactFix
Plain-text secrets in GitCredential leak, non-complianceUse Sealed Secrets, SOPS or External Secrets
A single app + config repositoryMixed lifecycles, noise in the historySplit into two repositories
Ignoring driftThe actual state diverges without alertConfigure the operator's alerts
Too much customisation per environmentComplex maintenance, hard mergesKeep overlays minimal, only patch what differs
No validation before mergeInvalid manifests merged and appliedAdd kubeconform to the CI (kubeval is no longer maintained)
kubectl access kept in prodSilent bypass of the GitOps workflowRemove the access after migration
No tested rollback strategyPanic during an incidentDocument and test git revert before you need it
Forgetting the CRDsThe operator fails on unknown resourcesVersion the CRDs in the config-repo with the other manifests

Key points

  • Git is the declarative source of truth for the scope managed by the operator, not for the whole system in the absolute sense.
  • Four OpenGitOps principles: declarative, versioned and immutable, pulled automatically, continuously reconciled.
  • Pull strategy: the operator pulls the changes from Git, the CI does not touch the cluster.
  • ArgoCD and Flux are both CNCF Graduated since late 2022, a maturity signal for a production choice.
  • Two repositories: app-repo (code) and config-repo (manifests) have different lifecycles.
  • Continuous reconciliation: drift is detected and fixed automatically, self-healing is the main operational benefit.
  • Separate secrets: never in plain text in Git, always encrypted or externalised.
  • Rollback = git revert: no manual handling, one commit is enough.

Knowledge check

Check that you have the essentials of this guide. The questions only cover what has just been explained here.

Knowledge check

Check what you have learned with this interactive quiz

6 questions
6 min
70% to pass

How it works

  • The timer starts when you click Start
  • Multiple choice, true/false and short answer questions
  • You can move between questions
  • Detailed results are shown at the end

Starts the quiz and the timer

FAQ: frequently asked questions

The questions below cover the points teams hesitate on the most when they adopt GitOps: the difference with classic CI/CD, the choice of operator and secrets.

Is this project useful to you?

The guides, courses, quizzes and labs stay free. If you use them regularly, you can contribute to their upkeep and development.

Become a supporting member (new tab) One-time support (new tab) Learn more

Follow the project on LinkedIn