Orchestrating Multi-Container Applications with Docker Compose
Docker Compose Overview
Problem Statement
When working with Docker, complex applications typically require multiple services running simultaneously. A typical Django project might need MySQL, Redis, and other dependencies. Maanging these as separate containers individual becomes cumbersome and error-prone. Docker Compose solves this problem by providing a tool to define and manage multiple containers as a single application.
Key Capabilities
Docker Compose is a tool for defining and running multi-container Docker applications. It uses YAML files to configure application services and allows you to start and stop all services with a single command.
Container Orchestration Options:
| Type | Tool |
|---|---|
| Single-host orchestration | Docker Compose |
| Multi-host orchestration | Docker Swarm, Kubernetes |
Installation
Download the Docker Compose binary from the official GitHub repository:
wget https://github.com/docker/compose/releases/download/v2.15.1/docker-compose-linux-x86_64
sudo cp ./docker-compose-linux-x86_64 /usr/local/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-compose
Add the binary to your system PATH by placing it in /usr/local/bin, enabling execution from any directory.
Permission Model
Owner Group Others
rwx rwx rwx
Example permission commands:
chmod 777 filename # Full permissions for all
chmod +x filename # Add execute permission
chmod 555 filename # Read and execute for all
Essential Commands
| Command | Description |
|---|---|
docker-compose up |
Start services (searches for compose file in current directory) |
docker-compose -f <file> up |
Start services using specified file |
docker-compose up -d |
Run in detached mode (background) |
docker-compose up -d --build |
Rebuild images and start containers |
docker-compose stop |
Stop containers without removal |
docker-compose down |
Stop and remove containers |
docker-compose start |
Start managed containers |
docker-compose ps |
List running containers |
docker-compose images |
List managed images |
docker-compose exec <service> /bin/bash |
Shell into a service container |
Docker Installation (CentOS)
sudo yum install -y yum-utils
sudo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
sudo yum install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
Deploying a Flask Application
Project Structure
A Flask application with Redis requires two containers: the Flask application and the Redis cache.
Application Code (app.py)
from flask import Flask
from redis import Redis
app = Flask(__name__)
redis_client = Redis(host='redis', port=6379)
@app.route('/')
def index():
redis_client.incr('visits')
return f'Page visited {redis_client.get("visits").decode()} times\n'
if __name__ == "__main__":
app.run(host="0.0.0.0", port=5000, debug=True)
Service names in the compose file become hostname aliases. The Flask container can reach Redis using the hostname redis.
Dockerfile
FROM python:3.10
WORKDIR /app
COPY . /app
RUN pip install flask redis -i https://pypi.tuna.tsinghua.edu.cn/simple
EXPOSE 5000
CMD [ "python", "app.py" ]
Docker Compose Configuration
version: "3"
services:
redis:
image: redis
web:
build:
context: .
dockerfile: Dockerfile
ports:
- 8080:5000
environment:
REDIS_HOST: redis
Deployment
docker-compose up
This single command performs the following:
- Builds the Flask image from Dockerfile
- Pulls the Redis image if not present
- Starts both containers on a shared network
Containers can communicate using service names as hostnames. Verify connectivity:
# Enter web container
docker-compose exec web /bin/bash
# Inside container
apt-get update && apt-get install -y inetutils-ping
ping redis
Deploying a Full-Stack Application
Architecture
A complete deployment typically includes:
- Django API: Python 3.8 runtime with uWSGI
- Nginx: Web server and reverse proxy
- MySQL: Database server
- Redis: Caching layer
Each component runs in its own container.
Project Layout
project/
├── docker-compose.yml
├── docker_config/
│ ├── nginx/
│ ├── redis/
│ └── mysql.env
├── api_service/
│ ├── Dockerfile
│ └── uwsgi.ini
└── frontend/
└── dist/
API Service Dockerfile
FROM python:3.8
WORKDIR /app
COPY requirements.txt /app/requirements.txt
RUN pip install -r requirements.txt -i https://pypi.doubanio.com/simple
CMD ["uwsgi", "./uwsgi.ini"]
Complete Docker Compose Configuration
version: "3"
services:
nginx:
image: nginx
container_name: app_nginx
ports:
- "80:80"
- "8000:8000"
restart: always
volumes:
- ./frontend/dist:/var/www/html
- ./docker_config/nginx:/etc/nginx/conf.d
depends_on:
- django
networks:
- frontend_net
django:
build:
context: ./api_service
dockerfile: Dockerfile
container_name: app_django
restart: always
ports:
- "8080:8080"
volumes:
- ./api_service:/app
environment:
- TZ=Asia/Shanghai
depends_on:
- mysql
- redis
networks:
- frontend_net
- backend_net
redis:
image: redis:6.0-alpine
container_name: app_cache
ports:
- "6379:6379"
volumes:
- ./docker_config/redis/data:/data
- ./docker_config/redis/redis.conf:/etc/redis/redis.conf
command: redis-server /etc/redis/redis.conf
networks:
- backend_net
mysql:
image: mysql:5.7
container_name: app_database
restart: always
ports:
- "3306:3306"
env_file:
- ./docker_config/mysql.env
volumes:
- ./docker_config/mysql/data:/var/lib/mysql
- ./docker_config/mysql/logs:/var/log/mysql
- ./docker_config/mysql/conf:/etc/mysql/conf.d
networks:
- backend_net
networks:
frontend_net:
backend_net:
Deployment Steps
- Prepare the frontend build:
cd frontend
npm install
npm run build
- Clone and configure on the target server:
git clone <repository>
cd project
docker-compose up -d
- Access the application at
http://<server-ip>:80