Stop by Stop

DevOps line

Docker Compose

One page draws a private hallway of rooms, and only one door opens onto the street.

Words to know

Stops explain each step. The film plays the whole ride.

Explain it
Route
Private hallwayThe planNames every roomYouOn the streetNotice boardNotes wait hereBack roomDoes slow jobsFront deskThe street doorRecords roomKeeps the recordsFiling cabinetOutside the rooms
  • Starting, or a call
  • A note on its way
  • Ready
  • A call that failed
Stop 1 of 11

You open the plan

This one page names every room, the private hallway they share, and the cabinet outside. One word from you starts the whole floor.

Next stop: One private hallway

All stops

The everyday version

An office floor runs from one plan. The rooms share a private hallway, only the front desk opens onto the street, and the filing cabinet is fixed outside.

  • Youis the You

    Stands on the street and says start.

  • The planis the Docker Compose

    Names every room, the hallway, and the cabinet.

  • The front deskis the api

    The only room with a door onto the street.

  • The records roomis the db

    Must show a ready light before the front desk opens.

  • The notice boardis the redis

    Slow notes wait here until the back room has time.

  • The back roomis the worker

    Takes notes off the board and does the slow work out of sight.

  • The filing cabinetis the pgdata

    Stays put when the rooms are locked for the night.

  • Wrong rooma connection refused error

    The front desk looks for the records in its own room and finds nobody, because the records are down the hallway under their own name.

Interview questions

Say the short answer first. Go deeper only if they ask.

How do services find each other?
Short answer

By service name: Compose puts every service on one project network with built-in DNS.

If they dig deeper

Compose creates a network called <project>_default, and each service registers its name as a host name. Use the container port, as in db:5432, never the published host port. Traffic between services ignores ports.

Answer that loses points

“Use localhost”, or hardcoding container IP addresses.

Does depends_on wait for the database to be ready?
Short answer

Not by default. It only controls start order, and Compose waits until the container is running.

If they dig deeper

Add condition: service_healthy and a healthcheck such as pg_isready, so Compose waits for a passing check. Many teams also make the app retry its connection, because a dependency can restart later.

Answer that loses points

“depends_on guarantees the database accepts connections.”

What is the difference between ports and expose?
Short answer

ports publishes a port on the host. expose only records a port for other containers and publishes nothing.

If they dig deeper

Containers on one network reach each other’s ports without either setting. Publishing binds all interfaces unless you add 127.0.0.1:, and db and redis usually need no ports at all.

Answer that loses points

“Services need ports to talk to each other.”

Where does the data live, and how do you reset it?
Short answer

In a named volume. docker compose down keeps it, and docker compose down -v deletes it.

If they dig deeper

down removes containers and the project network, not named volumes. -v also removes the named volumes in the file and anonymous ones; external volumes are never removed. For Postgres 18 and newer mount at /var/lib/postgresql, for older versions /var/lib/postgresql/data.

Answer that loses points

“down deletes my database.”

What does localhost mean inside a container?
Short answer

The container itself, not your laptop and not another service.

If they dig deeper

Each container has its own network namespace, so its loopback is private. Reach another service by its name, such as db. On Docker Desktop, host.docker.internal resolves to the host. A published port is how the host reaches a container.

Answer that loses points

“localhost is always my machine.”

How do you change the setup for another environment?
Short answer

Keep compose.yaml as the base and layer compose.override.yaml on top. Compose reads both by default.

If they dig deeper

With -f you list files and they merge in order. Single-value fields such as command are replaced, while multi-value fields such as ports are concatenated. docker compose config prints the merged result.

Answer that loses points

“Keep a full copy of the file for each environment.”

How do you run several copies of a service?
Short answer

Use docker compose up -d --scale worker=3, or set scale in the file.

If they dig deeper

The flag overrides scale in the file. A service with a container_name cannot go beyond one container, so leave naming to Compose.

Answer that loses points

“Set container_name on every service, then scale.”

Compose or Kubernetes?
Short answer

Compose is the simple way to describe and run a stack on one server. Kubernetes manages containers across a cluster of nodes.

If they dig deeper

Docker says Compose works in development, testing, CI, staging and production, and its production guide starts with a single server. Kubernetes adds cluster features: it restarts failed containers, rolls out and rolls back changes, and scales horizontally.

Answer that loses points

“Compose is just Kubernetes on a laptop.”

Cheat-sheet

Commands you will actually type.

docker compose up -d --build

Build images, then create and start every service in the background.

docker compose logs -f api worker

Follow the logs of the services you name.

docker compose exec db psql -U app

Run psql inside the running db container, as user app.

docker compose run --rm api pytest

Run a one-off command in a new container, removed afterwards. It publishes no ports by default.

docker compose down -v

Remove containers and the network. Plain down keeps named volumes, and -v deletes them too.

docker compose config

Print the merged, resolved configuration, including compose.override.yaml.

docker compose up -d --scale worker=3

Run three worker containers. The flag overrides scale in the file.

depends_on: { db: { condition: service_healthy } }

Wait for the db healthcheck to pass. Pair it with `test: ["CMD-SHELL", "pg_isready -U app"]` on db.

Sources