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

Docker Compose Tip #6: Service discovery and internal DNS

Hardcoding IP addresses in your containers? Docker Compose provides automatic DNS-based service discovery. Each service can reach another using just the service name. How it works Docker Compose creates a default network and registers each container with an internal DNS server. The DNS name matches the service name in your compose.yml. services: web: image: nginx environment: # Just use the service name! API_URL: http://api:3000 DB_HOST: postgres api: image: myapi environment: DATABASE_URL: postgres://user:pass@postgres:5432/mydb postgres: image: postgres:15 No configuration needed. The web service connects to api using http://api:3000, and api connects to postgres using the hostname postgres. ...

January 12, 2026 · 2 min · 344 words · Guillaume Lours

Docker Compose Tip #5: Writing Compose files for AI tools

AI tools work better when they understand the setup. Here’s how to document Compose files effectively. Add context with comments Comments help AI understand what each service does: services: # Primary web application serving React frontend # Handles user authentication and API gateway web: image: myapp:latest ports: - "3000:3000" # Public facing port - update in .env for production environment: # Connection string to PostgreSQL - format: postgresql://user:pass@host:5432/db DATABASE_URL: ${DATABASE_URL} # JWT secret for auth - must be at least 256 bits JWT_SECRET: ${JWT_SECRET} depends_on: db: condition: service_healthy # Development only - remove for production volumes: - ./src:/app/src # Hot reload for development # PostgreSQL 15 database with PostGIS extension # Stores user data and geographic information db: image: postgis/postgis:15-3.3 environment: POSTGRES_DB: myapp POSTGRES_PASSWORD: ${DB_PASSWORD} # Never commit actual password volumes: # Initial schema and seed data - ./init.sql:/docker-entrypoint-initdb.d/01-init.sql # Persistent data storage - postgres_data:/var/lib/postgresql/data volumes: postgres_data: # Named volume for database persistence across container restarts File headers For bigger projects, add a header: ...

January 9, 2026 · 3 min · 436 words · Guillaume Lours

Docker Compose Tip #4: Using SSH keys during build

Need to access private Git repositories during build? Here’s how to do it securely with SSH. The setup Enable SSH forwarding in your compose.yml: services: app: build: context: . ssh: - default # Uses your default SSH agent Or use specific keys for different services: services: app: build: context: . ssh: - github=/home/user/.ssh/github_key # Custom key for GitHub - gitlab=/home/user/.ssh/gitlab_key # Different key for GitLab The Dockerfile Use BuildKit’s SSH mount to clone private repos: ...

January 8, 2026 · 2 min · 293 words · Guillaume Lours