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.

The reconciliation loop, one more time
This is, again, Chapter 2 (Course 1)'s reconciliation loop pattern — just with the "desired state" source now being a git repository rather than what's already stored in etcd directly.

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 clusterA controller inside the cluster pulls changes from git itself
Where do deployment credentials live?In the external CI/CD systemNowhere 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

1. A developer changes a Helm chart's values.yaml (k8s2-3) in git 2. Opened as a pull request, reviewed (git2-7's own code review process) 3. Merged 4. The GitOps controller notices the change in git 5. It automatically applies the change to the cluster -- nobody runs kubectl or helm manually at all

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.

GitOps isn't a security fix on its own
The GitOps controller's own identity still needs the same RBAC discipline (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

Exercise 1

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 solution
Exercise 2

Explain how Sealed Secrets resolves the tension between GitOps wanting everything in git and Chapter 1-7's warning against committing raw Secrets.

📄 View solution
Exercise 3

Identify 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 solution

Chapter 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 manual kubectl/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