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 #11: Mastering docker compose up --watch for hot reload

Stop manually restarting containers when code changes. Docker Compose Watch automatically syncs files and reloads services - zero interruption development. The basics Enable watch mode with: docker compose up --watch # If you don't want mixed logs, you can run it in a dedicated process, you need to have your stack started on its own process docker compose watch Then configure watching in your compose.yml: services: web: image: node:20 command: npm start develop: watch: - path: ./src target: /app/src action: sync - path: package.json action: rebuild Files in ./src sync instantly. Changes to package.json trigger a rebuild. ...

January 19, 2026 · 2 min · 365 words · Guillaume Lours

Docker Compose Tip #10: Using init for proper PID 1 handling

Zombie processes in your containers? Slow shutdowns? Your app shouldn’t run as PID 1. Here’s the simple fix. The problem When your app runs as PID 1, it has special responsibilities: Handle system signals (SIGTERM, SIGINT) Reap zombie processes Forward signals to child processes Most apps (especially Node.js, Python) don’t handle these well. The solution Add init: true to your service: services: app: image: node:20 init: true # Adds Tini as PID 1 command: node server.js Docker automatically injects a tiny init system (Tini) that handles PID 1 responsibilities properly. ...

January 16, 2026 · 3 min · 432 words · Guillaume Lours

Docker Compose Tip #9: Publishing Compose applications as OCI artifacts

Package your entire Docker Compose application as an OCI artifact and share it through any container registry. No more complex installation instructions. The basics Publish your Compose configuration as an OCI artifact: # Publish your compose.yml to a registry docker compose publish myusername/myapp:v1.0 # Users run it directly with oci:// prefix docker compose -f oci://docker.io/myusername/myapp:v1.0 up The compose.yml (and any included files) are stored as an OCI artifact alongside your container images. ...

January 15, 2026 · 2 min · 414 words · Guillaume Lours

Docker Compose Tip #8: Healthchecks with Docker Hardened Images

Docker Hardened Images (DHI) maximize security by removing shells and package managers. But how do you add healthchecks? Use a secure sidecar with shared network namespace. The problem Your hardened Node.js application: services: app: image: dhi.io/node:25-debian13-sfw-ent-dev healthcheck: test: ["CMD", "curl", "-f", "http://localhost:3000/health"] # FAILS: No curl in hardened image! The solution: Network namespace sidecar Use a hardened curl image that shares the app’s network: services: app: image: dhi.io/node:25-debian13-sfw-ent-dev ports: - "3000:3000" environment: NODE_ENV: production app-health: image: dhi.io/curl:8-debian13-dev entrypoint: ["sleep", "infinity"] network_mode: "service:app" # Shares app's network namespace! healthcheck: test: ["CMD", "curl", "-f", "http://localhost:3000/health"] interval: 30s timeout: 3s retries: 3 start_period: 10s The network_mode: "service:app" allows the sidecar to access localhost:3000 directly - they share the same network stack! ...

January 14, 2026 · 3 min · 478 words · Guillaume Lours

Docker Compose Tip #7: Restarting single services without stopping the stack

Stop doing docker compose down && docker compose up for every code change. Docker Compose lets you restart individual services while keeping the rest running. The solution Restart just what changed: # Restart only the web service docker compose up -d web # Your database, cache, and queue keep running! This simple command saves minutes per restart. Your database keeps its data, Redis maintains its cache, message queues preserve their state. ...

January 13, 2026 · 3 min · 439 words · Guillaume Lours