Docker interview question
How would you use Docker Compose to spin up a test environment?
Short answer
Define the app, its database and dependencies, and the test runner as services in compose.yaml. Use healthchecks with depends_on condition service_healthy so tests start only when services are ready, address services by name on the Compose network, and run with docker compose up --abort-on-container-exit.
Answer
Docker Compose describes a multi-container environment in one file, so “start the app, its database, a mock for the payment provider and the tests” becomes a single command. Modern Compose (v2, the docker compose CLI plugin) uses compose.yaml and does not need a top-level version: key.
Example
services:
db:
image: postgres:16
environment:
POSTGRES_USER: app
POSTGRES_PASSWORD: app
POSTGRES_DB: app
healthcheck:
test: ["CMD-SHELL", "pg_isready -U app -d app"]
interval: 2s
timeout: 3s
retries: 20
payments-mock:
image: wiremock/wiremock:3.9.1
volumes:
- ./mocks/payments:/home/wiremock
api:
build: ./api
environment:
DATABASE_URL: postgres://app:app@db:5432/app
PAYMENTS_URL: http://payments-mock:8080
depends_on:
db:
condition: service_healthy
payments-mock:
condition: service_started
healthcheck:
test: ["CMD", "curl", "-fsS", "http://localhost:3000/health"]
interval: 3s
timeout: 3s
retries: 30
tests:
build: ./tests
environment:
BASE_URL: http://api:3000
depends_on:
api:
condition: service_healthy
volumes:
- ./reports:/tests/reports
docker compose up --build --abort-on-container-exit --exit-code-from tests
docker compose down -v
Key points
- Readiness, not just start order. Plain
depends_ononly waits for the container to start. A database container starts long before it accepts connections. Healthchecks pluscondition: service_healthymake the test runner wait until dependencies are actually ready, which removes a whole category of flaky first tests. Theapihealthcheck assumescurlexists in that image; use whatever probe the image supports. - Networking. Compose creates a default network where services resolve each other by service name (
db,api). Inside the network, use container ports; host port mappings (ports:) are only needed if something outside Compose must reach a service. - Exit codes for CI.
--exit-code-from tests(which implies--abort-on-container-exit) makes the command return the test container’s exit code, so the CI step fails when tests fail, and the rest of the stack stops when the tests finish. - Clean state.
docker compose down -vremoves containers, the network and named volumes, so the next run starts from fresh data. Seed data through init scripts or API calls in test setup. - Parallel runs. Different project names (
docker compose -p run123 up) isolate stacks from each other on the same host. Avoid fixed host ports in that case. - Mocks for third parties. WireMock or a similar stub keeps tests deterministic and lets you simulate errors and timeouts the real sandbox can’t produce on demand.
Limits
Compose is excellent for local development and single-host CI. It is not a production orchestrator, so environment-specific behaviour (autoscaling, service mesh, real cloud services) still needs testing in a real environment.
What interviewers look for
- Healthchecks with
service_healthy, and knowing whydepends_onalone is insufficient. - Service-name networking.
- CI-friendly execution: exit code propagation and teardown with volumes.
A strong answer covers
- Services defined in compose.yaml: app, database, mocks, test runner
- Healthchecks with depends_on condition service_healthy for readiness
- Service discovery by name on the default network
- Run and tear down cleanly with exit code propagation
- Isolation: fresh data per run, project names for parallel runs