Case Study 02
From Docker Swarm to GKE + GitOps
Starting point
There was no concept of automated deployment. The first step up from manual releases was containerisation with Docker Swarm, using an NGINX reverse-proxy container as the entry point. This made deployments repeatable — but as the number of services and the traffic grew, Swarm’s ceilings became the bottleneck: limited autoscaling, weak self-healing, awkward rolling updates, and no first-class secret management.
Migration to Kubernetes
The estate was migrated to managed Kubernetes (GKE). The moves that mattered:
- Self-healing & rolling updates out of the box — failed containers restart, deploys are zero-downtime.
- Horizontal Pod Autoscaling — services scale on load instead of being statically sized.
- Sealed Secrets (kubeseal) — secrets are encrypted at rest and safe to commit to Git, so the entire desired state (including secrets) lives in version control without exposing plaintext.
- Helm — one parameterised chart renders every service across environments, replacing hand-maintained manifests.
The migration itself was run as a planned cut-over with documented run-books and a rollback path, because it touched every production service at once (including a stateful cache tier whose immutable selectors required careful handling).
GitOps with ArgoCD
Kubernetes solved orchestration, but deployments were still applied imperatively and drifted from what was in Git. The fix was GitOps:
- An app-of-apps pattern — one root application manages ~20 child applications under a governed project with source/namespace/resource allow-lists.
- Ordered sync-waves bring up namespaces → configuration → secrets → controllers → applications in the correct sequence.
- Automated prune + self-heal — the live cluster can never silently diverge from Git; a commit is a deployment, and rollback is a revert.
Edge, release engineering & observability
With delivery under control, the platform gained a regional L7 gateway and a Cloud Armor Web Application Firewall (OWASP Core Rule Set + rate limiting), tuned through a preview-soak-then-enforce process; a build-once / promote-any release engine with immutable, uniquely-tagged images and tag-based rollback; and a Prometheus / Loki / Grafana stack with Fluent Bit shipping logs to the SIEM.
Each stage was driven by a concrete limit of the previous one: manual releases → Swarm; Swarm’s scaling ceiling → Kubernetes; imperative drift → GitOps; exposure → WAF. The architecture matured by following the constraints rather than by big-design-up-front.
Outcome
~20 services now deploy themselves from Git onto autoscaling, self-healing infrastructure, behind a WAF, with full metrics and logs — operated end to end by one engineer, and reproducible from a documented run-book.