Docker Compose:编排多容器应用

FreeGuideOnline 最新 2026-06-13

Docker Compose 多容器管理

概述

Docker Compose 是 Docker 官方提供的用于定义和运行多容器应用的工具。通过一个 YAML 文件,你可以配置应用需要的所有服务、网络和数据卷,然后使用一条命令即可启动并管理整个栈。对于微服务架构、开发环境和测试场景,Compose 能极大简化容器编排工作。


为什么需要 Docker Compose?

单独使用 docker run 启动多个容器时,你需要手动管理复杂的选项、网络和依赖关系。Compose 实现了 基础设施即代码,将多容器配置版本化、可重复执行,并支持:

  • 声明式配置:清晰描述服务、端口、环境变量等。
  • 一键启动/停止:整个栈的生命周期管理。
  • 开发便捷性:快速重建、日志聚合、服务隔离。
  • 生产过渡:Compose 文件可扩展到 Swarm 集群。

安装 Docker Compose

Docker Compose 现已集成到 Docker CLI 中(Docker Compose V2 作为插件)。新版本推荐使用 docker compose(无中划线)命令。

Linux(Ubuntu/Debian)

# 安装 Docker 引擎(包含 Compose 插件)
sudo apt update
sudo apt install docker.io docker-compose-plugin -y
# 验证
docker compose version

macOS / Windows

安装 Docker Desktop 即自动包含 Docker Compose,无需额外操作。

注意:旧版独立的 docker-compose(Python 编写)仍可使用,但官方推荐迁移到 Compose V2 插件。


核心概念

概念 说明
服务(services) 一个容器化的应用组件(如 web 服务、数据库),定义镜像、端口等。
网络(networks) 允许服务间通信,默认创建 bridge 网络。
卷(volumes) 持久化数据,可被多个服务共享或挂载。
项目(project) 由一个 Compose 文件定义的一组服务,默认用目录名作为项目名。

编写 docker-compose.yml

下面是一个经典的 Web 应用 + Redis 示例,包含两个服务。

version: "3.9"   # Compose 文件格式版本(兼容性说明见下文)
services:
  web:
    build: ./web                # 从当前目录下的 web/ 构建镜像
    ports:
      - "8080:80"               # 主机端口:容器端口
    environment:
      - REDIS_HOST=redis        # 服务名作为主机名,Compose 自动解析
    depends_on:
      - redis                   # 启动顺序依赖,但不等待 Redis 就绪
  redis:
    image: redis:7-alpine       # 直接使用官方镜像
    volumes:
      - redis-data:/data        # 挂载命名卷持久化数据

volumes:
  redis-data:                   # 声明卷,默认由 Compose 管理

文件格式版本说明

version 字段对应 Compose 文件格式,推荐使用 3.9(兼容最新 Docker 引擎)。Docker Compose V2 实际上已弱化此要求,但仍建议保留以避免警告。


常用命令

所有命令需在有 docker-compose.yml 的目录下执行(或通过 -f 指定文件)。

命令 功能
docker compose up 创建并启动所有服务(前台运行)
docker compose up -d 后台运行所有服务
docker compose down 停止并移除容器、网络(保留数据卷)
docker compose down -v 同时删除匿名卷和命名卷(谨慎!)
docker compose ps 列出项目中的容器及状态
docker compose logs -f [service] 实时查看服务日志
docker compose build 重新构建服务的镜像
docker compose restart [service] 重启指定服务
docker compose exec service sh 进入正在运行的服务容器内部
docker compose start / stop 启动/停止已有容器,不会重建

服务间通信与网络

默认情况下,Compose 为你的应用创建一个独立的网络,所有服务均可通过服务名互相访问。例如 web 服务连接 redis 时,只需将主机名设为 redis,Docker 的内置 DNS 会自动解析。

你也可以自定义网络以实现更精细的控制:

networks:
  frontend:
  backend:

services:
  web:
    networks:
      - frontend
      - backend
  redis:
    networks:
      - backend

此时 web 同时连接前端和后端网络,而 redis 仅在后端网络中,前端网络无法直接访问 redis


数据卷与持久化

  • 命名卷:在顶层 volumes 声明,由 Docker 管理,适合数据库存储。
  • 绑定挂载:直接挂载主机路径,适合开发时实时同步代码。
services:
  app:
    volumes:
      - ./src:/app/src          # 绑定挂载,主机当前 src/ 映射到容器 /app/src
      - node_modules:/app/node_modules  # 命名卷,防止模块被挂载覆盖
volumes:
  node_modules:

环境变量与配置文件

直接定义

services:
  db:
    environment:
      - MYSQL_ROOT_PASSWORD=secret
      - MYSQL_DATABASE=myapp

引用 .env 文件

在项目根目录创建 .env 文件,键值对会被 Compose 自动加载(但需在 YAML 中显式引用):

# .env
MYSQL_ROOT_PASSWORD=supersecret
services:
  db:
    environment:
      - MYSQL_ROOT_PASSWORD=${MYSQL_ROOT_PASSWORD}

使用 env_file

services:
  app:
    env_file:
      - ./config/app.env

多环境与覆盖文件

利用多个 Compose 文件叠加配置,实现开发/生产分离。

基础文件 docker-compose.yml

services:
  web:
    image: myapp:latest
    ports:
      - "80:80"

生产覆盖 docker-compose.prod.yml

services:
  web:
    environment:
      - ENV=production
    restart: always

启动时指定多个文件(右侧文件覆盖左侧):

docker compose -f docker-compose.yml -f docker-compose.prod.yml up -d

开发者友好功能

实时重载与开发伺服

结合绑定挂载和文件监视工具(如 nodemon, webpack-dev-server),容器内代码修改可即时生效。

services:
  dev:
    build: .
    volumes:
      - .:/app
    command: npm run dev   # 启动带热重载的开发服务器
    ports:
      - "3000:3000"

容器内执行一次性任务

services:
  migration:
    build: .
    command: python manage.py migrate
    depends_on:
      - db

up 时该服务会执行并退出,不会长期运行。


实战:构建一个简单的微服务栈

目标:用 Python Flask + Redis + Nginx 搭建一个计数器应用。

项目结构:

myapp/
├── docker-compose.yml
├── web/
│   ├── Dockerfile
│   └── app.py
└── nginx/
    └── nginx.conf

1. web 服务(Flask)

web/app.py

from flask import Flask
import redis
import os

app = Flask(__name__)
cache = redis.Redis(host=os.getenv('REDIS_HOST', 'redis'), port=6379)

@app.route('/')
def hello():
    count = cache.incr('hits')
    return f'Hello! This page has been visited {count} times.'

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

web/Dockerfile

FROM python:3.10-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install flask redis
COPY . .
CMD ["python", "app.py"]

2. Nginx 反向代理

nginx/nginx.conf

server {
    listen 80;
    location / {
        proxy_pass http://web:5000;   # 使用服务名
        proxy_set_header Host $host;
    }
}

3. Compose 编排文件

version: "3.9"
services:
  web:
    build: ./web
    environment:
      - REDIS_HOST=redis
    networks:
      - backend

  redis:
    image: redis:alpine
    networks:
      - backend

  nginx:
    image: nginx:alpine
    ports:
      - "80:80"
    volumes:
      - ./nginx/nginx.conf:/etc/nginx/conf.d/default.conf:ro
    depends_on:
      - web
    networks:
      - frontend
      - backend

networks:
  frontend:
  backend:

4. 启动应用

docker compose up -d

浏览器访问 http://localhost,刷新即可看到访问计数递增。


常见问题与调试技巧

问题 排查方式
服务无法启动 docker compose logs <service> 查看日志
服务间连通失败 docker compose exec <service> ping <target> 测试 DNS 解析
端口冲突 检查主机端口,修改 ports 左侧端口或停止占用进程
镜像未更新 docker compose build --no-cache 强制重新构建
数据卷权限错误 注意容器内用户 UID/GID,或使用 user: 映射

从旧版 docker-compose 迁移

  • 命令从 docker-compose 改为 docker compose(不带连字符)。
  • 移除 Compose 文件中的 version(可选,但保留无害)。
  • V2 支持更快的构建和 GPU 设备等高级特性,完全向下兼容。

最佳实践总结

  1. 保持 Compose 文件简洁:一个文件定义核心服务,通过覆盖文件处理环境差异。
  2. 显式声明资源:为关键服务配置 restart: unless-stopped 保证自愈。
  3. 使用 .env 管理敏感信息,切勿将密钥硬编码并提交到版本控制。
  4. 利用 depends_on 结合健康检查(使用 condition: service_healthy)确保就绪顺序。
  5. 生产环境考虑扩展:结合 docker compose up --scale web=3 水平扩缩,但需配合负载均衡。

掌握 Docker Compose 意味着你可以用代码化、可重复的方式管理整个容器生态,从本地开发到部署流水线都受益匪浅。