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 success1. V1 与 V2 版本差异
| 特性 | docker-compose (V1) | docker compose (V2) |
|---|---|---|
| 状态 | 已停止维护 (2023.06 后) | 当前标准 |
| 语言 | Python | Go |
| 集成 | 独立二进制 | 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 | # version 字段在 V2+ 规范中可选,通常省略 |
执行 docker compose up 后:
- Compose 解析配置文件
- 根据
depends_on先启动cache服务 - 构建
webapp镜像并启动容器 - 创建默认网络,
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 C2.2 环境变量管理
敏感信息应存放于 .env 文件,Compose 自动加载:
1 | # .env |
1 | # docker-compose.yml |
2.3 启动顺序与健康检查
depends_on 仅保证容器启动顺序,不保证服务就绪。需配合 healthcheck 使用:
1 | services: |
下面的流程图展示了 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 danger2.4 Profiles 按需启动
为特定场景的服务分配 profile,仅在显式指定时启动:
1 | services: |
启动命令:docker compose --profile dev up
配置方式理解后,网络配置是另一个关键环节。
3. 网络配置
3.1 Expose 与 Ports 对比
| 配置 | 作用范围 | 用途 |
|---|---|---|
ports | 宿主机 + 内部网络 | 对外暴露服务 |
expose | 仅内部网络 | 服务间通信 |
数据库等内部服务应仅使用 expose:
1 | services: |
%%{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 danger3.2 服务发现机制
Compose 网络内可直接用服务名作为主机名通信:
- ✅
redis://cache:6379 - ❌
redis://localhost:6379(容器内 localhost 指向自身)
网络配置决定了服务间如何通信,而日常操作中命令的选择同样重要。
4. 常用命令
4.1 Run 与 Exec
| 命令 | 容器生命周期 | 用途 |
|---|---|---|
run | 创建新容器,执行后销毁 | 一次性任务(迁移、安装依赖) |
exec | 进入已运行容器 | 调试、查看日志 |
1 | # 一次性安装依赖 |
4.2 Up 与 Run
| 维度 | up | run |
|---|---|---|
| 启动范围 | 所有服务 | 单个服务 |
| 端口映射 | 生效 | 默认不生效 |
| 容器生命周期 | 持续运行 | 执行后退出 |
强制端口映射:docker compose run --service-ports web
4.3 水平扩展
1 | # 启动 3 个 worker 副本 |
约束条件:
- 仅限无状态服务,不可扩展数据库等有状态服务
- 扩展服务不能定义固定宿主机端口,否则端口冲突
- 无自动伸缩能力,需手动调整副本数(自动伸缩需 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 success5. 配置复用
5.1 Include 模块化
include 可嵌入外部 Compose 文件,包括远程 Git 仓库中的配置:
1 | include: |
%%{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 run | Docker Compose | Kubernetes |
|---|---|---|---|
| 定位 | 单容器运行 | 单机多容器编排 | 集群容器编排 |
| 管理方式 | 命令式 | 声明式 YAML | 声明式 YAML |
| 伸缩性 | 手动 | 单机伸缩 | 自动水平伸缩 |
| 适用场景 | 快速测试 | 开发、测试、小型部署 | 大规模生产环境 |
7. 常见错误
以下是使用 Compose 时最容易犯的三个错误:
- 服务间通信用 localhost:容器内
localhost指向自身,应使用服务名(如cache) - 卷路径方向弄反:格式为
主机路径:容器路径(左主右容) - 扩展服务时端口冲突:扩展服务需移除固定端口映射,改用动态端口或仅
expose