Docker Compose编排多容器应用

实际项目中,一个应用往往需要多个服务配合运行。Docker Compose 是管理多容器应用的标准工具,一个 YAML 文件定义所有服务。

docker-compose.yml 基本结构

version: "3.8"

services:
  web:
    image: nginx:alpine
    ports:
      - "80:80"

  app:
    build: ./app
    environment:
      - REDIS_HOST=redis

  redis:
    image: redis:6-alpine

networks:
  default:
    driver: bridge

volumes:
  data:

三个核心部分:services 定义容器、networks 定义网络、volumes 定义持久化存储。

实战:nginx + Flask + Redis

项目结构:

project/
├── docker-compose.yml
├── nginx/
│   └── nginx.conf
├── app/
│   ├── Dockerfile
│   ├── app.py
│   └── requirements.txt

app/app.py

from flask import Flask, jsonify
import redis

app = Flask(__name__)
r = redis.Redis(host='redis', port=6379, decode_responses=True)

@app.route('/')
def index():
    count = r.incr('hits')
    return jsonify({"message": "Hello", "visits": count})

@app.route('/health')
def health():
    return jsonify({"status": "ok"})

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=5000)

app/Dockerfile

FROM python:3.9-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
CMD ["python", "app.py"]

app/nequirements.txt

flask==2.0.1
redis==3.5.3

nginx/nginx.conf

upstream flask_app {
    server app:5000;
}

server {
    listen 80;
    location / {
        proxy_pass http://flask_app;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }
}

docker-compose.yml

version: "3.8"

services:
  nginx:
    image: nginx:alpine
    ports:
      - "80:80"
    volumes:
      - ./nginx/nginx.conf:/etc/nginx/conf.d/default.conf
    depends_on:
      - app
    restart: unless-stopped

  app:
    build: ./app
    expose:
      - "5000"
    environment:
      - FLASK_ENV=production
    depends_on:
      - redis
    restart: unless-stopped
    deploy:
      replicas: 2

  redis:
    image: redis:6-alpine
    volumes:
      - redis_data:/data
    command: redis-server --appendonly yes
    restart: unless-stopped

volumes:
  redis_data:

常用命令

# 启动所有服务(后台运行)
docker-compose up -d

# 查看运行状态
docker-compose ps

# 查看日志
docker-compose logs -f app

# 只重建某个服务
docker-compose up -d --build app

# 停止并删除所有容器
docker-compose down

# 停止并删除容器+数据卷(慎用)
docker-compose down -v

# 进入某个容器
docker-compose exec app sh

# 扩缩容
docker-compose up -d --scale app=3

环境变量管理

.env 文件管理环境变量:

# .env
REDIS_VERSION=6-alpine
FLASK_PORT=5000

docker-compose.yml 中引用:

services:
  redis:
    image: redis:${REDIS_VERSION}
  app:
    environment:
      - PORT=${FLASK_PORT}

depends_on 的局限

depends_on 只保证启动顺序,不保证服务就绪。Redis 启动后到可接受连接有一小段时间,app 可能连接失败。解决方案:

  1. 应用代码里做重试逻辑
  2. 使用 healthcheck + condition:
services:
  redis:
    image: redis:6-alpine
    healthcheck:
      test: ["CMD", "redis-cli", "ping"]
      interval: 5s
      retries: 3
  app:
    depends_on:
      redis:
        condition: service_healthy

小结

Docker Compose 适合开发和测试环境的多容器编排。生产环境如果需要跨主机部署、自动伸缩,应该考虑 Kubernetes。但对于中小项目,Compose 配合一台服务器完全够用。