case study · containers
Docker Lab
UNDER CONSTRUCTION
A hands-on containers lab, built step by step: a Python/Flask API with PostgreSQL and Redis that starts as a single Docker Compose service and grows into a hardened, multi-service system with CI/CD, observability and a final migration to Kubernetes. The goal is to justify every decision and show the full path from containers to orchestration.
architecture
Target architecture
The target architecture. A developer pushes code; GitHub Actions builds, scans and publishes images to the registry, which are deployed into the runtime. Orchestrated with Docker Compose today and migrating to a local Kubernetes cluster, the Flask API queries PostgreSQL, caches in Redis and offloads async jobs to a worker via a queue. Prometheus and Grafana collect metrics.
overview
What it is & why I'm building it
Docker Lab is a progressive project: I build a small but realistic containerised system and evolve it stage by stage, so I can understand and defend every decision — from image layers to orchestration.
It starts as a single Docker Compose service (Flask API + PostgreSQL + Redis) and grows toward a hardened, observable, multi-service system that finally runs on a local Kubernetes cluster.
Highlights
- Container-first — a Flask API with PostgreSQL and Redis, defined and run with Docker Compose.
- Hardened images — multi-stage builds, non-root users and vulnerability scanning in the pipeline.
- Multi-service — the app splits into API + worker + queue for asynchronous processing.
- CI/CD — GitHub Actions builds, scans and publishes images to a registry (GHCR).
- Observability & orchestration — Prometheus + Grafana metrics, then a final migration to Kubernetes.
engineering decisions
Key decisions
// why containers?
Reproducible everywhere
Compose describes the whole stack as code: the same environment on my laptop, in CI and in production. No "works on my machine".
// why harden images?
Small, safe images
Multi-stage builds keep images small; non-root users and vulnerability scans reduce the attack surface before anything ships.
// why a worker + queue?
Async by design
Splitting slow work into a worker behind a queue keeps the API responsive and lets each part scale independently.
// why Kubernetes?
From Compose to orchestration
Compose is perfect to build and learn; migrating to a local Kubernetes cluster shows the real path to self-healing, scaling and rollouts.
build status
The build plan, stage by stage
This lab is under active construction. The foundation runs; the rest is a clear, honest roadmap from containers to orchestration.
// foundation · running
- Base stack: Flask API + PostgreSQL + Redis on Docker Compose
// in progress · next
- Image hardening: multi-stage, non-root, vulnerability scanning
- Split into services: API + worker + queue
- CI/CD: build, scan and publish images (GitHub Actions → GHCR)
- Observability: Prometheus + Grafana
- Migration to a local Kubernetes cluster
tech stack
Stack & responsibilities
| Technology | Layer | Responsibility |
|---|---|---|
| Docker · Compose | Orchestration | Defines and runs the whole multi-container stack as code. |
| Python · Flask | API | REST API and application logic. |
| PostgreSQL | Data | Relational persistence for the app. |
| Redis | Cache · Broker | In-memory cache and job-queue backend. |
| worker | Worker | Consumes queued jobs for async processing. |
| GitHub Actions | CI/CD | Builds, scans and publishes images to GHCR. |
| multi-stage · scan | Security | Image hardening: non-root, minimal layers, vuln scanning. |
| Prometheus · Grafana | Monitoring | Metrics, dashboards and alerts. |
| Kubernetes | Orchestration | Target platform: self-healing, scaling and rollouts. |
| Git · GitHub | Versioning | Everything versioned and documented, stage by stage. |
Follow the build
The repo grows stage by stage, each with its decisions and how to reproduce it — or get in touch to talk it through.