AB
The third part of our Docker Compose series explores essential commands and daily operations for managing multi-container applications effectively.
Welcome to the third installment of our Docker Compose series! In Part 1, we covered the fundamentals of Docker Compose. In Part 2, we explored the anatomy of docker-compose.yml
files.
Now, let’s dive into the practical side - the essential Docker Compose commands and operations that will help you manage your containerized applications efficiently on a day-to-day basis.
Before we explore specific commands, let’s understand the general structure of Docker Compose commands:
docker-compose [OPTIONS] COMMAND [ARGS]
The most common options include:
-f, --file FILE
: Specify an alternate compose file (default: docker-compose.yml
)-p, --project-name NAME
: Specify an alternate project name (default: directory name)--profile PROFILE
: Specify a profile to enableLet’s dive into the most useful commands for daily operations:
The most basic command to start your application is:
docker-compose up
This command creates and starts all services defined in your docker-compose.yml
file. Some useful flags include:
-d, --detach
: Run containers in the background--build
: Build images before starting containers--no-deps
: Don’t start linked services--force-recreate
: Recreate containers even if their configuration hasn’t changedExample: Start your application in detached mode with rebuilt images:
docker-compose up -d --build
To stop your application:
docker-compose down
This command stops and removes containers, networks, and the default volume. Additional flags include:
-v, --volumes
: Remove named volumes declared in the volumes
section--rmi TYPE
: Remove images, where TYPE can be all
or local
--remove-orphans
: Remove containers for services not defined in the compose fileExample: Stop your application and remove volumes and local images:
docker-compose down -v --rmi local
To restart all services or specific ones:
# Restart all services
docker-compose restart
# Restart specific services
docker-compose restart web db
You can specify a timeout (in seconds) before killing the container:
docker-compose restart --timeout 30 web
To see what’s currently running:
docker-compose ps
This displays all containers and their status, ports, and command. If you want to see all containers (including stopped ones), use:
docker-compose ps -a
One of the most useful commands for troubleshooting is:
docker-compose logs
This shows the logs from all services. To make it more useful:
-f, --follow
: Follow log output--tail N
: Show only the last N linesSERVICE
: Specify service name(s) to view only those logsExample: Follow the last 100 lines of logs from the web service:
docker-compose logs -f --tail=100 web
This is incredibly useful for debugging issues in real-time.
To monitor resource usage (CPU, memory) of your containers:
docker-compose top
To build or rebuild services without starting them:
docker-compose build
Useful flags include:
--no-cache
: Don’t use cache when building the image--pull
: Always attempt to pull a newer version of the imageSERVICE
: Specify service name(s) to buildExample: Rebuild the API service without using cache:
docker-compose build --no-cache api
You can start specific services instead of the entire stack:
docker-compose up -d db redis
This is useful when you only need certain components of your application.
Similarly, you can stop specific services:
docker-compose stop web
This stops the containers without removing them.
To remove stopped service containers:
docker-compose rm
Use the -f
flag to force removal of running containers.
To run a one-off command in a service container:
docker-compose run --rm SERVICE COMMAND
The --rm
flag removes the container after the command completes.
Examples:
# Run database migrations
docker-compose run --rm backend python manage.py migrate
# Open a shell in the frontend container
docker-compose run --rm frontend bash
# Run tests
docker-compose run --rm backend npm test
To execute a command in an already running container:
docker-compose exec SERVICE COMMAND
Examples:
# Check the environment variables in a running container
docker-compose exec web env
# Get an interactive shell
docker-compose exec db psql -U postgres
# View container files
docker-compose exec app ls -la /app
The difference between run
and exec
is important:
run
creates a new container to run the commandexec
runs the command in an already running containerTo run multiple instances of a service:
docker-compose up -d --scale SERVICE=NUM
Example: Start 3 instances of the worker service:
docker-compose up -d --scale worker=3
Note that to scale services, you need to:
For example:
services:
web:
image: nginx
ports:
- "80" # Docker will assign random host ports
Before deploying changes, it’s good practice to validate your compose file:
docker-compose config
This also shows you the resolved configuration with all variables interpolated.
To check for errors only:
docker-compose config --quiet
Docker Compose automatically reads variables from a .env
file in the same directory. Use this for storing environment-specific settings:
# .env example
POSTGRES_PASSWORD=secret123
APP_ENV=development
EXTERNAL_PORT=8080
Then reference these in your compose file:
services:
web:
ports:
- "${EXTERNAL_PORT}:80"
environment:
- APP_ENV=${APP_ENV}
For different environments (development, staging, production), you can extend a base configuration using multiple compose files:
docker-compose -f docker-compose.yml -f docker-compose.prod.yml up -d
The second file will override values from the first. This allows for a DRY (Don’t Repeat Yourself) approach:
docker-compose.yml
: Base configurationdocker-compose.override.yml
: Development overrides (loaded automatically)docker-compose.prod.yml
: Production overridesTo check which ports are being used by your services:
docker-compose port SERVICE PRIVATE_PORT
Example:
docker-compose port web 80
This outputs the host port mapped to port 80 of the web service.
If you make changes to your environment variables or other configurations:
docker-compose up -d --force-recreate
This ensures fresh containers with the latest configuration.
To remove all stopped containers, unused networks, and dangling images:
docker system prune
Add -a
and --volumes
to also remove unused images and volumes (use with caution).
Let’s look at some common practical use cases for Docker Compose commands:
A typical development workflow might look like this:
# Start the development environment
docker-compose up -d
# View logs of a specific service
docker-compose logs -f app
# Run tests in the test container
docker-compose run --rm test npm run test
# Make code changes locally...
# Rebuild and restart the affected service
docker-compose up -d --build app
# When done, shut down the environment
docker-compose down
Working with databases is a common task:
# Start just the database
docker-compose up -d db
# Run a database migration
docker-compose run --rm app ./manage.py migrate
# Connect to the database with a client
docker-compose exec db psql -U postgres
# Create a database backup
docker-compose exec db pg_dump -U postgres > backup.sql
# Restore from backup
cat backup.sql | docker-compose exec -T db psql -U postgres
The -T
flag in the last command disables pseudo-TTY allocation, which is necessary when piping input to the container.
When things go wrong, these commands help diagnose issues:
# Check container status
docker-compose ps
# See container logs
docker-compose logs -f --tail=100
# Check resource usage
docker-compose top
# Get a shell in the problematic container
docker-compose exec app bash
# Inspect network settings
docker network inspect docker-compose_default
Based on the commands we’ve explored, here are some best practices:
--build
flag when changes are madeAlways use --build
when you’ve made changes to your Dockerfile or source code:
docker-compose up -d --build
If you have services that aren’t always needed (like monitoring tools), use profiles:
services:
app:
image: myapp
monitoring:
image: prometheus
profiles:
- monitoring
Then start only when needed:
docker-compose --profile monitoring up -d
.env
files for environment-specific variablesKeep secrets and environment-specific configuration in .env
files, which should not be committed to version control.
Ensure services wait for dependencies properly:
services:
app:
depends_on:
db:
condition: service_healthy
db:
healthcheck:
test: ["CMD", "pg_isready", "-U", "postgres"]
interval: 5s
timeout: 5s
retries: 5
Prevent resource exhaustion by cleaning up unused resources:
docker-compose down -v
docker system prune
Track changes to your compose files in git, making it easier to roll back changes if needed.
If your containers exit immediately after starting:
docker-compose logs SERVICE
If you see errors like “port is already allocated”:
lsof -i :PORT
If containers can’t communicate:
docker network inspect NETWORK
docker-compose exec service1 ping service2
If you see permission denied errors with volumes:
Use:
docker-compose up -d --no-deps --build SERVICE
The --no-deps
flag ensures dependent services aren’t also restarted.
While Docker Compose can be used in production for simple setups, tools like Docker Swarm or Kubernetes are generally recommended for production deployments. That said, many companies successfully use Compose in production for smaller applications.
Use:
docker-compose config
This shows the interpolated compose file with all variables resolved.
Use resource constraints in your compose file:
services:
app:
image: myapp
deploy:
resources:
limits:
cpus: "0.5"
memory: 512M
reservations:
cpus: "0.25"
memory: 256M
Docker Compose is also valuable in Continuous Integration and Continuous Deployment pipelines:
# Example GitLab CI/CD pipeline using Docker Compose
stages:
- test
- build
test:
stage: test
script:
- docker-compose -f docker-compose.test.yml up --build --exit-code-from tests
- docker-compose -f docker-compose.test.yml down
build:
stage: build
script:
- docker-compose build
- docker-compose push
The --exit-code-from SERVICE
flag makes the up
command return the exit code from a specific service, which is perfect for test runners.
In this article, we’ve explored the essential Docker Compose commands for managing your containerized applications, from basic lifecycle management to advanced operations and troubleshooting.
In Part 4, our final installment, we’ll dive into advanced Docker Compose topics, including using Docker Compose with Swarm mode, creating production-ready configurations, implementing CI/CD pipelines, and optimizing your Docker Compose workflows.
Continue to Part 4: Advanced Topics and Production Deployment or go back to Part 2: Anatomy of docker-compose.yml Files