-f merges files left to right, resolving relative paths from the first file's directory. BookNest keeps compose.yaml as the complete definition Jenkins and Kubernetes reuse, with small files on top: compose.dev.yaml for development, compose.prod.yaml for a server, and nothing extra for tests (the profile of Profiles for Optional Services). COMPOSE_FILE=compose.yaml:compose.dev.yaml in a developer's own .env makes plain docker compose commands use the development pair.
# Production: docker compose -f compose.yaml -f compose.prod.yaml up -d
services:
api:
environment:
PGPASSWORD: !reset null
PGPASSWORD_FILE: /run/secrets/db_password
secrets: [db_password]
restart: unless-stopped
deploy: { resources: { limits: { cpus: "1.0", memory: 256M } } }
develop: !reset {}
db:
ports: !reset []
environment:
POSTGRES_PASSWORD: !reset null
POSTGRES_PASSWORD_FILE: /run/secrets/db_password
secrets: [db_password]
restart: unless-stopped
deploy: { resources: { limits: { cpus: "1.0", memory: 512M } } }
secrets:
db_password:
file: ./secrets/db_password.txtmv compose.override.yaml compose.dev.yaml
P="-f compose.yaml -f compose.prod.yaml"
docker compose $P config db | grep -cE 'published|POSTGRES_PASSWORD:'
docker compose $P config api | grep -E '^ PGPASS|restart: u|memory: "2'0
memory: "268435456"
PGPASSWORD_FILE: /run/secrets/db_password
restart: unless-stopped
restart: unless-stoppedports: !reset [] removed the database's published port, since nothing outside the stack should reach PostgreSQL 1,289 on a server, and !reset null removed both plain-text passwords, replaced by a secret next. Keep such files small, or environments drift apart again.