Docker Compose — Volumes Exercises

1 minute read

Practice what you’ve learned about volumes. These exercises cover named volumes, bind mounts, sharing data, and lifecycle management.


Exercise 1 — Named Volume

Task: Write a compose file that runs MySQL 8 with:

  • A named volume mysql-data for database storage
  • Database name: testdb
  • Root password: rootpass
Show Answer
services:
  db:
    image: mysql:8
    environment:
      MYSQL_ROOT_PASSWORD: rootpass
      MYSQL_DATABASE: testdb
    volumes:
      - mysql-data:/var/lib/mysql

volumes:
  mysql-data:

Exercise 2 — Bind Mount Development

Task: Write a compose service for a Python Flask app in development:

  • Use python:3.12-slim image
  • Mount current directory to /app
  • Set working directory to /app
  • Install requirements and run in debug mode
  • Map port 5000
Show Answer
services:
  app:
    image: python:3.12-slim
    volumes:
      - .:/app
    working_dir: /app
    command: sh -c "pip install -r requirements.txt && flask run --host=0.0.0.0 --debug"
    ports:
      - "5000:5000"
    environment:
      FLASK_APP: app.py

Exercise 3 — Volume Syntax

Question: Identify each mount type (named volume, bind mount, anonymous volume, or error):

volumes:
  - pgdata:/var/lib/postgresql/data
  - ./src:/app/src
  - /tmp/logs:/var/log
  - /app/node_modules
  - config:/etc/config
Show Answer
  1. pgdata:/var/lib/postgresql/data → Named volume (no ./ or / prefix on source)
  2. ./src:/app/src → Bind mount (./ prefix = relative host path)
  3. /tmp/logs:/var/log → Bind mount (/ prefix = absolute host path)
  4. /app/node_modules → Anonymous volume (no source, just target)
  5. config:/etc/config → Named volume (no path prefix = volume name)

Remember: named volumes must be declared in the top-level volumes: key.


Exercise 4 — Sharing Data

Task: Write a compose file where:

  • A generator service writes a file every 5 seconds
  • A web service serves those files via Nginx on port 8080
  • They share a volume called web-content
Show Answer
services:
  generator:
    image: alpine
    command: sh -c "while true; do echo '<h1>Generated at '$(date)'</h1>' > /output/index.html; sleep 5; done"
    volumes:
      - web-content:/output

  web:
    image: nginx:alpine
    ports:
      - "8080:80"
    volumes:
      - web-content:/usr/share/nginx/html:ro

volumes:
  web-content:

Exercise 5 — Volume Lifecycle

Question: What happens to the named volume pgdata in each scenario?

  1. docker compose up -d (first time)
  2. docker compose down
  3. docker compose up -d (second time)
  4. docker compose down -v
  5. docker compose up -d (third time)
Show Answer
  1. Created — Volume pgdata is created fresh
  2. Kept — Volume survives down (data safe)
  3. Reused — Same volume, same data from step 1
  4. Removed — -v flag removes the volume (data lost!)
  5. Created — New empty volume (previous data is gone)

Key takeaway: Never use docker compose down -v unless you intentionally want to destroy volume data.