Introduction to GitOps: Principles and Practices
Git holds the desired state. An agent in the cluster makes the live system match it. Drift is a pull request, or it is a lie.
“Git as the source of truth is charming until someone force-pushes main and the cluster politely agrees.”
What you'll learn
Git is the desired state, not a diary
GitOps means the cluster is supposed to look like a commit. Not like the last thing someone typed into kubectl, and not like a console click that nobody reviewed. The repository holds the manifests. An agent inside the cluster reads them and makes the live objects match.
If the repo and the cluster disagree, the repo wins. That is the whole product. Everything else is how you stop people from 'just this once' editing a live Deployment.
Four rules, none of them a poster
The state is declarative. You write what should exist, not a shell script of the steps that got you there. The state is versioned. A bad change is a revert, which is a commit you already know how to make. The agent pulls. The cluster fetches the repo. You do not SSH in and push a manifest from a laptop. Reconciliation is continuous. If someone deletes a Deployment by hand, the agent puts it back, which is either the point or a surprise, depending on whether you told the team.
Skip any of those and you have Git-shaped CI, which is fine, and which is not GitOps. Call it what it is.
The agent pulls. You do not SSH
A push pipeline (GitHub Actions runs kubectl apply) can be reliable. It is also a credential that lives outside the cluster and a laptop that can still apply over the top. A pull agent (Argo CD, Flux) runs where the objects live, watches the repo, and applies the diff. The audit log is the Git history plus the agent's sync status.
Give the agent a read-only deploy key. Give humans pull requests. If humans still have production kubectl, you will get drift, and the agent will either fight them or be turned off. Decide which one before the incident.
Argo CD and Flux are the usual suspects
Argo CD shows you a tree of apps and goes red when sync fails. Flux is quieter and composes with the same Git repositories. Both will happily sync a broken manifest if you merged it. The tool is not the review.
Pin the agent version the way you pin any other production component. An unattended upgrade of the thing that applies every other upgrade is a bold choice. Point it at a branch you protect. main, with required reviews, is the boring correct answer.
What GitOps does not fix
It does not design the manifests. A repo full of copy-pasted YAML is still copy-pasted YAML, with a nicer history. It does not rotate secrets by itself. Sealed secrets, SOPS, or an external store still have to be a decision. It does not make a bad rollout safe. If the Deployment has no readiness probe, the agent will roll it out faithfully.
It also does not replace the pipeline that builds the image. CI produces an artifact and bumps the tag in Git. The agent deploys that tag. Mixing 'build' and 'apply' in one job is how a failed test still reaches the cluster because someone commented out the test step.
A change, from laptop to cluster
Edit the manifest. Open a pull request. Let CI render and lint it. A human reads the diff, which should be small enough to read. Merge. The agent syncs. If production looks wrong, revert the commit. Do not kubectl edit and promise to back-port it later.
If you cannot revert because the database migration already ran, that is an application problem. Write it down next to the change. GitOps will not invent a down migration for you.