Docker Compose Tip #52: Setting up a CI test environment

Your development Compose file isn’t your CI Compose file. A dedicated CI configuration ensures tests run against a clean, seeded database with no leftover state. The development stack Take a typical full-stack project like dockersamples/sbx-quickstart — a FastAPI backend with a Next.js frontend and PostgreSQL: # compose.yml services: backend: build: ./backend ports: - "8000:8000" environment: DATABASE_URL: postgresql://postgres:postgres@db:5432/devboard depends_on: db: condition: service_healthy frontend: build: ./frontend ports: - "3000:3000" db: image: postgres:16 environment: POSTGRES_PASSWORD: postgres POSTGRES_DB: devboard volumes: - db-data:/var/lib/postgresql/data healthcheck: test: ["CMD", "pg_isready"] interval: 5s retries: 5 volumes: db-data: Adding a CI override Create a compose.ci.yml that adapts the stack for testing: ...

April 13, 2026 · 3 min · 470 words · Guillaume Lours

Docker Compose Tip #50: GPU support with deploy.resources

Running ML models, video processing, or any GPU-accelerated workload? Compose lets you reserve GPU devices for specific services. Basic GPU access Give a service access to all available GPUs: services: ml-training: image: pytorch/pytorch deploy: resources: reservations: devices: - driver: nvidia count: all capabilities: [gpu] Limiting GPU count Reserve a specific number of GPUs instead of all: services: inference: image: mymodel:latest deploy: resources: reservations: devices: - driver: nvidia count: 1 capabilities: [gpu] Selecting specific GPUs by ID Target specific GPU devices when you have multiple: ...

April 8, 2026 · 2 min · 296 words · Guillaume Lours

Docker Compose Tip #46: Build args vs environment variables

Build args and environment variables both pass values to your containers, but they work at different times and serve different purposes. Mixing them up is a common source of confusion. Build args: build-time only Build args are available during docker build and are not present in the running container: services: app: build: context: . args: NODE_VERSION: "20" APP_VERSION: "2.1.0" In the Dockerfile, they’re consumed with ARG: ...

March 30, 2026 · 3 min · 471 words · Guillaume Lours

Docker Compose Tip #45: Multi-stage builds with target

Multi-stage Dockerfiles let you define multiple build stages. With the target option in Compose, you can choose which stage to build — giving you different images from the same Dockerfile. A multi-stage Dockerfile # Stage 1: dependencies FROM node:20-slim AS deps WORKDIR /app COPY package*.json ./ RUN npm ci # Stage 2: development (with dev dependencies and tools) FROM deps AS dev RUN npm install --include=dev COPY . . CMD ["npm", "run", "dev"] # Stage 3: build FROM deps AS build COPY . . RUN npm run build # Stage 4: production (minimal) FROM node:20-slim AS production WORKDIR /app COPY --from=build /app/dist ./dist COPY --from=deps /app/node_modules ./node_modules CMD ["node", "dist/index.js"] Targeting stages in Compose Use target to pick which stage to build: ...

March 27, 2026 · 2 min · 354 words · Guillaume Lours

Docker Compose Tip #44: Signal handling in containers

When you run docker compose down or docker compose stop, Compose sends a signal to your containers. Understanding which signal is sent and how your application handles it is key to graceful shutdowns. Default behavior By default, Compose sends SIGTERM to the main process (PID 1), waits 10 seconds, then sends SIGKILL: services: app: image: myapp # Default: SIGTERM, 10s grace period, then SIGKILL Changing the stop signal Some applications expect a different signal. Nginx, for example, uses SIGQUIT for graceful shutdown: ...

March 25, 2026 · 2 min · 386 words · Guillaume Lours