Compose 是 Docker 官方推出的多容器编排工具——把一组容器 / 网络 / 卷 / 配置用一份 YAML 描述,docker compose up 一键拉起。从 v1(Python 实现)到 v2(Go 插件化,2020-08 GA)经历了一次大重构,v2 速度更快、不再是 Python 副作用、字段语义和 v1 大体兼容。
这一篇把 compose 文件的所有常用字段按 services / networks / volumes 三大块组织成速查字典,配实战示例。
阅读对象:用 docker compose 编排多服务、想系统了解每个字段的开发者 / 运维
覆盖范围:compose v1 vs v2 差异 + service 字段字典 + networks / volumes 顶层 + 实战 YAML + compose 常用命令
一、Compose v1 vs v2:先搞清楚用哪个
| 维度 | v1 | v2 |
|---|
| 命令 | docker-compose(带横线) | docker compose(空格) |
| 实现 | Python | Go(Docker CLI 插件) |
| 启动速度 | 慢(要启 Python 解释器) | 快(Go 二进制) |
| Compose Spec | 1.x - 3.x | 3.8+ 兼容 Spec |
| K8s 集成 | 实验性 kompose | 内置 docker compose convert |
| 维护 | 已停止新特性 | 当前主推 |
2023 年后:docker compose (v2) 是事实标准。新项目不要再用 v1。
二、Compose 文件结构总览
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
| # 顶层 keys(按规范顺序)
version: "3.8" # 文件格式版本(v2 中可选,但建议保留)
name: "my-project" # v2.20+ 项目名(影响容器前缀)
services: # 必填:所有服务
web:
image: nginx:latest
# ... 50+ 字段
networks: # 可选:自定义网络
frontend:
backend:
volumes: # 可选:命名卷
db-data:
configs: # 可选:配置文件
app-config:
secrets: # 可选:密钥
db-password:
|
Spec 是什么:Compose Spec 是 v2.0 起的"格式规范"——docker compose、Kompose、docker stack deploy、podman compose 都按这个规范解析 YAML。比 v1 的 version: 3.x 更通用。
三、service 字段字典
3.1 镜像 / 构建
| 字段 | 作用 | 版本 |
|---|
image | 指定镜像 | 全部 |
build | 构建路径或对象 | 全部 |
build.context | Dockerfile 所在目录 | v2 起 |
build.dockerfile | Dockerfile 名(默认 Dockerfile) | v2 起 |
build.args | ARG 参数 | v2 起 |
build.cache_from | 缓存来源镜像列表 | v3.2+ |
build.labels | 构建后打 labels | v3.3+ |
build.shm_size | /dev/shm 大小 | v3.5+ |
示例:
1
2
3
4
5
6
7
8
9
| services:
web:
build:
context: ./app
dockerfile: Dockerfile.prod
args:
NODE_ENV: production
cache_from:
- myapp:cache
|
3.2 启动 / 运行时
| 字段 | 作用 |
|---|
command | 覆盖默认启动命令(支持 shell 格式或 [] 格式) |
entrypoint | 覆盖默认入口点 |
container_name | 指定容器名(docker run --name 等价) |
working_dir | 工作目录 |
user | 容器内运行用户 |
tty / stdin_open | 是否分配 TTY / 保持 stdin |
privileged | 特权模式 |
init | 容器内跑 init 进程(PID 1,正确转发信号) |
示例:
1
2
3
4
5
6
7
8
| services:
api:
image: myapi:latest
command: ["python", "manage.py", "runserver", "0.0.0.0:8000"]
user: "1000:1000"
init: true
tty: true
working_dir: /app
|
3.3 端口 / 网络
| 字段 | 作用 |
|---|
ports | 端口映射(HOST:CONTAINER) |
expose | 暴露端口(容器间可访问,不映射到宿主机) |
networks | 加入指定网络 |
network_mode | 单一网络模式(如 host) |
dns / dns_search | 自定义 DNS |
extra_hosts | 加 /etc/hosts 条目 |
hostname | 容器主机名 |
domainname | 域名 |
mac_address | MAC 地址 |
ports 短语法:
1
2
3
4
5
6
7
| ports:
- "3000" # 容器 3000 端口,宿主机随机
- "3000-3005" # 范围
- "8000:8000" # 宿主机 8000:容器 8000
- "9090-9091:8080-8081" # 范围映射
- "127.0.0.1:8001:8001" # 指定宿主机 IP
- "6060:6060/udp" # 指定协议
|
ports 长语法(v3.2+):
1
2
3
4
5
| ports:
- target: 80
published: 8080
protocol: tcp
mode: host
|
networks 与固定 IP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
| services:
test:
image: nginx:1.14-alpine
networks:
app_net:
ipv4_address: 172.16.238.10
networks:
app_net:
driver: bridge
ipam:
driver: default
config:
- subnet: 172.16.238.0/24
|
3.4 存储 / 卷
| 字段 | 作用 |
|---|
volumes | 挂载卷 / 目录 |
tmpfs | 挂载 tmpfs(v2+) |
read_only | 根文件系统只读 |
短语法:
1
2
3
4
5
6
| volumes:
- /var/lib/mysql # 匿名卷
- /opt/data:/var/lib/mysql # bind mount
- ./cache:/tmp/cache # 相对路径 bind
- ~/configs:/etc/configs/:ro # 只读
- datavolume:/var/lib/mysql # 引用顶层命名卷
|
长语法(v3.2+):
1
2
3
4
5
6
7
8
9
10
| volumes:
- type: volume
source: mydata
target: /data
volume:
nocopy: true
- type: bind
source: ./static
target: /opt/app/static
read_only: true
|
3.5 环境变量 / 配置
| 字段 | 作用 |
|---|
environment | 内联环境变量 |
env_file | 从文件读环境变量 |
secrets | 挂载 secret(来自顶层 secrets) |
configs | 挂载 config(来自顶层 configs) |
1
2
3
4
5
6
7
8
9
10
11
| services:
app:
environment:
DB_HOST: db
DB_PORT: 5432
env_file:
- .env
- .env.production
configs:
- source: app-config
target: /app/config.json
|
优先级:environment > env_file > 镜像内 ENV
3.6 依赖 / 健康检查
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
| services:
web:
depends_on:
db:
condition: service_healthy # v2 起
redis:
condition: service_started # 默认
db:
image: postgres:14
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 10s
timeout: 5s
retries: 5
start_period: 30s
|
condition: service_healthy 必须配 healthcheck 才生效——v2 起推荐用这个替代 wait-for-it 脚本。
3.7 资源限制 / 重启
| 字段 | 作用 |
|---|
restart | no / always / on-failure / unless-stopped |
deploy.resources.limits | CPU / 内存上限(docker stack 用) |
cpus / cpuset | v1 兼容字段,docker compose 仍支持 |
mem_limit / memswap_limit | v1 兼容内存限制 |
ulimits | ulimit 列表 |
pids_limit | PID 上限 |
logging | 日志驱动(json-file / syslog / fluentd) |
shm_size | /dev/shm 大小 |
stop_grace_period | 收到 SIGTERM 后等待秒数(默认 10s) |
stop_signal | 停止信号(默认 SIGTERM) |
资源限制示例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
| services:
api:
image: myapi:latest
deploy:
resources:
limits:
cpus: "0.5" # 50% 单核
memory: 512M
reservations:
cpus: "0.2" # 预留 20%
memory: 128M
logging:
driver: json-file
options:
max-size: "50m"
max-file: "3"
|
Why 用 deploy.resources 而不是 mem_limit:前者是 Compose Spec 规范字段,后者是 v1 兼容字段。新项目用前者。
3.8 其他
| 字段 | 作用 |
|---|
labels | Docker 标签(LABEL 等价) |
pid | host 表示共享宿主机 PID namespace |
ipc | 共享 IPC namespace |
security_opt | SELinux / AppArmor 选项 |
cap_add / cap_drop | Linux capabilities |
devices | 设备映射(docker run --device) |
links | 链接到其他容器(已废弃,用 networks) |
external_links | 链接到 compose 外的容器 |
isolation | 隔离技术(仅 default / process / hyperv) |
runtime | 指定 runtime(runc / runsc 沙箱) |
profiles | 启用 profile(条件启动) |
profiles 示例:
1
2
3
4
5
6
7
| services:
api:
image: myapi:latest
debug-tools:
image: mydebug:latest
profiles: ["debug"]
|
1
2
3
4
| # 默认 up 不启动 debug-tools
docker compose up
# 加 profile 启动
docker compose --profile debug up
|
四、networks 顶层
1
2
3
4
5
6
7
8
9
10
11
| networks:
frontend:
driver: bridge
backend:
driver: bridge
internal: true # 不通外网
monitoring:
driver: overlay # 跨主机
external_net:
external: true # 引用已创建的网络
name: my-pre-existing-network
|
internal: true:内网隔离的 bridge——容器能互相访问,不能访问外网。数据库 / 缓存很适合。
五、volumes 顶层
1
2
3
4
5
6
7
8
9
10
| volumes:
db-data:
driver: local
driver_opts:
type: "nfs"
o: "addr=10.0.0.10,nolock,soft,rw"
device: ":/path/to/dir"
shared:
external: true
name: my-pre-existing-volume
|
六、完整实战示例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
| version: "3.8"
services:
redis:
image: redis:alpine
ports:
- "6379"
networks:
- frontend
deploy:
replicas: 2
update_config:
parallelism: 2
delay: 10s
restart_policy:
condition: on-failure
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 10s
timeout: 3s
retries: 3
db:
image: postgres:14
volumes:
- db-data:/var/lib/postgresql/data
networks:
- backend
environment:
POSTGRES_PASSWORD: ${DB_PASSWORD}
deploy:
placement:
constraints: [node.role == manager]
web:
build: ./app
ports:
- "8080:8080"
networks:
- frontend
- backend
depends_on:
redis:
condition: service_healthy
db:
condition: service_started
environment:
REDIS_HOST: redis
DB_HOST: db
deploy:
resources:
limits:
cpus: "0.5"
memory: 512M
networks:
frontend:
backend:
internal: true
volumes:
db-data:
|
关键点:
web 同时加入 frontend 和 backend 网络——能访问 redis 和 dbdb 在 internal: true 的 backend 网络——不能访问外网redis 多副本 + 滚动更新配置web 资源限制
七、Compose 常用命令
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
| # 启动
docker compose up -d
# 启动指定服务
docker compose up -d web
# 不重建已停止的容器
docker compose up -d --no-recreate
# 停止 / 启动
docker compose stop
docker compose start
# 停掉 + 销毁容器
docker compose down # 保留卷
docker compose down -v # 同时删卷(**危险**)
docker compose down --rmi all # 同时删镜像
# 查看状态
docker compose ps
docker compose logs -f web
# 进入容器
docker compose exec web bash
# 在 web 容器内跑一次性命令
docker compose run --rm web python manage.py migrate
|
八、字段优先级与兼容性
| 字段类型 | 优先级 |
|---|
environment | > env_file > 镜像 ENV |
command | 覆盖镜像 CMD |
entrypoint | 覆盖镜像 ENTRYPOINT |
ports + expose | 都可以,ports 同时映射到宿主机 |
v1 → v2 字段迁移:
| v1 字段 | v2 推荐 |
|---|
mem_limit | deploy.resources.limits.memory |
memswap_limit | deploy.resources.limits.memory(swap 用 flag) |
cpus / cpuset | deploy.resources.limits.cpus |
volume_driver | driver_opts(在 volumes 顶层) |
extends | 已移除(用 include 或合并 YAML) |
九、要点回顾
- Compose v2 (
docker compose) 是当前主推,不要再用 v1 (docker-compose) services 是必填顶层,networks / volumes / configs / secrets 可选build 支持对象语法(context + dockerfile + args)depends_on: condition: service_healthy 替代 wait-for-it 脚本deploy.resources.limits 才是规范字段,mem_limit 是 v1 兼容internal: true 给敏感服务(数据库)做网络隔离profiles 区分"开发 / 调试 / 生产"不同场景docker compose down -v 是核弹——会删数据卷
十、小结
Compose v2 是个"看似简单、字段多到爆炸"的工具。日常用到的不到 20 个字段:
image / buildports / networks / volumesenvironment / env_filedepends_on + healthcheckrestart / deploy.resources.limitslogging
把这十几个字段摸熟,80% 的多服务编排就够用了。剩下冷门字段(cap_add / secrets / configs / pid)需要时查文档即可。
下一步:理解了 Compose,下一步是 Kubernetes——把"compose 文件"换成"YAML manifest",把 docker compose up 换成 kubectl apply,把"单机多服务"换成"集群多副本"。K8s 的 Pod 抽象比 Container 更进一步——把"应用 + 卷 + 网络"打包成不可变单元,跨节点调度。
参考资料