In modern application development, it’s rare to find a single-service system. Most real-world applications rely on multiple services working together — think of a web server, database, cache, and message broker forming one cohesive stack. Managing all these containers manually can be messy. That’s where Docker Compose becomes your secret weapon.
Docker Compose is a simple yet powerful tool for defining and running multi-container Docker applications. You describe your entire stack in a single docker-compose.yml file, and with one command, you can build, start, and stop everything — from your API to your database — like clockwork.
🚀 Why Docker Compose?
Here’s why Compose is a game changer for developers and DevOps engineers alike:
- Simplified Configuration: Define your entire application stack in one YAML file.
- Quick Environment Setup: Start or tear down complete environments with a single command.
- Service Orchestration: Manage all your containers together rather than individually.
- Portability: Share and reuse the same configuration across teams and environments.
Whether you’re setting up a local dev environment, a testing pipeline, or even lightweight staging, Compose keeps things consistent and reproducible.
🧩 Anatomy of a docker-compose.yml
The docker-compose.yml file is the backbone of your setup. It defines services, networks, and volumes that together form your stack.
Here’s a simple structure:
version: '3.8'
services:
web:
build: .
ports:
- "8000:8000"
volumes:
- .:/app
depends_on:
- db
db:
image: postgres:13
environment:
POSTGRES_DB: mydatabase
POSTGRES_USER: user
POSTGRES_PASSWORD: password
volumes:
- db-data:/var/lib/postgresql/data
volumes:
db-data:
networks:
default:
# You can define custom networks here if needed
# driver: bridge
Let's break down the key sections:
version
Specifies the Compose file format version. It's important for compatibility and features. 3.8 is a commonly used recent version.
services
This is where you define the individual components (containers) of your application. Each service typically corresponds to a single container.
-
build: Specifies the path to the directory containing theDockerfilefor this service. If omitted,imagemust be specified. -
image: Specifies the Docker image to use for the service (e.g.,postgres:13,nginx:latest). -
ports: Maps host ports to container ports. Format:"HOST_PORT:CONTAINER_PORT". -
volumes: Mounts host paths or named volumes into the container for data persistence or code synchronization. Format:"HOST_PATH:CONTAINER_PATH"or"VOLUME_NAME:CONTAINER_PATH". -
environment: Sets environment variables inside the container. -
depends_on: Expresses dependency between services. Services listed here will be started before the current service. Note thatdepends_ononly ensures the order of startup, not that the dependent service is ready.
volumes
Defines named volumes that can be used by services for persistent data storage. This is crucial for databases where you don't want data to be lost when containers are removed.
networks
Defines custom networks. By default, Compose creates a default network for your application, allowing all services to communicate with each other using their service names as hostnames.
Essential Docker Compose Commands
docker compose up
Builds, (re)creates, starts, and attaches to containers for all services defined in docker-compose.yml.
Usage: docker compose up [OPTIONS] [SERVICE...]
Common Options:
-
-d: Run containers in detached mode (in the background). -
--build: Build images before starting containers.
Example: Start all services in detached mode.
docker compose up -d
docker compose down
Stops and removes containers, networks, and volumes created by up.
Usage: docker compose down [OPTIONS]
Common Options:
-
--volumes(or-v): Remove named volumes declared in thevolumessection of the Compose file.
Example: Stop and remove all services and their associated networks.
docker compose down
Example: Stop and remove services, networks, and volumes.
docker compose down -v
docker compose build
Builds or rebuilds services.
Usage: docker compose build [OPTIONS] [SERVICE...]
Example: Build the web service image.
docker compose build web
Other Useful Commands
-
docker compose ps: Lists containers for the current project. -
docker compose logs [SERVICE]: Displays log output from services. -
docker compose exec [SERVICE] COMMAND: Executes a command in a running container.
Practical Example: An Express.js Web App with PostgreSQL
Let's create a simple Python Flask application that connects to a PostgreSQL database, all managed by Docker Compose.
1. Project Structure
my-flask-app/
├── app.py
├── requirements.txt
├── Dockerfile
└── docker-compose.yml
2. app.js (Express.js Application)
const express = require('express');
const { Pool } = require('pg');
const app = express();
const port = 8000;
const pool = new Pool({
host: process.env.DB_HOST || 'db',
user: process.env.DB_USER || 'user',
password: process.env.DB_PASSWORD || 'password',
database: process.env.DB_NAME || 'mydatabase',
port: 5432,
});
app.get('/', async (req, res) => {
try {
await pool.query('SELECT 1');
res.send('Hello from Express.js! Connected to PostgreSQL successfully!');
} catch (err) {
console.error(err);
res.status(500).send(`Hello from Express.js! Could not connect to PostgreSQL: ${err.message}`);
}
});
app.listen(port, () => {
console.log(`App listening at http://localhost:${port}`);
});
3. package.json
{
"name": "my-express-app",
"version": "1.0.0",
"description": "A simple Express.js app with PostgreSQL",
"main": "app.js",
"scripts": {
"start": "node app.js"
},
"dependencies": {
"express": "^4.18.2",
"pg": "^8.11.3"
}
}
4. Dockerfile (for the Express.js app)
FROM node:18-alpine
WORKDIR /app
COPY package.json ./
RUN npm install
COPY . .
EXPOSE 8000
CMD ["npm", "start"]
5. docker-compose.yml
version: '3.8'
services:
web:
build: .
ports:
- "8000:8000"
volumes:
- .:/app
environment:
DB_HOST: db
DB_NAME: mydatabase
DB_USER: user
DB_PASSWORD: password
depends_on:
- db
db:
image: postgres:13
environment:
POSTGRES_DB: mydatabase
POSTGRES_USER: user
POSTGRES_PASSWORD: password
volumes:
- db-data:/var/lib/postgresql/data
volumes:
db-data:
How to Run This Example
- Save the files above in a directory named
my-express-app. - Navigate to the
my-express-appdirectory in your terminal. - Run
docker compose up -d. - Open your web browser and go to
http://localhost:8000. You should see the message "Hello from Express.js! Connected to PostgreSQL successfully!". - To stop and remove the services, run
docker compose down -v.
Conclusion
Docker Compose is an incredibly powerful tool for managing multi-container applications. It simplifies the development workflow, making it easier to define, run, and scale complex applications. By mastering docker-compose.yml and its associated commands, you can significantly boost your productivity and streamline your containerization efforts. Happy composing!
Top comments (0)