Docker Compose — Services Exercises
Practice what you’ve learned about services. These exercises cover service definitions, image vs build, ports, commands, and DNS.
Exercise 1 — Service Definition
Task: Write a compose file with these requirements:
- Service
webusingnginx:alpineon port 8080 - Service
apibuilt from./backenddirectory on port 3000 - Service
dbusingpostgres:16with password “secret” - All services restart unless stopped
Show Answer
services:
web:
image: nginx:alpine
ports:
- "8080:80"
restart: unless-stopped
api:
build: ./backend
ports:
- "3000:3000"
restart: unless-stopped
db:
image: postgres:16
environment:
POSTGRES_PASSWORD: secret
restart: unless-stopped
Exercise 2 — Ports
Question: For each scenario, write the correct ports: configuration:
- Nginx accessible on host port 80
- PostgreSQL accessible only from localhost
- App on port 3000, same on host
- Two web servers on different host ports, both using container port 80
- UDP service on port 5353
Show Answer
# 1. Nginx on port 80
ports:
- "80:80"
# 2. PostgreSQL localhost only
ports:
- "127.0.0.1:5432:5432"
# 3. Same port
ports:
- "3000:3000"
# 4. Two web servers
# web1:
ports:
- "8081:80"
# web2:
ports:
- "8082:80"
# 5. UDP
ports:
- "5353:5353/udp"
Exercise 3 — DNS Connection
Question: Given this compose file, write the correct DATABASE_URL and REDIS_URL for the api service:
services:
api:
build: .
environment:
DATABASE_URL: ???
REDIS_URL: ???
database:
image: postgres:16
environment:
POSTGRES_USER: appuser
POSTGRES_PASSWORD: apppass
POSTGRES_DB: mydb
redis:
image: redis:7
Show Answer
DATABASE_URL: postgres://appuser:apppass@database:5432/mydb
REDIS_URL: redis://redis:6379
Key points:
- Use the service name as the hostname:
database(notdb) - Use the service name as the hostname:
redis - PostgreSQL default port: 5432
- Redis default port: 6379
Exercise 4 — Command Override
Task: Write a compose service that:
- Uses the
node:20-alpineimage - Mounts the current directory to
/app - Sets the working directory to
/app - Runs
npm install && npm run devas the command
Show Answer
services:
app:
image: node:20-alpine
volumes:
- .:/app
working_dir: /app
command: sh -c "npm install && npm run dev"
ports:
- "3000:3000"
Using shell form (sh -c "...") because we need the && operator to chain commands.
Exercise 5 — Image vs Build
Question: For each scenario, should you use image:, build:, or both?
- Running a MySQL database
- Building your Python Flask API from source
- Building your app and pushing to a private registry
- Running Redis as a cache
- Using Nginx with a custom configuration
Show Answer
image:—image: mysql:8— official image, no customization neededbuild:—build: ./api— your custom code needs a Dockerfile- Both —
build: .+image: registry.example.com/myapp:v1— build and tag for push image:—image: redis:7-alpine— official imageimage:+ volumes —image: nginx:alpinewithvolumes: - ./nginx.conf:/etc/nginx/nginx.conf:ro— mount config without custom build