π A hands-on Docker learning lab β from your very first container to multi-language, production-style architectures with CI/CD.
docker-hands-on/
β
βββ π docker-basics/ # Start here! Your first Dockerfile & Python app
βββ π¦ fastapi-demo-01/ # FastAPI + PostgreSQL with Docker Compose
βββ πΈ django-docker-demo/ # Django 6 + PostgreSQL + multi-stage builds + CI/CD
βββ π polyglot-docker/ # Python + Node.js + Rust + Nginx + Grafana/Loki
βββ π¬ docker-debug-lab/ # Simulate real production incidents & debug them
Follow these projects in order for the smoothest learning journey:
β docker-basics β β‘ fastapi-demo-01 β β’ django-docker-demo
First container Compose + DB Multi-stage + CI/CD
β
β£ docker-debug-lab β β€ polyglot-docker
Debug like a pro Multi-language microservices + Observability
What you'll learn: Writing a Dockerfile, building an image, running a container, reading live logs.
docker-basics/
βββ app.py # Simple Python counter app
βββ Dockerfile # Your first Dockerfile
The App: A Python script that prints a running counter every 2 seconds β perfect for watching logs live.
# app.py
while True:
print(f"Running...{counter}!!", flush=True)
counter += 1
time.sleep(2)The Dockerfile:
FROM python:3.12
WORKDIR /app
COPY . /app/
CMD ["python", "-u", "app.py"]cd docker-basics
docker build -t my-first-app .
docker run my-first-app
# Watch the counter tick... πWhat you'll learn: Docker Compose, multi-container apps, volume persistence, service dependencies.
fastapi-demo-01/
βββ main.py # FastAPI app with health-check endpoint
βββ requirements.txt # fastapi, uvicorn, watchfiles
βββ Dockerfile
βββ docker-compose.yml # Web + PostgreSQL services
Architecture:
βββββββββββββββββββ ββββββββββββββββββββ
β FastAPI :8000 β βββββββΊ β PostgreSQL :5432 β
β (fast-api- β β (fast-api-db) β
β demo-01) β β β
βββββββββββββββββββ ββββββββββββββββββββ
Endpoints:
| Method | Path | Description |
|---|---|---|
GET |
/ |
Hello from Docker! |
GET |
/health-check |
Returns {"status": "Healthy"} |
cd fastapi-demo-01
docker compose up --build
# Test it
curl http://localhost:8000/health-checkWhat you'll learn: Multi-stage Docker builds, Django + PostgreSQL, GitHub Actions CI/CD, GHCR image publishing.
django-docker-demo/
βββ config/ # Django project settings, URLs, WSGI/ASGI
βββ core/ # Core app with health-check view
β βββ views.py # Returns {"status": "Healthy"}
βββ requirements.txt # Django 6, psycopg, etc.
βββ Dockerfile # β¨ Multi-stage build (builder + runtime)
βββ docker-compose.yml # Web + PostgreSQL
βββ .github/workflows/
βββ django_docker_demo.yml # π Build & push to GHCR on every push
This is where things get serious! The Dockerfile uses two stages to keep the final image lean:
# ββ Stage 1: Builder ββββββββββββββββββββββββββββββ
FROM python:3.12-slim AS builder
WORKDIR /app
RUN apt-get update && apt-get install -y build-essential # compile deps
COPY requirements.txt .
RUN pip install -r requirements.txt # install into /usr/local
# ββ Stage 2: Runtime ββββββββββββββββββββββββββββββ
FROM python:3.12-slim # fresh, clean image
WORKDIR /app
COPY --from=builder /usr/local /usr/local # copy ONLY installed packages
COPY . /app/
ENV PYTHONUNBUFFERED=1
EXPOSE 8000
CMD ["python", "manage.py", "runserver", "0.0.0.0:8000"]π‘ Why two stages? The builder stage needs
build-essential(heavy!) to compile Python packages. The runtime stage copies only the installed packages β no build tools, no bloat. Smaller image = faster deploys!
Every push to any branch automatically:
- β Checks out the code
- π·οΈ Sets a lowercase image name from your GitHub username
- π Logs into GitHub Container Registry (GHCR)
- ποΈ Builds the Docker image (tagged with the commit SHA)
- π€ Pushes the image to
ghcr.io/<your-username>/docker-hands-on
cd django-docker-demo
docker compose up --build
# Health check
curl http://localhost:8000/health-check/
# β {"status": "Healthy"}What you'll learn: Multi-container orchestration across different languages, Nginx reverse proxy, centralized logging with Grafana + Loki + Promtail.
polyglot-docker/
βββ python-api/ # FastAPI service (Python 3.12)
βββ node-api/ # Express service (Node.js 22)
βββ rust-api/ # Axum service (Rust) β multi-stage build
βββ nginx/
β βββ nginx.conf # Reverse proxy routing all 3 APIs
βββ promtail-config.yaml # Scrapes Docker container logs
βββ compose.yaml # Wires everything together
ββββββββββββββββββββββββ
β Nginx :5000 β
β (reverse proxy) β
βββββ¬βββββββ¬ββββββββ¬ββββ
β β β
/api/ β /node/ /rust/
βΌ βΌ βΌ
ββββββββββββ ββββββββββ ββββββββββββ
β Python β β Node β β Rust β
β FastAPI β βExpress β β Axum β
β :8000 β β :3000 β β :4000 β
ββββββββββββ ββββββββββ ββββββββββββ
ββββββββββββββββββββββββββββββββββββββ
β Grafana :3001 βββ Loki :3100 β
β βββ Promtail (log scraper) β
ββββββββββββββββββββββββββββββββββββββ
| Path | Routes To |
|---|---|
/api/ |
Python FastAPI (:8000) |
/node/ |
Node.js Express (:3000) |
/rust/ |
Rust Axum (:4000) |
The Rust API uses a two-stage build β compile in rust:1.93, ship in debian:bookworm-slim:
FROM rust:1.93 AS builder
RUN cargo build --release # heavy compile step
FROM debian:bookworm-slim # tiny runtime image
COPY --from=builder /app/target/release/rust-api /app
CMD ["./rust-api"]| Tool | Role | Port |
|---|---|---|
| Promtail | Scrapes Docker container logs | β |
| Loki | Log aggregation & storage | 3100 |
| Grafana | Visualize logs & build dashboards | 3001 |
cd polyglot-docker
docker compose up --build
curl http://localhost:5000/api/health # Python
curl http://localhost:5000/node/health # Node.js
curl http://localhost:5000/rust/health # Rust
curl http://localhost:5000/api/aggregate # Python calls Node + Rust!
# Open Grafana at http://localhost:3001What you'll learn: Debugging containers using docker logs, docker stats, and docker inspect. Recognize common failure patterns before they bite you in production.
docker-debug-lab/
βββ services/
β βββ api-crash/ # Simulates a crash loop
β βββ api-memory/ # Simulates a memory leak
β βββ api-network/ # Simulates network failures
β βββ api-good/ # A healthy baseline service
βββ compose.yaml
Incident Simulation Table:
| # | Incident | Container | Debug Skill |
|---|---|---|---|
| 1 | π₯ Crash loop | crash-api |
docker logs |
| 2 | π§ Memory leak | memory-api |
docker stats |
| 3 | π Network failure | network-api |
docker inspect |
| 4 | β Healthy baseline | good-api |
Comparison reference |
Key debug commands to practice:
docker logs <container> # What did it print before dying?
docker stats # Live CPU/memory per container
docker inspect <container> # Full config, network, mounts
docker exec -it <container> sh # Shell in to investigate live# ποΈ Build & Run
docker build -t my-app .
docker run -d -p 8000:8000 my-app
docker compose up --build
# π Inspect & Debug
docker ps # running containers
docker ps -a # all containers
docker logs -f <container> # follow logs
docker stats # live resource usage
docker exec -it <container> sh # shell into container
docker inspect <container> # full container details
# π§Ή Cleanup
docker stop <container>
docker rm <container>
docker rmi <image>
docker system prune -a # β οΈ removes everything unused| Technology | Used In |
|---|---|
| π Python 3.12 | docker-basics, fastapi-demo-01, django-docker-demo, polyglot-docker |
| π¦ FastAPI + Uvicorn | fastapi-demo-01, polyglot-docker |
| πΈ Django 6 | django-docker-demo |
| π¦ Rust (Axum + Tokio) | polyglot-docker |
| π© Node.js 22 (Express) | polyglot-docker |
| π PostgreSQL 16 | fastapi-demo-01, django-docker-demo |
| π Nginx | polyglot-docker (reverse proxy) |
| π Grafana + Loki + Promtail | polyglot-docker (observability) |
| βοΈ GitHub Actions + GHCR | django-docker-demo (CI/CD) |
Prerequisites: Install Docker Desktop
# 1. Clone the repo
git clone https://github.com/Riju007/docker-hands-on.git
cd docker-hands-on
# 2. Start with the basics
cd docker-basics
docker build -t my-first-app .
docker run my-first-app
# 3. Work your way up through each project! π―Made with β€οΈ and lots of β by Riju
Learning in public. Failing forward. Shipping containers. π³
β If this helped you learn Docker, drop a star! β