GitOps & CI/CD for Kubernetes
Kubernetes Intermediate/Advanced
Chapter 9 · GitOps & CI/CD for Kubernetes
Chapter 8 covered fixing things once they're already deployed. This chapter covers how deployments get into the cluster in the first place, in a disciplined, reviewable way — building on cloud1-11's IaC material and this site's own pipelines1 CI/CD course.
Revisiting Cloud1-11's Declarative-vs-Imperative Material
k8s1-4's own point: "real, reusable, version-controllable work should be declarative YAML." This chapter takes that all the way — not just writing YAML declaratively, but making git itself the actual source of truth for what's deployed, rather than a human running kubectl by hand.
What GitOps Actually Means
A git repository holds the desired state of the cluster — the same YAML/Helm charts this entire course has been writing — as the single source of truth. A dedicated GitOps controller running inside the cluster continuously watches that repository and automatically reconciles the cluster's actual state to match it.
GitOps vs. Traditional CI/CD Push-Based Deployment
| Traditional CI/CD (push) | GitOps (pull) | |
|---|---|---|
| Who initiates deployment? | An external pipeline (pipelines1) runs kubectl apply/helm upgrade against the cluster | A controller inside the cluster pulls changes from git itself |
| Where do deployment credentials live? | In the external CI/CD system | Nowhere external — the cluster reaches out, nothing reaches in |
A genuinely meaningful difference: broad deployment credentials living in an external CI system is a real, larger attack surface than a cluster-internal controller that only ever pulls — directly echoing k8s2-4's own least-privilege material.
ArgoCD & Flux — The Two Common GitOps Controllers
Both watch a git repository (or repositories) and continuously reconcile cluster state to match. ArgoCD offers a genuinely useful web UI showing exactly what's in git vs. what's actually deployed, and any drift between them — directly tying to cloud1-11's own configuration-drift material. GitOps controllers make drift immediately visible, and can optionally auto-correct it back to match git — genuinely resolving cloud1-11's own "manual fix gets silently overwritten" gotcha, by making that overwriting the actual intended behavior rather than a surprise. Flux offers similar core capability with different tooling/ecosystem choices, often used more as a Kubernetes-CLI/GitOps-toolkit-native option.
The Full GitOps Workflow
Genuinely closing the loop on Chapter 11 (Course 1)'s own "config as code, reviewed like any other code" aspiration.
Secrets in a GitOps World — Revisiting Chapter 1-7's Own Note
k8s1-7 flagged this chapter directly: "committing raw Secret YAML to git is genuinely risky... tools like Sealed Secrets or External Secrets Operator exist specifically to solve this." Now explained properly: Sealed Secrets encrypts a Secret's value client-side, before it's ever committed to git, producing a SealedSecret object that's genuinely safe to commit — only the cluster's own controller, holding the matching private key, can decrypt it back into a real Secret. This resolves the tension between GitOps' own core principle ("everything should be in git") and Chapter 7's own warning ("Secrets shouldn't be committed in a readable form") simultaneously.
When GitOps Is Worth the Setup
Honest framing, matching this course's own recurring convention: for a single-cluster, small-team setup, a straightforward CI/CD pipeline running kubectl apply/helm upgrade directly (pipelines1's own approach) is genuinely simpler and perfectly reasonable. GitOps earns its setup complexity specifically once there are multiple clusters/environments needing consistent, auditable, driftless deployment, or a genuine desire to eliminate external systems holding direct cluster deployment credentials.
This Course's Closing Thread — One Pattern, All the Way Through
Worth naming directly, this close to the end of the course: the reconciliation loop (Chapter 2, Course 1) has now appeared as ReplicaSets (Chapter 5), Service Endpoints (Chapter 6), liveness probes (Chapter 11), DaemonSets (k8s2-2), HPA (k8s2-6), and now a GitOps controller reconciling an entire cluster against a git repository — the same one idea, at every scale from a single container's health to a whole cluster's complete configuration.
k8s2-4) as anything else — least privilege applies to the controller's own permissions too, not just to human or application ServiceAccounts.
Hands-On Exercises
Explain the key security-model difference between traditional push-based CI/CD deployment and pull-based GitOps, specifically regarding where cluster deployment credentials live.
📄 View solutionExplain how Sealed Secrets resolves the tension between GitOps wanting everything in git and Chapter 1-7's warning against committing raw Secrets.
📄 View solutionIdentify at least four different places across this entire course (both Course 1 and Course 2) where the reconciliation loop pattern from Chapter 2 has appeared in a genuinely different guise, including this chapter's own GitOps controller example.
📄 View solutionChapter 9 Quick Reference
- GitOps — git as the source of truth; an in-cluster controller pulls and reconciles, another reconciliation-loop instance
- Push (external CI/CD holds deployment credentials) vs. pull (nothing external ever needs them) — a genuine security-model difference
- ArgoCD (drift visibility/UI) and Flux — the two common controllers
- Full workflow: PR → review (
git2-7) → merge → controller notices → auto-applies, no manualkubectl/helm - Sealed Secrets — client-side encryption before commit, resolving the git-everything vs. no-raw-Secrets tension from
k8s1-7 - Worth the setup at multi-cluster/multi-environment scale; a single-cluster small team is fine with plain CI/CD
- GitOps controllers still need RBAC discipline (
k8s2-4) applied to their own identity - Next chapter: Capstone — Deploying a Production-Ready Application, combining Helm, RBAC, autoscaling, monitoring, and health checks into one realistic deployment