Skip to content
advanced Phase 16 · Docker Capstone Project

Capstone: Project Architecture

Design a multi-container Docker application with proper services.

1h
0 problems
Topic Progress 0%

Decomposing the Application

Decomposing the Application

A capstone starts with a diagram, not YAML. Take a typical web app and split it into pieces that can fail and scale independently: a web frontend (nginx serving static assets), an API (your language runtime), a background worker consuming jobs, PostgreSQL for state, and Redis for cache or queues.

For every edge, write two contracts: the protocol (HTTP across the compose network, TCP on 5432 for Postgres) and who owns the data. Services must be stateless — persist to Postgres or Redis, never to the container filesystem, or a restarted container loses work. Put everything on one user-defined network so Compose DNS resolves api and db by name instead of hardcoded IPs that change on every up.

Compose Service Topology

Compose Service Topology

services:
  web:
    image: nginx:1.27
    ports: ["8080:80"]
    depends_on:
      api: { condition: service_healthy }
  api:
    build: ./api
    environment:
      DATABASE_URL: postgres://app:secret@db:5432/app
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:3000/health"]
      interval: 10s
  worker:
    build: ./worker
    environment: { REDIS_URL: redis://cache:6379 }
  db:
    image: postgres:16
    volumes: [dbdata:/var/lib/postgresql/data]
volumes:
  dbdata: {}

Only web publishes a host port; db stays reachable solely on the internal network. The named volume dbdata preserves Postgres data across docker compose down, and service_healthy gates startup until the API health check passes.

Architecture Review and Tradeoffs

Architecture Review and Tradeoffs

Run the design through this checklist: does any service write to its own container layer (it should not)? Does scaling the API require redeploying the worker? Is Postgres accidentally published on the host? Each right answer is a boundary you defended.

Common pitfalls: bundling cron into the app container, which couples their lifecycles; using legacy links: instead of default DNS networking; hardcoding container IPs; and embedding database credentials in the image rather than environment or files.

Remember Compose is single-host. The moment you need multi-host scheduling, the same service definitions carry to Swarm or Kubernetes — that portability is part of the architecture's value.

Interview: justify every service with an independent scaling or failure-domain reason, or merge it.

Quiz

1. Why should services be stateless in this design?

Question 1 options

2. What does depends_on with condition: service_healthy guarantee?

Question 2 options

3. How does the api container reach the database?

Question 3 options

Flashcards

Question

Service boundary test

Answer

A boundary is justified if the service scales or fails independently; otherwise consider merging.

Question

Compose DNS

Answer

Services reach each other by service name over the default project network (e.g., db:5432).

Question

Named volume

Answer

Persists data across docker compose down; container layers do not.

Question

Health-gated startup

Answer

depends_on: {condition: service_healthy} waits for the target healthcheck before starting.

Revision Notes

Key Takeaways

  • 1. Design service contracts (protocol + data ownership) before writing compose YAML
  • 2. Stateless services plus named volumes survive restarts and scaling
  • 3. Only the frontend publishes ports; databases stay on the internal network

Interview Tips

  • • For every service, state why it is not merged into another — scaling axis or failure domain
  • • Be ready to explain what breaks when Compose moves from one host to an orchestrator

Cheat Sheet

Capstone: web → api → worker + db/redis. Stateless services; named volumes for state; service DNS on one user-defined network; healthcheck + depends_on condition; publish only frontend ports.

Continue Learning

Before You Start

  • No prerequisites listed.