Bird
Raised Fist0
Microservicessystem_design~25 mins

Docker Compose for local development in Microservices - System Design Exercise

Choose your learning style10 modes available

Start learning this pattern below

Jump into concepts and practice - no test required

or
Recommended
Test this pattern10 questions across easy, medium, and hard to know if this pattern is strong
Design: Local Development Environment with Docker Compose
Includes designing the Docker Compose setup for local microservices development. Excludes production deployment, CI/CD pipelines, and cloud infrastructure.
Functional Requirements
FR1: Run multiple microservices locally with a single command
FR2: Services should communicate with each other over a private network
FR3: Support environment variable configuration for each service
FR4: Allow easy rebuilding and restarting of services
FR5: Persist data for stateful services like databases
FR6: Expose necessary ports to host machine for testing
FR7: Enable logs viewing for all services in one place
Non-Functional Requirements
NFR1: Should work on developer machines with Docker installed
NFR2: Startup time for all services should be under 1 minute
NFR3: Services must be isolated but able to communicate internally
NFR4: Configuration should be simple and maintainable
NFR5: Support scaling of services locally (e.g., multiple instances)
Think Before You Design
Questions to Ask
❓ Question 1
❓ Question 2
❓ Question 3
❓ Question 4
❓ Question 5
❓ Question 6
❓ Question 7
Key Components
Docker Compose YAML file
Individual Dockerfiles for each microservice
Docker networks for service communication
Volumes for data persistence
Environment variable files (.env)
Service scaling configuration
Logging configuration
Design Patterns
Service discovery via Docker Compose network
Volume mounting for code hot-reloading
Multi-stage Docker builds for efficient images
Dependency ordering with depends_on
Using environment files for configuration management
Reference Architecture
Host Machine
   |
Docker Engine
   |
+-----------------------------+
|        Docker Compose        |
| +-----------+  +-----------+ |
| | Service A |  | Service B | |
| +-----------+  +-----------+ |
|       |            |         |
|    Network: dev-net          |
|       |            |         |
| +-----------+  +-----------+ |
| |  Database |  |  Cache    | |
| +-----------+  +-----------+ |
+-----------------------------+
Components
Docker Compose
Docker Compose YAML
Defines and manages multi-container application for local development
Microservices
Docker containers built from Dockerfiles
Individual services running isolated but networked together
Docker Network
User-defined bridge network
Allows services to discover and communicate with each other internally
Volumes
Docker volumes or bind mounts
Persist data and optionally mount source code for live reload
Environment Variables
.env files and environment section in Compose
Configure services dynamically without changing images
Ports
Port mapping in Compose
Expose service ports to host machine for testing and debugging
Logging
Docker logs and Compose logging options
Aggregate and view logs from all services easily
Request Flow
1. Developer runs 'docker compose up' command on host machine.
2. Docker Compose reads the YAML file and builds or pulls images for each service.
3. Docker Compose creates a private network 'dev-net' for services.
4. Each service container starts and connects to 'dev-net'.
5. Services communicate internally using service names as hostnames.
6. Persistent volumes are mounted for databases or stateful services.
7. Ports are mapped from containers to host for external access.
8. Logs from all containers are streamed to the terminal or log files.
9. Developer can stop or restart services with Docker Compose commands.
Database Schema
Not applicable as this design focuses on local environment orchestration rather than data schema.
Scaling Discussion
Bottlenecks
Limited CPU and memory resources on developer machines restrict number of running containers.
Network latency and port conflicts when scaling many services locally.
Long startup times if images are large or services have heavy dependencies.
Complexity in managing environment variables and configuration for many services.
Difficulty in replicating production environment exactly.
Solutions
Use lightweight base images and multi-stage builds to reduce image size.
Limit number of service instances locally; use mocks or stubs for some dependencies.
Use Docker Compose profiles to start only needed services.
Leverage bind mounts for faster code iteration without rebuilding images.
Use environment variable files and templates to manage configurations cleanly.
Consider container resource limits to avoid overloading host machine.
Interview Tips
Time: Spend 10 minutes understanding requirements and constraints, 20 minutes designing the Docker Compose setup and explaining components, 10 minutes discussing scaling and trade-offs, and 5 minutes for questions.
Explain how Docker Compose simplifies running multiple microservices locally.
Discuss service isolation and internal networking via Docker networks.
Highlight use of volumes for persistence and bind mounts for code changes.
Mention environment variable management for flexible configuration.
Address how to handle scaling and resource constraints on developer machines.
Show awareness of differences between local development and production environments.

Practice

(1/5)
1. What is the main purpose of using Docker Compose in local development for microservices?
easy
A. To replace the need for writing application code
B. To run multiple microservices together easily on a single machine
C. To deploy microservices directly to production servers
D. To monitor live traffic of microservices in production

Solution

  1. Step 1: Understand Docker Compose's role

    Docker Compose is designed to help developers run multiple services together locally using a simple configuration file.
  2. Step 2: Differentiate local development from production

    It is not meant for production deployment or monitoring but for easy local setup and testing.
  3. Final Answer:

    To run multiple microservices together easily on a single machine -> Option B
  4. Quick Check:

    Docker Compose = local multi-service setup [OK]
Hint: Docker Compose is for local multi-service running [OK]
Common Mistakes:
  • Confusing Docker Compose with production deployment tools
  • Thinking it replaces writing application code
  • Assuming it monitors live production traffic
2. Which of the following is the correct syntax to define a service named web in a docker-compose.yml file?
easy
A. service: web: image: nginx
B. containers: web: image: nginx
C. services: - web: image: nginx
D. services: web: image: nginx

Solution

  1. Step 1: Identify the correct top-level key

    The correct key to define multiple services is services, not service or containers.
  2. Step 2: Check service definition syntax

    Services are defined as keys under services, not as list items with dashes.
  3. Final Answer:

    services: web: image: nginx -> Option D
  4. Quick Check:

    Correct YAML key for services = services [OK]
Hint: Services go under 'services:' key without dashes [OK]
Common Mistakes:
  • Using 'service' instead of 'services'
  • Defining services as list items with dashes
  • Using 'containers' instead of 'services'
3. Given this docker-compose.yml snippet:
services:
  db:
    image: postgres
    ports:
      - "5432:5432"
  api:
    build: ./api
    depends_on:
      - db
    ports:
      - "8000:8000"

What happens when you run docker-compose up?
medium
A. Both db and api services start, with api waiting for db to be ready
B. api starts first, then db starts after
C. Only db service starts, api is ignored
D. Both services start but ports are not exposed

Solution

  1. Step 1: Understand depends_on behavior

    The api service depends on db, so Docker Compose starts db first.
  2. Step 2: Check port mappings

    Ports are correctly mapped for both services, so they are exposed on the host machine.
  3. Final Answer:

    Both db and api services start, with api waiting for db to be ready -> Option A
  4. Quick Check:

    depends_on controls start order [OK]
Hint: depends_on means start order matters [OK]
Common Mistakes:
  • Assuming api starts before db
  • Thinking ports are not exposed without extra config
  • Believing depends_on waits for full readiness (it waits only for start)
4. You wrote this docker-compose.yml but docker-compose up fails:
services:
  app:
    image: myapp
    ports:
      - "8080:80"
    volumes:
      - ./app:/app
    environment:
      - DEBUG=true
  db:
    image: postgres
    ports:
      - "5432:5432"
    environment:
      POSTGRES_PASSWORD: example

What is the error causing the failure?
medium
A. Port mapping for app is reversed; host port must be higher
B. Volume mapping for app is invalid; local path must be absolute
C. The environment variable for db uses wrong syntax; should be a list or key-value pairs
D. Missing depends_on between app and db

Solution

  1. Step 1: Check environment variable syntax

    For db, environment variables must be either a list of strings or a map with key-value pairs. Mixing styles causes errors.
  2. Step 2: Validate other configurations

    Volume and port mappings are valid; depends_on is optional and won't cause startup failure.
  3. Final Answer:

    The environment variable for db uses wrong syntax; should be a list or key-value pairs -> Option C
  4. Quick Check:

    Environment vars syntax must be consistent [OK]
Hint: Use consistent environment variable syntax [OK]
Common Mistakes:
  • Mixing list and map styles for environment variables
  • Assuming volume paths must be absolute
  • Thinking depends_on is mandatory
5. You want to develop three microservices locally: frontend, backend, and database. The backend depends on database, and frontend depends on backend. You also want to share code changes live between your host and containers. Which docker-compose.yml setup best fits these requirements?
hard
A. Define all three services with depends_on chaining, map ports, and use volumes to mount source code directories
B. Define only frontend and backend services, omit database, and build images without volumes
C. Run each service in separate Docker Compose files without depends_on, and no volume mounts
D. Use a single service combining all three microservices in one container with no volumes

Solution

  1. Step 1: Setup service dependencies

    Use depends_on to ensure backend starts after database, and frontend after backend.
  2. Step 2: Enable live code sharing

    Use volumes to mount local source code directories into containers for live updates during development.
  3. Step 3: Expose necessary ports

    Map ports for each service to access them from the host machine.
  4. Final Answer:

    Define all three services with depends_on chaining, map ports, and use volumes to mount source code directories -> Option A
  5. Quick Check:

    Dependencies + volumes + ports = correct setup [OK]
Hint: Use depends_on and volumes for live dev setup [OK]
Common Mistakes:
  • Omitting the database service
  • Not using volumes for live code updates
  • Combining all services into one container