Back to All Cheatsheet Libraries cheatsheets

GitOps

Git as the single source of truth for Kubernetes: the four OpenGitOps principles, Argo CD and Flux CD command references, repo patterns, and a secrets + safety guide.

Git is the single source of truth; software agents make reality match it

GitOps is an operating model for Kubernetes and cloud infrastructure. You describe the desired state of your system declaratively and store it in Git. An in-cluster agent (Argo CD or Flux) continuously watches Git and the live cluster, and reconciles any difference. You never kubectl apply to production by hand: you open a pull request, merge it, and the agent rolls it out. The Git history becomes your audit log, your change-approval record, and your one-command rollback.

The term was coined by Weaveworks in 2017; the vendor-neutral definition is now maintained by the OpenGitOps project under the CNCF (principles v1.0.0). Argo CD and Flux are both CNCF graduated projects that implement it.

The four GitOps principles

The vendor-neutral standard from OpenGitOps (v1.0.0). Any tool that calls itself GitOps should satisfy all four.

1. Declarative

The entire system's desired state is expressed declaratively — what you want, not the steps to get there. YAML manifests, Helm charts, Kustomize overlays.

2. Versioned and Immutable

Desired state is stored so that it is immutable, versioned, and keeps a complete history. Git is the canonical store; every change is a commit.

3. Pulled Automatically

Software agents automatically pull the desired state from the source. The cluster reaches out to Git — nothing outside pushes changes in.

4. Continuously Reconciled

Agents continuously observe actual state and apply the desired state, correcting drift on their own without a human running a deploy.

Push CD vs pull-based GitOps

Traditional push: CI pipeline --kubectl/helm apply--> cluster GitOps pull: Git repo <--watch & reconcile-- in-cluster agent

Push (classic CI/CD)

The pipeline holds cluster credentials and applies changes from outside. Simple, but the pipeline is a standing set of prod keys, and the cluster can silently drift from what CI last ran.

Pull (GitOps)

An agent inside the cluster pulls from Git. No external system needs cluster write-credentials, drift is auto-corrected, and the running state always maps to a Git commit.

Why pull is safer

Prod credentials never leave the cluster. A leaked CI token can't touch prod. This credential-boundary win is the main security argument for GitOps.

Rollback

Reverting a deploy is git revert plus a merge. The agent converges the cluster back to the previous commit automatically.

When GitOps fits
Kubernetes-heavy platforms, multiple clusters or environments, teams that want PR-based change control and audit trails, and anyone tired of manual kubectl apply drift.
When it may be overkill
A single tiny app, no Kubernetes, or a team with no Git-review culture yet. GitOps adds an agent, a repo layout, and a secrets story you must maintain.
Pairs well with
Runs on top of your existing Kubernetes, Docker images, and Git & GitHub workflow. Terraform still provisions the cluster; GitOps manages what runs on it.

Argo CD — GitOps with a web UI

A Kubernetes controller plus a web dashboard. You define Application resources that point at a Git repo path; Argo CD syncs them into the cluster and shows a live diff of desired vs actual. Popular for its UI, multi-tenancy (Projects), and the ApplicationSet generator for fanning one config across many clusters. Heavier than Flux (roughly 500 MB–1 GB memory) because of the API server and UI.

1

Install into the cluster

kubectl create namespace argocd kubectl apply -n argocd --server-side --force-conflicts \ -f https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml
2

Reach the UI / API and log in

kubectl port-forward svc/argocd-server -n argocd 8080:443 argocd admin initial-password -n argocd # the starting admin password argocd login localhost:8080

Change the admin password immediately, then treat the initial-password secret as spent.

3

Point an app at a Git path and sync

argocd app create guestbook \ --repo https://github.com/argoproj/argocd-example-apps.git \ --path guestbook \ --dest-server https://kubernetes.default.svc \ --dest-namespace default argocd app sync guestbook
Commands: 0
Task Command Notes
List all applicationsargocd app listShows sync status (Synced/OutOfSync) and health for every app.
Show one app + live diffargocd app get guestbookThe status line tells you whether the cluster matches Git.
Manual syncargocd app sync guestbookApplies Git state now. With auto-sync on, Argo does this for you.
Preview the diff onlyargocd app diff guestbookDesired (Git) vs live (cluster). Run before a manual sync.
Roll back to a previous syncargocd app rollback guestbook &lt;revision&gt;Reverts the cluster; the durable rollback is still a git revert + merge.
Enable auto-sync + self-healargocd app set guestbook --sync-policy automated --self-heal --auto-pruneSelf-heal reverts manual cluster edits; auto-prune deletes resources removed from Git.
Watch historyargocd app history guestbookEvery sync, with its Git revision.
Delete an appargocd app delete guestbookAdd --cascade=false to keep the deployed resources.
Refresh from Git nowargocd app get guestbook --refreshForces a re-check instead of waiting for the ~3-minute poll.
Register another clusterargocd cluster add &lt;context&gt;One Argo CD can manage many clusters.
Create a Project (tenant boundary)argocd proj create team-aProjects restrict which repos, clusters, and namespaces apps may use.

Flux CD — lightweight, Kubernetes-native, CLI-first

A set of composable controllers (source, kustomize, helm, notification) with no built-in UI. You drive it with the flux CLI and plain YAML in Git. Lighter than Argo CD (roughly 200–400 MB) and favored when you want a minimal, GitOps-toolkit approach. flux bootstrap is the signature move: it installs Flux and commits Flux's own manifests to your repo, so Flux manages itself via GitOps from minute one.

1

Check prerequisites

flux check --pre
2

Bootstrap against your Git repo

export GITHUB_TOKEN=&lt;a PAT with repo scope&gt; flux bootstrap github \ --owner=$GITHUB_USER \ --repository=fleet-infra \ --branch=main \ --path=./clusters/my-cluster \ --personal

Creates the repo if needed, commits Flux's manifests under that path, installs the controllers, and points them at that path.

3

Add a source and a kustomization

flux create source git podinfo \ --url=https://github.com/stefanprodan/podinfo \ --branch=master --interval=1m flux create kustomization podinfo \ --source=podinfo --path="./kustomize" \ --prune=true --interval=10m
Commands: 0
Task Command Notes
Check a running installflux checkVerifies controllers are healthy after bootstrap.
List kustomizations + statusflux get kustomizationsReady column shows whether each is reconciled; add --watch to follow live.
List Git sourcesflux get sources gitShows which revision each source is pinned to.
Force a reconcile nowflux reconcile kustomization podinfo --with-sourceSkips the interval wait; --with-source pulls Git first.
Pause reconciliationflux suspend kustomization podinfoFreezes a workload — the safe way to stop auto-updates during an incident.
Resume reconciliationflux resume kustomization podinfoUn-pauses; Flux catches up to Git.
Explain why something failedflux logs --level=error --all-namespacesThe controllers' own logs — first stop when a sync won't go Ready.
Diff a kustomization vs clusterflux diff kustomization podinfo --path ./kustomizeLocal preview of what a reconcile would change.
Export a resource as YAMLflux create source git podinfo ... --exportPrints YAML to commit to Git instead of applying imperatively.
See everything Flux managesflux get all --all-namespacesSources, kustomizations, helm releases, alerts in one view.
Uninstall Fluxflux uninstallRemoves controllers; your Git repo is untouched.

Repository structure

Separate what changes for different reasons. The most common split is an app-source repo (code + Dockerfile) and a config repo (the manifests GitOps watches).

fleet-infra/ # the config repo GitOps watches |- clusters/ | |- prod/ # one folder per cluster | | |- apps.yaml # app-of-apps or Flux kustomization | |- staging/ |- apps/ | |- web/ | | |- base/ # shared Kustomize base | | |- overlays/prod/ # per-env overlays (image tag, replicas) | | |- overlays/staging/ |- infrastructure/ # ingress, cert-manager, etc.

Separate config repo

Keep manifests out of the app repo so a CI image build doesn't churn deploy history, and so read access to config doesn't mean read access to source.

Base + overlays

Kustomize (or Helm values) express one base and per-environment overlays. Promotion = change the image tag in an overlay via PR.

Folder-per-cluster

Each cluster maps to a directory the agent is pointed at, so adding a cluster is a folder, not a new tool.

Promotion by PR

Move a change from staging to prod by opening a PR that bumps the prod overlay. Review and merge is the deploy.

Core patterns

App-of-Apps (Argo CD)
One parent Application whose Git path contains child Application manifests. Bootstrap a whole cluster from a single root app.
ApplicationSet (Argo CD)
A generator that templates many Applications from a list, a Git directory, or a cluster list — the way to fan one config across many clusters/teams.
Kustomize / Helm
Both agents render Kustomize overlays and Helm charts. Pick one templating approach per repo and stay consistent.
Sync waves / dependencies
Argo CD sync waves and hooks order resources (CRDs before the workloads that use them). Flux uses dependsOn between kustomizations.
Progressive delivery
Layer canary/blue-green on top: Argo Rollouts for Argo CD, Flagger for Flux. GitOps handles the rollout; these handle the traffic shift.
Server-Side Apply
Both tools now lean on Kubernetes Server-Side Apply so the API server owns field merging — fewer "conflict storms" when multiple controllers touch one resource.

Terminology

Showing 0 terms
Term What it means
Desired stateThe declarative spec of what should be running, stored in Git.
Live / actual stateWhat is really running in the cluster right now.
ReconciliationThe agent's loop that compares desired vs live and applies the difference.
DriftWhen live state diverges from Git — a manual kubectl edit, a crash, an operator change.
Self-healAuto-reverting drift back to Git without a human (Argo selfHeal; Flux corrects on each reconcile).
Sync / applyPushing the Git-defined state into the cluster.
PruneDeleting cluster resources that were removed from Git. Off by default — enable deliberately.
SourceA Git (or Helm/OCI) repository a tool watches. Flux models this as a GitRepository.
Application (Argo)An Argo CRD linking a repo path to a destination cluster/namespace.
Kustomization (Flux)A Flux CRD that builds a path from a source and applies it on an interval.
Rendered manifestsThe final YAML after Kustomize/Helm templating, which is what actually gets applied.
Reconcile intervalHow often the agent re-checks (Flux per-resource; Argo polls Git ~3 min, or instantly via webhook).
App-of-AppsA parent app whose children are more apps — bootstraps a cluster from one root.
BootstrapFlux's install step that also commits Flux's own config to Git so it self-manages.
Secrets: never commit plaintext to Git
  • The core tension: GitOps wants everything in Git, but a secret in Git is in history forever, readable by anyone who ever clones the repo. Plain Kubernetes Secret YAML is only base64 — that is not encryption.
  • Sealed Secrets (Bitnami): encrypt a secret with a cluster-side key so only that cluster can decrypt it. Simplest "just commit it and the controller handles it" option. Back up the controller's private key offline — lose it and every sealed secret is unrecoverable.
  • SOPS (+ age/GPG/KMS): encrypts values inside YAML while keys stay readable. Git-native, works for non-Kubernetes files too, integrates with cloud KMS. Both Flux and Argo can decrypt SOPS at apply time.
  • External Secrets Operator: don't store the secret at all — store a reference and pull the real value from Vault / AWS Secrets Manager / etc. Best for many clusters and automatic rotation.
  • Rule of thumb: Sealed Secrets for a simple single cluster, SOPS for small teams already using KMS, ESO for enterprise/multi-cluster with rotation.
Safety guardrails
  • Protect the config repo like production — it is production. Require PR review, branch protection, and signed commits on the branch the agent tracks. Merge access = deploy access.
  • Turn on auto-prune deliberately. Pruning deletes cluster resources removed from Git. Powerful for keeping state clean, dangerous if someone deletes the wrong file. Test in staging first.
  • Self-heal will fight your hotfix. With self-heal on, a manual kubectl edit in prod is reverted within minutes. During an incident, suspend/pause the app first, fix, then land the fix in Git and resume.
  • Scope the agent's RBAC. The in-cluster agent is highly privileged. Use Argo Projects / per-tenant service accounts so one team's app can't deploy into another's namespace.
  • Pin sources. Track a branch or a tag you control, not someone else's main. For third-party charts, pin a version and mirror it.
  • Least privilege on the pull side. Give the agent a read-only deploy key / token scoped to the config repo only.

Best practices

One repo, one source of truth
Every environment's state lives in Git. If you changed it with kubectl, it will be reverted — put it in Git instead.
Deploy = merge a PR
No out-of-band applies. The PR is the change request, the review, and the audit record in one.
Roll back with git revert
A bad deploy is undone by reverting the commit and merging. The agent converges the cluster back automatically.
Separate app and config repos
CI builds the image and bumps the tag in the config repo via an automated PR. Keeps deploy history clean and access boundaries sharp.
Wire up notifications
Alert on OutOfSync, failed syncs, and drift (Argo notifications / Flux alerts to Slack). Silent reconciliation should still be observable.
Promote through environments
staging overlay first, then a PR to the prod overlay. Never edit prod directly; let the same change flow through.
Order with waves / dependsOn
Apply CRDs, namespaces, and operators before the workloads that need them, or the first sync flaps.
Watch for drift, don't ignore it
Persistent drift usually means someone is working around GitOps. Fix the process, not just the resource.