Automating Infrastructure with Docker Compose

shellgear shellgear #infrastructure#automation#docker

A practical guide to containerizing services and managing them with Docker Compose, from development to production.

This article explores how to use Docker Compose to automate the deployment and management of self-hosted services. We’ll cover the basics of writing a docker-compose.yml file, managing volumes and networks, and setting up a simple production workflow.

Why Docker Compose?

Docker Compose provides a declarative way to define multi-container applications. Instead of running multiple docker run commands, you describe your entire stack in a single YAML file.

Key benefits:

  • Reproducibility: The same docker-compose.yml works on any machine with Docker installed.
  • Simplicity: One command to start, stop, or restart the entire stack.
  • Isolation: Services run in separate containers with their own dependencies.

A Basic Example

Let’s start with a simple stack: a web application and a database.

version: "3.8"
services:
web:
build: ./web
ports:
- "8080:80"
volumes:
- ./web:/app
depends_on:
- db
db:
image: postgres:15
environment:
POSTGRES_USER: app
POSTGRES_PASSWORD: secret
volumes:
- db_data:/var/lib/postgresql/data
volumes:
db_data:

This file defines two services:

  1. web: Built from a local Dockerfile, with hot-reload enabled via volume mounting.
  2. db: A PostgreSQL container with persistent storage.

To start the stack:

Terminal window
docker-compose up -d

To stop it:

Terminal window
docker-compose down

To stop and remove volumes:

Terminal window
docker-compose down -v

Best Practices

Use Named Volumes

Named volumes (like db_data) persist data across container recreation. Avoid binding to host paths for production data.

Environment Variables for Secrets

Never hardcode passwords in docker-compose.yml. Use environment variables:

services:
db:
image: postgres:15
environment:
POSTGRES_PASSWORD: ${DB_PASSWORD}

Then run:

Terminal window
DB_PASSWORD=secret docker-compose up -d

Or use a .env file (which should be in .gitignore):

DB_PASSWORD=secret

Health Checks

Add health checks to ensure services are actually ready before dependent services start:

services:
db:
image: postgres:15
healthcheck:
test: ["CMD-SHELL", "pg_isready -U app"]
interval: 10s
timeout: 5s
retries: 5

Going Further

In future articles, we’ll explore:

  • Reverse proxies with Traefik or Caddy
  • Secrets management with Docker Swarm or external tools
  • CI/CD pipelines for containerized deployments

Conclusion

Docker Compose is a powerful tool for automating infrastructure. Start small, iterate, and gradually add complexity as your needs grow.