Skip to main content
RunBook Academy

Git, CI/CD & GitOpsLXXII · GitOps FoundationsFoundations

The GitOps principles — declarative, versioned, pulled, reconciled

Foundation⏱ ~18 mingit

What you'll learn

  • State the four OpenGitOps principles and the operational property each one guarantees
  • Explain why GitOps is a description of a target state, not a sequence of imperative steps
  • Distinguish a controller-based model from an agent-based push model
  • Recognise why the four principles together are stronger than any one of them alone

Prerequisites

Verified against Git 2.55.x teaching target; 2.40+ minimum · GitHub Actions continuous service; Aug 2026 documentation baseline · Argo CD v3.5.x teaching target; v3.0+ minimum · Flux v2.9.x · Sigstore Cosign v3.1.x · SLSA v1.2 · OCI Distribution Specification v1.1 · Git LFS v3.7.1 · Kubernetes (cross-course target) 1.36.x

Not yet marked complete on this device.

GitOps is not a product and not a single tool. It is an operational model whose definition is fixed by four principles, formalised by the OpenGitOps project under the CNCF TAG App Delivery working group. A system that satisfies all four is GitOps. A system that satisfies one or two is a CI/CD pipeline with some Git in it, which is fine, but is not the same thing.

The four principles:

  1. Declarative — the desired state of the system is described declaratively, not as a sequence of imperative steps.
  2. Versioned and immutable — the desired state is stored in a version-control system and that store is treated as immutable history.
  3. Pulled automatically — the changes to the desired state are pulled into the system by a software agent, not pushed by an external pipeline.
  4. Continuously reconciled — a controller continuously observes the actual state and reconciles it against the desired state.
flowchart LR
    A["Git repository"] -->|"desired state"| B["Controller"]
    B -->|"observe"| C["Actual state"]
    C -->|"diff"| B
    B -->|"apply / revert"| D["System"]
    D -->|"observed"| C

The diagram is the GitOps model in one picture. The desired state lives in Git. A controller inside the system reaches out, observes the actual state, computes a diff, and converges the system to the desired state. There is no imperative job that runs once and exits; there is a loop that never stops.

Why “declarative” is the first word

A declaration describes the world as it should be. An imperative script describes the world as it is changed. The distinction matters because the diff is the deliverable.

A Terraform apply, an ansible-playbook, a kubectl apply -f are all imperative operations on a desired-state description; the declarative artefact is the file. GitOps cares about the file, not the operation, because the file is what can be diffed, reviewed, signed, and reverted. The operation is a side effect of the loop.

Why “versioned and immutable” is the second word

If the declarative file lives only on a CI runner’s filesystem, it is not GitOps. The desired state must be in a system with a history (Git), and that history must be treated as immutable - tags are signed, branches are protected, force-pushes are forbidden. The reason is that the controller trusts whatever is at the ref; if the ref is mutable, the controller can be made to apply arbitrary state by an attacker who can edit the repository.

Why “pulled automatically” is the third word

The controller inside the system pulls from Git; nothing outside the system pushes to the system. The trust boundary moves. The system does not need to expose a write API; it only needs to be able to reach Git (or a Git proxy) on a read path. The cluster’s blast radius for an external compromise shrinks to “the attacker can read Git, but they cannot push the system”.

Why “continuously reconciled” is the fourth word

A push-based deploy applies the change once and exits. A GitOps loop never exits. It observes, diffs, and converges on a cadence. A configuration drift introduced by a manual kubectl edit is corrected by the next reconciliation; a manifest that someone deleted from the cluster is re-applied; a node that lost state is brought back to the desired state. The loop is the safety net.

Production discipline

  1. Name the loop. A team running GitOps should be able to answer “which controller reconciles which repository against which cluster?” in one sentence. If the answer is unclear, the system has drifted from the model.
  2. Treat Git as the only mutable surface. The cluster has a read API for humans and a write API only for the controller. If both humans and the controller write, the loop has to win.
  3. Measure the loop. Reconciliation latency (how long from commit to applied) and drift count (how many clusters diverged from Git) are the two operational metrics. Both should be dashboards.

Cross-course references

  • Ansible for Production Sysadmins - Parts XXXVII-XXXVIII (RepoArch, PlaybookCI) cover the imperative-versus-declarative distinction at the playbook layer; the principles are the same.
  • Terraform for Production Sysadmins - Parts IX-XII (State) cover the declarative state model that Terraform pioneered.
  • Kubernetes for Production Sysadmins - Parts on controllers and operators cover the reconcile loop pattern that GitOps relies on.

Quiz

Knowledge check · 4 questions

  1. Q1. A team stores Kubernetes manifests in Git and runs `kubectl apply -f` from a CI pipeline on every merge. Which GitOps principle does this NOT satisfy?

  2. Q2. A system can be considered GitOps as long as its desired state is declarative and stored in Git.

  3. Q3. Name the four OpenGitOps principles and identify which one defines who initiates the change.

  4. Q4. Diagnose why a 'GitOps' deployment pipeline is allowing drift and identify which principle is missing.

    Team T runs a CI pipeline that watches the main branch, runs `kubectl apply -f manifests/` on every commit, and exits. Six hours after a deploy, an on-call engineer notices the cluster has three pods that are not in any manifest, and one manifest in Git that does not correspond to any running workload. The CI pipeline has not run for four hours because no commit has landed.

Passing score: 75%. Answers are checked in this browser.