GitOps Fundamentals
itDevOps and software delivery
GitOps Fundamentals
GitOps is a way of operating infrastructure and applications where the entire desired state of a system is described declaratively, stored in version control, and kept in sync by software agents that continuously compare what's actually running against what Git says should be running. The name is a compression of the idea: Git becomes the single source of truth for "what should exist," and an automated process — not a person running commands by hand — makes reality match it.
The term and its formal definition come from the CNCF's OpenGitOps working group, which publishes four principles that something has to satisfy to be called GitOps: the desired state must be expressed declaratively; it must be stored in a way that enforces immutability, versioning, and a complete history; software agents must pull that desired state automatically from the source rather than having it pushed to them; and those agents must continuously reconcile — observe the actual state, compare it to the desired state, and act to correct any difference.
The mental model
Picture a control loop, not a one-time deployment step. A GitOps agent runs inside (or alongside) your cluster. On an interval — often a few minutes — it checks the Git repository (or, increasingly, an OCI registry) that holds your desired-state manifests. If the repository has changed, or if the live system has drifted from what the repository describes, the agent reconciles: it applies whatever changes are needed to bring the live state back into alignment with the declared state. If you manually edit a resource with kubectl edit outside of Git, a correctly configured GitOps agent will revert it on the next reconciliation pass — the live cluster isn't the source of truth, Git is.
This is a structural break from how most teams have run CI/CD. A traditional pipeline pushes: a CI job builds an artifact, then a deploy step in that same pipeline reaches out and pushes changes into the target environment, usually with credentials for that environment sitting in the CI system. GitOps inverts the direction of control: the agent living inside the target environment pulls its own configuration from Git. Nothing external needs standing credentials to reach into your cluster and change it; the cluster reaches out to Git instead, on its own schedule, with its own scoped permissions. This is a genuine security property, not just an implementation style — it's called out explicitly by the Flux project as one of the reasons GitOps agents are designed the way they are: least-privilege, pull rather than push.
What you get that a manual kubectl apply doesn't
Because the desired state lives in Git, you inherit everything Git already gives you for free: a complete, versioned history of every change, code review through pull requests before a change ever reaches production, and a rollback mechanism that's just "revert the commit" rather than a bespoke runbook. Because reconciliation is continuous rather than a one-off apply, you also get drift detection: if someone (or something) changes a live resource outside of Git, the next reconciliation pass notices the mismatch and either reports it or corrects it, depending on configuration. That combination — declared state, continuous reconciliation, pull-based agents — is what distinguishes GitOps from "we happen to keep our Kubernetes YAML in a Git repo."
The tooling landscape
Two CNCF projects dominate GitOps tooling for Kubernetes, and they approach the same four principles somewhat differently.
Argo CD runs as a Kubernetes controller that continuously monitors running Applications — its core custom resource, representing a group of Kubernetes resources defined by a manifest — and compares their live state against the target state declared in Git. When they differ, Argo CD reports the Application as OutOfSync and can either wait for a manual sync or, if configured for automated sync, reconcile immediately. It supports several ways of producing manifests from a repository (Kustomize, Helm, Jsonnet, or plain YAML/JSON directories), ships a web UI that visualizes sync status and resource health, and provides sync hooks (PreSync, Sync, PostSync) for orchestrating more complex rollouts like blue/green or canary deployments.
Flux takes a more modular, Kubernetes-native approach built as a set of composable custom resources under the "GitOps Toolkit" umbrella. A GitRepository (or OCIRepository, HelmRepository, Bucket) resource is a Source — it defines where desired-state configuration comes from and periodically checks it for changes, producing an artifact when something new is available. A Kustomization resource then reconciles that artifact's contents into the cluster on an interval (five minutes by default), and — this is the drift-correction behavior in practice — reverts any manual kubectl edit/patch/delete you make outside of Git on the next pass, unless you've suspended reconciliation. Installing Flux itself is done through a GitOps-native bootstrap process: Flux's own manifests get committed to a Git repository and then reconciled the same way as everything else it manages.
Both tools are graduated or widely adopted CNCF projects, both work with Kustomize and Helm, and both are frequently run together with each other's ecosystems or alongside CI systems like GitHub Actions or GitLab CI/CD, which typically handle the build half of the pipeline (compiling code, running tests, producing a container image and updating a manifest) while Argo CD or Flux handle the deploy half.
A useful first journey
- Read the four OpenGitOps principles and be able to explain, for any deployment process, whether it actually satisfies all four or just looks like GitOps because the YAML lives in a repo.
- Install Argo CD or Flux against a test cluster following its official getting-started guide, and point it at a small repository of plain Kubernetes manifests.
- Change a value in Git, push it, and watch the agent detect the difference and reconcile it — without running
kubectl applyyourself. - Manually edit the same resource directly in the cluster and watch the next reconciliation revert your change; this is the moment the "pull, not push" model stops being an abstraction.
- Read your chosen tool's core-concepts documentation (Argo CD's core concepts, or Flux's concepts and Kustomization docs) to connect its vocabulary to the four principles you started with.
Where GitOps is not automatically the answer
GitOps principles are agent-and-Kubernetes-shaped: they presume something is continuously watching a source of desired state and able to reconcile a live system against it, which fits container orchestration platforms very naturally and fits, say, a one-off database schema migration much less naturally. It also adds a layer you now have to operate and understand — reconciliation intervals, sync policies, drift-detection alerts — on top of Kubernetes itself, which is a real cost for a small team running one small cluster. And GitOps changes how changes reach production, not whether they're safe: a bad manifest committed and merged to the tracked branch will be reconciled into production just as faithfully as a good one, so code review and testing discipline around the Git repository matter more, not less, once an automated agent is the thing actually applying your changes.
