GitOps
Make Git the source of truth for what runs: declarative desired state, controllers that pull and reconcile, drift that heals itself, and rollbacks by revert.
- Explain the GitOps principles and how pull-based deployment differs from push-based
- Follow a reconciliation loop as it corrects drift and applies commits
- Promote changes and roll back with ordinary pull requests and reverts
Byte Bakery now runs on Kubernetes. One Tuesday someone “temporarily” scaled the checkout service down by hand with kubectl, forgot, and Friday’s rush hit a single pod. Nobody could tell what the cluster should look like.
GitOps applies Git workflows to operations. Its principles (from the OpenGitOps project):
- Declarative: the whole desired state of the system is described as data (YAML manifests, not scripts).
- Versioned and immutable: that desired state lives in Git, with full history.
- Pulled automatically: software agents pull the desired state - nobody runs
kubectl applyfrom a laptop. - Continuously reconciled: the agents keep comparing actual state with desired state and fix any difference.
Tools like Argo CD and Flux run inside the cluster as controllers. Changing production means opening a pull request; merging it is deploying. Manual changes get reverted (or at least flagged) as drift.
1apiVersion: argoproj.io/v1alpha1
2kind: Application
3metadata:
4 name: shop-production
5 namespace: argocd
6spec:
7 project: default
8 source:
9 repoURL: https://github.com/byte-bakery/deployments.git
10 targetRevision: main
11 path: environments/production/shop
12 destination:
13 server: https://kubernetes.default.svc
14 namespace: shop
15 syncPolicy:
16 automated:
17 prune: true # delete resources removed from Git
18 selfHeal: true # undo manual changes made in the cluster- Push vs pull: a push-based pipeline needs credentials to the cluster; in pull-based GitOps the cluster pulls from Git, so CI never holds production credentials.
- Promotion is a pull request that bumps an image tag in
environments/production/after it’s proven inenvironments/staging/. - Rollback is
git revert, and the audit log isgit log: who changed what, when, and who approved it.
1desired = {"shop": 3, "oven-api": 2}
2live = {"shop": 1, "oven-api": 2, "debug-pod": 1}
3
4for app in sorted(desired.keys() | live.keys()):
5 if app not in desired:
6 print(f"prune {app}")
7 elif live.get(app) != desired[app]:
8 print(f"scale {app}: {live.get(app, 0)} -> {desired[app]}")prune debug-pod scale shop: 1 -> 3
Key takeaways
GitOps: declarative desired state, versioned in Git, pulled and continuously reconciled by agents.
Deploying is merging a pull request; rolling back is reverting one.
Pull-based agents keep production credentials out of CI and heal drift.
Never commit plain secrets - encrypt them or reference a secret manager.
Lesson quiz
7 questions · pass with 5 correct · up to 50 XP
Passing this quiz completes the lesson and keeps your streak going. Questions you miss come back in review sessions later.
Practice: automate DevOps chores in Python
Write the small Python tools DevOps teams really build - pipeline runners, plan checkers, metric calculators, scanners - and run them against sample inputs. They run locally in your browser; no servers or cloud accounts needed.
Run a reconciliation loop
The input is the desired state from Git - lines app replicas image - then ---, then events. The cluster starts empty. Events:
drift APP replicas Nordrift APP image X- someone changes the live cluster by hand: printdrift: shop replicas = 1.commit APP replicas N,commit APP image Xorcommit APP delete- a merged change to Git: printcommit: shop image = shop:1.5.0(orcommit: shop deleted).tick- the controller reconciles. For each app alphabetically:create shop (3 x shop:1.4.0)if it isn’t live,prune shopif it’s live but not desired,scale shop 1 -> 3andupdate shop shop:1.4.0 -> shop:1.5.0for differences. Printtick 2: scale shop 1 -> 3, update ...joined by commas, ortick 2: in sync.
- A day in the cluster
Python runs in a sandboxed browser worker with a 60 second time limit. Its runtime loads from the Pyodide CDN; your code stays in this browser.
Order a sync
Each input line is a resource: Kind name, optionally followed by wave=N (default 0). Apply resources by wave (lowest first), then by kind in this order - Namespace, ServiceAccount, Secret, ConfigMap, PersistentVolumeClaim, Service, Deployment, Job, Ingress, with any other kind after those, alphabetically - then by name.
Print wave -1: Namespace bakery style lines numbered from 1, like 1. wave -1: Namespace bakery.
- Shop release
Python runs in a sandboxed browser worker with a 60 second time limit. Its runtime loads from the Pyodide CDN; your code stays in this browser.
Questions about this lesson
Stuck? Ask. Figured something out? Share it. Explaining is one of the best ways to learn.
Loading posts…