Skip to content
Platform Engineering

Day 29: GitOps — Declare It in Git, Let Automation Do It

GitOps isn't 'CI/CD but for Kubernetes.' It's a specific claim about where truth lives — and once you take that claim seriously, drift, rollbacks, and audits stop being separate problems.

Thamunkpillai 5 min read

There's a version of "GitOps" that just means "we keep our Kubernetes YAML in a Git repo," and a version that's a genuinely different operating model for infrastructure. The gap between them is one specific architectural decision: does a human or a pipeline push changes into the cluster, or does something inside the cluster continuously pull toward whatever Git says the world should look like?

Push-based automation — kubectl apply from a CI job — is still CI/CD. It's an improvement over manual changes, but it inherits CI/CD's blind spot: the pipeline knows what it sent, not what's actually running. GitOps closes that gap by putting a controller inside the cluster whose entire job is reconciliation — watch Git, compare it to the live state, and continuously correct any difference.

The mechanism, not the marketing

A GitOps setup has four moving parts:

  1. A developer changes a declarative config — a Helm values file, a Kustomize overlay, a raw manifest.
  2. That change is committed and pushed to a Git repository, which is the single source of truth.
  3. A GitOps controller — Argo CD or Flux are the two dominant choices — detects the change by continuously watching the repo.
  4. The controller reconciles: it syncs the cluster's actual state to match what Git declares, and it keeps doing this forever, not just at deploy time.

Note

The word to notice is "continuously." A CI pipeline runs once per deploy and then walks away. A GitOps controller never walks away — it's still comparing desired state to actual state five minutes after the last deploy, an hour after, a week after.

That last property is what makes GitOps a different category of tool, not a rebrand of CI/CD. It's also what gives you drift correction essentially for free: if someone runs kubectl scale deployment/webapp --replicas=1 directly against the cluster — bypassing Git entirely, the way an under-pressure engineer does at 2 a.m. — the controller notices the live state no longer matches Git, and reverts it. Not because anyone caught the change in review. Because the system never stopped watching.

Why teams that adopt this stop dreading rollbacks

In a traditional deploy model, rolling back means finding the previous artifact, re-running a deploy pipeline against it, and hoping the pipeline behaves the same way in reverse as it did forwards — which it often doesn't, because rollback paths get tested far less than forward paths.

In GitOps, a rollback is a git revert. The controller sees the reverted commit exactly like it sees any other commit, and reconciles the cluster to match it. There's no separate "rollback procedure" to maintain, because rolling back isn't a special operation — it's just another state transition, handled by the same mechanism as every other change.

Traditional push deploysGitOps
Source of truthWherever the last successful pipeline run pushed toThe Git repository, continuously
DriftSilent until someone noticesDetected and corrected automatically
RollbackA separate procedure, often untestedgit revert
Audit trailPipeline logs, if retainedFull Git history, inherently
Who can change the clusterAnyone with pipeline or cluster accessAnyone with Git access — and only Git access, if enforced

The part teams skip: RBAC follows from the model

If Git is genuinely the source of truth, direct cluster access stops being something engineers need day to day — which means it can be locked down without anyone losing the ability to ship changes. This is where GitOps stops being a convenience feature and starts being a security posture: fewer people holding kubectl credentials to production is a smaller attack surface, and every change that does land is a reviewable, revertible pull request instead of an unlogged command someone ran from their laptop.

Where this connects

GitOps is the delivery mechanism that makes the platform-as-a-product model from earlier in this series operationally real — a platform team can hand application teams a Git-based interface instead of cluster credentials, and mean it.

Where GitOps doesn't help

It's not a substitute for CI. Building, testing, and producing an artifact still happens before GitOps enters the picture — GitOps starts at "here's a declarative config pointing at a known-good image," not before. And it doesn't remove the need for good manifest hygiene: a values file that's grown into an unmaintainable pile of overrides is exactly as unmaintainable inside a GitOps workflow as outside one. GitOps fixes how changes reach the cluster. It has no opinion on whether the changes themselves are well designed.

The failure mode worth watching for is the anti-pattern list any GitOps rollout eventually runs into: someone bypasses Git with a direct kubectl change "just this once," someone disables the sync policy "temporarily" during an incident and forgets to re-enable it, or the repo structure sprawls until nobody's sure which overlay is actually driving production. None of these are GitOps failing — they're the discipline being abandoned under pressure, which is exactly when the reconciliation loop is most valuable.

Git is the source of truth. Automation is the engine. The cluster is just the destination it's driving toward.

Written by Thamunkpillai · Have a question or a correction? Reach out via email.

Get the useful stuff, not the noise.

Occasional notes on engineering, Platform Engineering, AI, cloud and things I’m learning along the way.

No spam. Unsubscribe anytime.