Compose, Break, Repeat

Welcome! I’m Guillaume Lours, Docker Compose maintainer, passionate about containerization and developer tools.
I’m currently Software engineer at Docker working on Compose and Docker Sandboxes.

Exploring the iterative world of software engineering, Docker, and the art of building things that sometimes break.

Docker Compose Tip #81: tty and stdin_open for interactive containers

Drop a bash or python service into a compose.yaml and it exits immediately on up. The container starts, sees no stdin, prints nothing, and stops. The fix is the Compose equivalent of docker run -it: tty: true and stdin_open: true. What each flag does The two flags map directly to the docker run flags everyone has typed a thousand times: stdin_open: true ⇔ docker run -i — keep STDIN open even when not attached. tty: true ⇔ docker run -t — allocate a pseudo-TTY. services: shell: image: alpine command: sh stdin_open: true tty: true Set both for an interactive shell. Set only tty: true for a process that wants a terminal (for color output, line-buffered logs) but doesn’t read from stdin. stdin_open: true alone is rare — almost always paired with tty. ...

June 26, 2026 · 3 min · 610 words · Guillaume Lours

Docker Compose Tip #80: additional_contexts for multi-context builds

A Dockerfile has one build context, the directory you point docker build at. That’s enough for the vast majority of builds, but sometimes you need files from somewhere else: a base image, a separate git repository, a local directory outside the project root, or another service’s build output. additional_contexts lets you wire all of those into a single build. The basic shape Under build:, declare named contexts. Inside the Dockerfile, reference them with COPY --from=<name>: ...

June 24, 2026 · 4 min · 640 words · Guillaume Lours

Docker Compose Tip #79: docker compose run advanced flags

docker compose run creates a fresh container for a service and attaches your terminal to it. Compared to exec (Tip #34), which jumps into a running container, run is for one-shot tasks — migrations, ad-hoc scripts, REPLs, smoke tests. The flags around it decide what gets started, what gets cleaned up, and whether ports are published. –rm — clean up after exit By default, the container created by run stays around (stopped) after the command finishes. That accumulates dead containers fast in a dev loop. --rm removes the container as soon as it exits: ...

June 22, 2026 · 4 min · 684 words · Guillaume Lours

Docker Compose Tip #78: The COMPOSE_* environment variables

Almost every Compose CLI flag has an environment-variable counterpart. Setting them once in a project .env file, in your shell, or in CI removes the need to retype the same flags on every command — and makes the configuration of a stack visible to anything that reads the environment. The core set The variables you reach for most often: Variable What it sets CLI equivalent COMPOSE_FILE Path(s) to the Compose file(s) -f, --file COMPOSE_PATH_SEPARATOR Separator when listing multiple files (in COMPOSE_FILE) COMPOSE_PROJECT_NAME Project name -p, --project-name COMPOSE_PROFILES Profiles to enable --profile COMPOSE_ENV_FILES Project-level env files --env-file COMPOSE_PARALLEL_LIMIT Max parallel operations --parallel (on some subcommands) COMPOSE_IGNORE_ORPHANS Don’t warn about orphan containers (no flag) COMPOSE_REMOVE_ORPHANS Always remove orphans on up/down --remove-orphans COMPOSE_ANSI Control ANSI output (auto, never, always) --ansi COMPOSE_PROGRESS Progress style (auto, tty, plain, json, quiet) --progress COMPOSE_STATUS_STDOUT Send status messages to stdout instead of stderr (no flag) COMPOSE_MENU Disable the interactive Docker Desktop menu (no flag) The full list lives in the Compose docs. The table above covers the ones that show up in real workflows. ...

June 19, 2026 · 4 min · 702 words · Guillaume Lours

Docker Compose Tip #77: Volume subpath for mounting a sub-directory

Named volumes are great for keeping data alive across container restarts. The default behavior mounts the entire volume root at the container target. Sometimes you want to mount only a sub-directory — for instance, a single service among many sharing the same named volume, each scoped to its own directory. The subpath option does exactly that. The basic shape services: app: image: myapp volumes: - type: volume source: shared-data target: /app/data volume: subpath: app volumes: shared-data: The named volume shared-data exists once on the host. The app container sees only the app/ directory of it mounted at /app/data. Other directories in shared-data are invisible to app. ...

June 17, 2026 · 4 min · 642 words · Guillaume Lours