5_DockerCompose实践指南

Docker Compose 将多容器应用的配置集中到一份 YAML 文件中,通过 docker compose up/down 一键创建或销毁整个运行环境,确保团队成员在相同配置下获得一致的开发、测试体验。

%%{init: {'theme': 'base', 'themeVariables': { 'primaryColor': '#3B82F6', 'primaryTextColor': '#1E3A5F', 'primaryBorderColor': '#2563EB', 'lineColor': '#60A5FA', 'secondaryColor': '#10B981', 'tertiaryColor': '#F59E0B'}}}%%
flowchart LR
    A["docker-compose.yml"] --> B["docker compose up"]
    B --> C["创建网络"]
    B --> D["拉取/构建镜像"]
    B --> E["启动容器"]
    C --> F["多容器应用运行"]
    D --> F
    E --> F

    classDef primary fill:#3B82F6,stroke:#2563EB,color:#fff
    classDef success fill:#10B981,stroke:#059669,color:#fff
    class A primary
    class F success

1. V1 与 V2 版本差异

特性docker-compose (V1)docker compose (V2)
状态已停止维护 (2023.06 后)当前标准
语言PythonGo
集成独立二进制Docker CLI 插件
性能一般启动更快,并发效率更高

V2 用 Go 重写,与 Docker 引擎深度集成,直接复用 CLI 上下文和认证机制。V1 已于 2023 年 6 月停止维护,新项目应一律使用 V2。

版本差异明确后,接下来看配置文件的核心结构。

2. 核心配置结构

docker-compose.yml 包含三个顶层配置块:

mindmap
  root["docker-compose.yml"]
    services
      定义各服务容器
      构建方式/镜像
      端口/环境变量
    networks
      服务间通信网络
      自定义网络拓扑
    volumes
      数据持久化存储
      主机挂载/命名卷

2.1 配置示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# version 字段在 V2+ 规范中可选,通常省略
services:
webapp:
build: .
ports:
- "8080:80"
volumes:
- .:/app
environment:
- REDIS_HOST=cache
depends_on:
- cache

cache:
image: "redis:alpine"

执行 docker compose up 后:

  1. Compose 解析配置文件
  2. 根据 depends_on 先启动 cache 服务
  3. 构建 webapp 镜像并启动容器
  4. 创建默认网络,webapp 可通过主机名 cache 访问 Redis
%%{init: {'theme': 'base', 'themeVariables': {'actorBkg': '#3B82F6', 'actorTextColor': '#1E3A5F', 'actorBorder': '#2563EB', 'signalColor': '#60A5FA', 'activationBkgColor': '#DBEAFE', 'activationBorderColor': '#3B82F6'}}}%%
sequenceDiagram
    autonumber
    participant U as "用户"
    participant C as "Compose"
    participant N as "网络"
    participant S1 as "cache"
    participant S2 as "webapp"

    U->>C: "docker compose up"
    activate C
    C->>N: "创建默认网络"
    C->>S1: "启动 cache 容器"
    activate S1
    C->>S2: "构建并启动 webapp"
    activate S2
    S2->>S1: "通过 cache:6379 连接"
    C-->>U: "所有服务就绪"
    deactivate C

2.2 环境变量管理

敏感信息应存放于 .env 文件,Compose 自动加载:

1
2
# .env
POSTGRES_PASSWORD=mysecretpassword
1
2
3
4
5
6
# docker-compose.yml
services:
db:
image: postgres
environment:
- POSTGRES_PASSWORD=${POSTGRES_PASSWORD}

2.3 启动顺序与健康检查

depends_on 仅保证容器启动顺序,不保证服务就绪。需配合 healthcheck 使用:

1
2
3
4
5
6
7
8
9
10
11
12
13
services:
db:
image: postgres
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 5s
timeout: 5s
retries: 5

webapp:
depends_on:
db:
condition: service_healthy

下面的流程图展示了 depends_on + healthcheck 的完整启动判定逻辑:

%%{init: {'theme': 'base', 'themeVariables': { 'primaryColor': '#3B82F6', 'primaryTextColor': '#1E3A5F', 'primaryBorderColor': '#2563EB', 'lineColor': '#60A5FA', 'secondaryColor': '#10B981', 'tertiaryColor': '#F59E0B'}}}%%
flowchart TD
    A["docker compose up"] --> B["启动 db 容器"]
    B --> C{"healthcheck 通过?"}
    C -->|"是"| D["启动 webapp 容器"]
    C -->|"否, 重试中"| E["等待 interval 后重试"]
    E --> C
    C -->|"超过 retries"| F["标记 unhealthy, webapp 不启动"]
    D --> G["所有服务就绪"]

    classDef primary fill:#3B82F6,stroke:#2563EB,color:#fff
    classDef success fill:#10B981,stroke:#059669,color:#fff
    classDef warning fill:#F59E0B,stroke:#D97706,color:#fff
    classDef danger fill:#EF4444,stroke:#DC2626,color:#fff

    class A primary
    class G success
    class E warning
    class F danger

2.4 Profiles 按需启动

为特定场景的服务分配 profile,仅在显式指定时启动:

1
2
3
4
5
6
services:
web:
image: nginx
mailhog:
image: mailhog/mailhog
profiles: ["dev"]

启动命令:docker compose --profile dev up

配置方式理解后,网络配置是另一个关键环节。

3. 网络配置

3.1 Expose 与 Ports 对比

配置作用范围用途
ports宿主机 + 内部网络对外暴露服务
expose仅内部网络服务间通信

数据库等内部服务应仅使用 expose

1
2
3
4
5
6
services:
database:
image: postgres
expose:
- "5432"
# 无 ports,禁止外部直接访问
%%{init: {'theme': 'base', 'themeVariables': { 'primaryColor': '#3B82F6', 'primaryTextColor': '#1E3A5F', 'primaryBorderColor': '#2563EB', 'lineColor': '#60A5FA', 'secondaryColor': '#10B981', 'tertiaryColor': '#F59E0B'}}}%%
flowchart TB
    subgraph Host ["宿主机"]
        P["ports: 8080"]
    end

    subgraph Network ["Compose 内部网络"]
        W["webapp"]
        D["database (expose: 5432)"]
    end

    External["外部访问"] --> P
    P --> W
    W --> D
    External -.->|"禁止"| D

    classDef primary fill:#3B82F6,stroke:#2563EB,color:#fff
    classDef danger fill:#EF4444,stroke:#DC2626,color:#fff
    class W primary
    class D danger

3.2 服务发现机制

Compose 网络内可直接用服务名作为主机名通信:

  • redis://cache:6379
  • redis://localhost:6379(容器内 localhost 指向自身)

网络配置决定了服务间如何通信,而日常操作中命令的选择同样重要。

4. 常用命令

4.1 Run 与 Exec

命令容器生命周期用途
run创建新容器,执行后销毁一次性任务(迁移、安装依赖)
exec进入已运行容器调试、查看日志
1
2
3
4
5
# 一次性安装依赖
docker compose run --rm webapp npm install

# 进入运行中的数据库容器
docker compose exec database bash

4.2 Up 与 Run

维度uprun
启动范围所有服务单个服务
端口映射生效默认不生效
容器生命周期持续运行执行后退出

强制端口映射:docker compose run --service-ports web

4.3 水平扩展

1
2
# 启动 3 个 worker 副本
docker compose up -d --scale worker=3

约束条件:

  1. 仅限无状态服务,不可扩展数据库等有状态服务
  2. 扩展服务不能定义固定宿主机端口,否则端口冲突
  3. 无自动伸缩能力,需手动调整副本数(自动伸缩需 Kubernetes HPA)

Compose 内置 DNS 对多副本自动进行轮询负载均衡,请求流向如下:

%%{init: {'theme': 'base', 'themeVariables': { 'primaryColor': '#3B82F6', 'primaryTextColor': '#1E3A5F', 'primaryBorderColor': '#2563EB', 'lineColor': '#60A5FA', 'secondaryColor': '#10B981', 'tertiaryColor': '#F59E0B'}}}%%
flowchart LR
    A["webapp"] -->|"worker:8080"| DNS["Compose DNS"]
    DNS -->|"轮询"| W1["worker-1"]
    DNS -->|"轮询"| W2["worker-2"]
    DNS -->|"轮询"| W3["worker-3"]

    classDef primary fill:#3B82F6,stroke:#2563EB,color:#fff
    classDef success fill:#10B981,stroke:#059669,color:#fff
    classDef info fill:#0EA5E9,stroke:#0284C7,color:#fff

    class A primary
    class DNS info
    class W1,W2,W3 success

5. 配置复用

5.1 Include 模块化

include 可嵌入外部 Compose 文件,包括远程 Git 仓库中的配置:

1
2
3
4
5
6
7
8
9
include:
- path: ./common-services/postgres.yml
- path: ./common-services/redis.yml
- project: my-monitoring-stack
path: git@github.com:my-org/infra-compose.git/logging-stack/compose.yml

services:
my-app:
build: .
%%{init: {'theme': 'base', 'themeVariables': { 'primaryColor': '#3B82F6', 'primaryTextColor': '#1E3A5F', 'primaryBorderColor': '#2563EB', 'lineColor': '#60A5FA', 'secondaryColor': '#10B981', 'tertiaryColor': '#F59E0B'}}}%%
flowchart TD
    A["主 compose.yml"] -->|"include"| B["postgres.yml"]
    A -->|"include"| C["redis.yml"]
    A -->|"include (Git)"| D["远程 logging-stack"]
    A --> E["my-app 服务"]
    B --> F["最终合并配置"]
    C --> F
    D --> F
    E --> F

    classDef primary fill:#3B82F6,stroke:#2563EB,color:#fff
    classDef success fill:#10B981,stroke:#059669,color:#fff
    classDef info fill:#0EA5E9,stroke:#0284C7,color:#fff

    class A primary
    class F success
    class B,C,D info

单机场景下 Compose 已满足大部分需求,但面对集群级部署时如何选择?

6. 与 Kubernetes 对比

%%{init: {'theme': 'base', 'themeVariables': { 'primaryColor': '#3B82F6'}}}%%
quadrantChart
    title 容器编排工具定位
    x-axis "单机" --> "集群"
    y-axis "简单" --> "复杂"
    quadrant-1 "生产级编排"
    quadrant-2 "企业级方案"
    quadrant-3 "开发测试"
    quadrant-4 "学习曲线陡"
    "docker run": [0.1, 0.15]
    "Docker Compose": [0.2, 0.4]
    "Docker Swarm": [0.5, 0.5]
    "Kubernetes": [0.9, 0.85]
特性docker runDocker ComposeKubernetes
定位单容器运行单机多容器编排集群容器编排
管理方式命令式声明式 YAML声明式 YAML
伸缩性手动单机伸缩自动水平伸缩
适用场景快速测试开发、测试、小型部署大规模生产环境

7. 常见错误

以下是使用 Compose 时最容易犯的三个错误:

  1. 服务间通信用 localhost:容器内 localhost 指向自身,应使用服务名(如 cache
  2. 卷路径方向弄反:格式为 主机路径:容器路径(左主右容)
  3. 扩展服务时端口冲突:扩展服务需移除固定端口映射,改用动态端口或仅 expose

8. 参考资料