skip to content

With a Docker Compose stack running detached, how do you see which services are up and follow only the API's recent log lines?

level: juniorimportance: should knowfreq 47%

answer

  1. detached means nothing streams
  2. one command lists, one prints output
  3. the crashed container is hidden
  4. follow plus a per-container tail

basics

~20 s

Run docker compose ps to list the project's running containers, adding -a to include exited ones, then docker compose logs -f --tail 50 api to print the api service's last 50 lines and keep streaming new ones.

solid answer

~40 s

`docker compose up -d` detaches, so nothing streams to your terminal. `docker compose ps` lists the project's containers with service, status and published ports, but **only running ones** by default: a crashed `api` simply vanishes, and `docker compose ps -a` shows it as exited with its exit code. For output, `docker compose logs api` prints that service's log history, each line prefixed with the container name such as `api-1`. `-f` (`--follow`) keeps streaming, and `--tail 50` (`-n 50`) starts from the last 50 lines **of each container** instead of the default `all`. So `docker compose logs -f --tail 50 api` is the everyday command, and `--since 10m` or `-t` narrow a noisy stream.

code

bash · 6 lines
bash
docker compose up -d
docker compose ps                     # running containers only
docker compose ps -a                  # include exited ones and their exit codes
docker compose logs -f --tail 50 api  # last 50 lines of api, then keep streaming
docker compose logs --since 10m -t api db
docker compose logs --index 2 api     # one replica of a scaled service

go deeper

for a junior

Recall the pair: docker compose ps for state, docker compose logs -f --tail N service for output, and that up -d detaches so nothing streams until you ask for it.

for a middle

Explain the defaults that trip people: ps hides exited containers without -a, --tail defaults to all and counts per container, and -f on logs means follow, not file.

for a senior

Show a fast triage routine under observation: ps -a for exit codes, logs --since and -t around the failure, --index for one replica, and a follow stream that survives a recreate.

for a principal

Treat these commands as a local convenience: be clear about what the team relies on in shared environments instead, and keep the local routine consistent with how incidents are investigated there.

## Detached means silent `docker compose up` without flags **attaches**: it streams the output of every service, prefixed with the container name, the way `docker compose logs --follow` does, and Ctrl+C stops the containers. `docker compose up -d` (`--detach`) starts them in the background and returns, and from then on nothing reaches your terminal until you ask. Two read-only commands answer the next two questions: *what is running?* and *what did it print?* Both are scoped to one Compose **project**, the set of containers created from one compose file under one project name. ## Reading state: `docker compose ps` `docker compose ps` lists the project's containers with the columns `NAME`, `IMAGE`, `COMMAND`, `SERVICE`, `CREATED`, `STATUS` and `PORTS`. - **Only running containers are shown by default.** A service that crashed disappears from the list rather than appearing as failed, which is the trap on a live screen share. - **`-a` (`--all`)** includes stopped containers with their exit status, plus the one-off containers that `docker compose run` created. - **`--status exited`** filters by state, **`--services`** prints only service names, **`-q`** prints container IDs, and **`--format json`** gives machine-readable output for scripts. ## Reading output: `docker compose logs` `docker compose logs [SERVICE...]` prints the output of the project's service containers, stopped ones included, each line prefixed with its container name such as `api-1`. | Flag | Meaning | Default | |---|---|---| | `-f`, `--follow` | keep streaming new lines | off: print and exit | | `-n`, `--tail N` | start from the last N lines **of each container** | `all` | | `--since`, `--until` | a time window, absolute or relative such as `10m` | none | | `-t`, `--timestamps` | show a timestamp on each line | off | | `--no-log-prefix` | drop the container-name prefix | off | | `--index N` | only replica N of a scaled service | every replica | Two details matter. `-f` here means `--follow`; the global `-f` written before the subcommand, as in `docker compose -f other.yaml logs`, means `--file`. And while following, Compose watches the project's container events, so when `api` is recreated by an `up --build` in another terminal, the new container's output joins the same stream. ## Attached `up` versus `logs` If you prefer to stay attached, `docker compose up` has its own output controls: `--attach api` streams only the `api` service, `--no-attach redis` mutes a noisy one, and `--timestamps` and `--no-log-prefix` behave like their `logs` counterparts. The difference is what Ctrl+C does. In an attached `up`, it stops the containers; in `docker compose logs -f`, it only stops the stream and the stack keeps running. That is why many developers run `up -d` once and open `logs -f` for the one service they are working on, in a terminal they can close freely. ## A triage session on an API + Postgres + Redis stack 1. `docker compose ps`: `db` and `redis` are up, `api` is missing. 2. `docker compose ps -a`: `api-1` shows as exited with a non-zero code. 3. `docker compose logs --tail 40 api`: the last 40 lines show why it stopped. 4. After the fix, `docker compose logs -f --tail 20 api` runs in one terminal while `docker compose up -d --build api` runs in another; the stream carries on into the recreated container. 5. `docker compose logs --since 5m -t api db` lines the two services up around the failure. ## What these commands do not cover - **Storage and rotation.** Where container output is kept and how it rotates is Docker Engine logging configuration, not a Compose command. - **One-off containers in `logs`.** `docker compose logs` skips containers created by `docker compose run`; their output went to the terminal that ran them. - **Other projects.** A stack started under another project name with `-p` needs the same `-p` on `ps` and `logs`, or you read the wrong stack. - **A single container outside Compose.** Plain `docker logs` and `docker ps` work on any container, but they know nothing about services, replicas or projects. The habit to show: **`ps -a` before concluding a service is fine, and `logs -f --tail N service` rather than replaying the whole history.**

  • You keep `docker compose logs -f api` open and rebuild `api` in another terminal. Do you lose the stream?
    No. With `--follow`, Compose watches the project's container events and attaches to containers that start later for the selected services, so the recreated `api` container's output appears in the same stream, from its start.
  • Why might `docker compose logs --tail 20 api` print 60 lines?
    `--tail` counts lines per container, not in total. With `api` scaled to three containers you get 20 lines from each, interleaved and prefixed `api-1`, `api-2` and `api-3`. Add `--index 2` to read a single replica.

saying these in an interview costs you the question

  • docker compose ps lists stopped containers by default.
  • docker compose logs -f shows only new lines and never the history.
  • --tail 50 limits the whole stack's output to 50 lines in total.
  • docker compose up -d keeps printing service logs in the terminal.
  • The -f in docker compose logs -f selects a compose file.