1 / 14
← → navigate | F fullscreen | T theme
100%

Docker Compose

From Single Containers to Microservice Architecture

Module 169 — Providing Services with Containers
gibb Bern • Platform Development • 2nd Year
Mario Iseli

Press Arrow Right to begin — or F for fullscreen

🐇

The Problem: Managing Containers Manually

Imagine you have 5 services. Each needs its own docker run command:

# Container 1: The database docker run -d --name db -e POSTGRES_PASSWORD=secret \ --network mynet -v db-data:/var/lib/postgresql/data postgres:16 # Container 2: The message broker docker run -d --name mq --network mynet rabbitmq:3 # Container 3: The backend API docker run -d --name api --network mynet -e DB_HOST=db myapp-api # Container 4: The frontend docker run -d --name web --network mynet -p 80:80 myapp-web # Don't forget the network! And the correct startup order!

Create networks, manage startup order, restart policies, volumes, environment variables... This doesn't scale.

The Solution: Docker Compose

🐇
One YAML file. One command. Everything runs.

What is Docker Compose?

  • Tool for defining and running multi-container applications
  • Configuration in a single docker-compose.yml file
  • Included with Docker Desktop
  • Infrastructure as Code for containers

What can it do?

  • Start/stop multiple containers at once
  • Automatically create networks
  • Manage volumes
  • Define dependencies between services
  • Centrally configure environment variables

docker run vs. docker compose up

Without Compose

# Create a network first docker network create myapp # Start each container manually... docker run -d --name db \ --network myapp \ -e POSTGRES_PASSWORD=s3cret \ -v pgdata:/var/lib/postgresql/data \ postgres:16 docker run -d --name api \ --network myapp \ -e DB_HOST=db \ myapp-api docker run -d --name web \ --network myapp \ -p 80:80 myapp-web

With Compose

# One single command! docker compose up -d # Rebuild & restart: docker compose up -d --build # Stop & clean up: docker compose down # Including volume cleanup: docker compose down -v

Anatomy of a docker-compose.yml

# The three main sections of a docker-compose.yml: services: # Which containers should run? web: image: nginx:alpine ports: - "80:80" api: build: ./backend # Build custom image from Dockerfile environment: DB_HOST: database # Service name = hostname! database: image: postgres:16 volumes: - db-data:/var/lib/postgresql/data networks: # Which networks do we need? (optional) default: driver: bridge volumes: # Which volumes for persistent data? db-data:

Services: The Key Options

Image & Build

  • image: Pre-built image from Docker Hub
  • build: Custom image from Dockerfile
  • container_name: Fixed name

Network & Ports

  • ports: "HOST:CONTAINER" mapping
  • networks: Which networks?
  • expose: Internal only

Configuration

  • environment: Set variables
  • env_file: Variables from .env
  • volumes: Persist data

Lifecycle

  • depends_on: Startup order
  • healthcheck: Readiness checks
  • restart: unless-stopped / always
🐇

Networking: DNS Instead of IP Addresses

Docker Compose automatically creates a network. Services find each other by their name:

# In docker-compose.yml: services: api: environment: DB_HOST: database # ← Service name = hostname! MQ_URL: amqp://rabbitmq # ← No localhost, no IP needed! database: # ← This name becomes a DNS entry image: postgres:16 rabbitmq: # ← This one too image: rabbitmq:3

Default Network

Compose automatically creates a network. All services can reach each other via their service name.

Custom Networks

With custom networks you can isolate services. E.g. the reverse proxy shouldn't access the database directly.

Essential Commands

Start & Stop

# Start everything (in background) docker compose up -d # Stop & remove containers docker compose down # Stop AND delete volumes docker compose down -v # Rebuild & start docker compose up -d --build

Observe & Debug

# Status of all containers docker compose ps # Follow logs (all services) docker compose logs -f # Follow logs (single service) docker compose logs -f api # Open shell inside container docker compose exec api sh

Docker CLI: Your Top 10 Commands

🐇

Images & Registry

# Download an image from Docker Hub docker pull nginx:alpine # Push your image to a registry docker push myuser/myapp:v1 # List all local images docker images # Build image from Dockerfile docker build -t myapp:latest .

Containers

# Run a new container docker run -d -p 80:80 nginx # List running containers docker ps # -a for all # Open a shell inside a container docker exec -it myapp sh # View container logs docker logs -f myapp

Cleanup

# Stop a running container docker stop myapp # Remove unused resources docker system prune -a
🐇

Your Best Friend

docker help docker <command> --help

When in doubt, follow the white rabbit.

🐇

The Container Journey: Where Does Compose Fit?

Every tool has its place — from simple to enterprise:

📦

Docker

One container, one service. Great for individual apps and first steps.

🐳

Compose

Multiple containers, single host. You are here! Perfect for dev & small deployments.

🐝

Swarm

Multi-host cluster. Docker-native, but rarely used in practice today.

⎈️

Kubernetes

Production orchestration. Self-healing, scaling, rolling updates.

Typical Use Cases

Local Development

New developers run docker compose up and have the complete environment running in 2 minutes.

Testing & CI/CD

Tests run against real databases and services — identical to production, but isolated and reproducible.

Microservice Prototypes

Different services in different languages, connected through networks and message queues.

Demo & Training

This presentation runs inside Docker Compose itself. 5 containers, one command. Meta enough? 😉

Our Demo Architecture

5 containers, 2 networks, 1 docker-compose.yml — everything you see right now:

┌──────────────────────────────────────────────────────────┐
  Caddy (Reverse Proxy) — Port 80                       
  Routes: /presentation/   /ingest/   /reader/           
├───────────────┬──────────────┬─────────────┬─────────────┤
  Presentation    Ingest         Reader        RabbitMQ    
  Astro/nginx     Node.js        Node.js       AMQP Broker 
  Static Slides   → publishes    ← consumes   Messages    
└───────────────┴──────┬────────┴──────┬───────┴─────────────┘
                                    
                      └────────┴──────┘
                         AMQP Queue
/presentation/ Slides /ingest/ Send /reader/ Receive

Login: student / m169StudenT

Hands-on: Read the docker-compose.yml!

The docker-compose.yml of this project is intentionally heavily commented. Every line explains what it does and why.

Tasks

  • Open the docker-compose.yml and read the comments
  • Send messages via /ingest/
  • Watch them arrive live at /reader/
  • Explore the RabbitMQ Management UI (Port 15672)

Experiments

  • docker compose ps — What's running?
  • docker compose logs -f ingest — What's happening?
  • docker compose restart reader — What happens to the messages?
  • docker compose down && docker compose up -d

Thank You!

Questions? Let's get hands-on.

Docs: docs.docker.com/compose

This presentation: built with Astro + Claude Code
Hosted in Docker Compose 🐳

🐇