本节摘要:Compose 文件是把散装命令翻译成声明式 YAML 的词典转换表。本节解剖文件的层级结构:顶级 services、networks、volumes 三大块各管什么,服务字段(image、build、ports、environment、volumes、depends_on)分别等价于前几部的哪条命令,读完能把任意 Compose 文件反译成命令序列。
别把 Compose 文件当成一门新语言:它只是把 docker run 的选项、docker network 的参数、docker volume 的声明搬进了 YAML 的格子。会读命令就会读它——本节给一份逐字段挂钩的解剖图,让你始终知道每个格子背后是哪条老熟人命令。
services: web: # 服务名 = 未来的互访主机名 image: nginx:1.25 # 等价于 run 的镜像位置参数 ports: - "8080:80" # 等价于 -p 8080:80 volumes: - ./site:/usr/share/nginx/html:ro # 等价于绑定挂载 + ro depends_on: - api api: build: # 不用 image 而用 build:现场构建 context: ./api # 等价于 build 的上下文参数 dockerfile: Dockerfile # 等价于 -f environment: - DB_HOST=db # 等价于 -e - REDIS_URL=redis://cache:6379 depends_on: db: condition: service_healthy db: image: postgres:16 environment: - POSTGRES_PASSWORD=secret volumes: - dbdata:/var/lib/postgresql/data # 命名卷挂载 healthcheck: test: ["CMD-SHELL", "pg_isready -U postgres"] interval: 5s timeout: 3s retries: 5 cache: image: redis:7.2 volumes: # 顶级卷声明:项目级命名卷 dbdata: networks: # 不写也有默认网络,写了可定制 default: driver: bridge

image 与 build:二选一,也可并用(build 出来再打 image 指定的标签)。build 子块的 context、dockerfile、args 与贰部 2.2 的同名义项一一对应,缓存规则也完全相同——Compose 不发明新机制,只做转发。
ports 与 environment:列表形态的 -p 与 -e。端口映射的"宿主:容器"格式、绑定回环 IP 的写法在 Compose 里原样有效;environment 既可列表也可映射两种写法,语义等价。敏感值从 .env 文件读入是标配做法,变量替换用 shell 风格的花括号。
volumes:两个位置要分清——服务级 volumes 是挂载动作(等价 run 的 -v),顶级 volumes 是卷声明(等价 volume create)。样本里 db 的 - dbdata:/var/lib/postgresql/data 之所以能挂上,是因为顶级声明了 dbdata;而 web 挂的 ./site 以斜杠点开头,是绑定挂载,无须声明。伍部"名字是卷、路径是绑定"的判别法在这里原样适用。
depends_on 与 healthcheck:depends_on 只保证"启动顺序",不保证"就绪"——db 容器先起不代表 postgres 已能接受连接。要等就绪,样本给出了标准组合:被依赖方声明 healthcheck,依赖方写 condition: service_healthy。这条组合拳是 7.3 实战的主角。
$ docker compose config --services web api db cache
config 子命令把文件解析一遍,--services 列出服务清单——写完文件先跑它验语法,比 up 时才炸强得多。加 --volumes 或 --networks 还能核对顶级声明。
⚠️ 常见坑:ports 的值不加引号时,"56:80" 这类端口对在 YAML 里会被当成六十进制数字解析出诡异结果。约定:端口对一律加引号。这个坑的报错毫不直观,预防的成本只是两个引号。
问:文件名必须是 docker-compose.yml 吗? 首选名已是 compose.yaml,旧名 docker-compose.yml 作为兼容写法照常识别;异名文件用 -f 显式指定,还能叠加——基础文件写共性,override 文件写差异,后者自动覆盖前者:
$ docker compose -f compose.yaml -f compose.prod.yaml config --services web api db
生产与开发的差异(端口、副本、资源限制)靠这套叠法分文件管理,避免一份文件伺候两个环境、每次发版手工改来改去。
问:顶部的 version 字段还要写吗? 老教程常带 version: "3.8",新版 Compose 已把它当历史遗物——写了会提示 version is obsolete。删掉即可,其余语法不受影响。
问:.env 文件与 environment 字段是什么关系? 两道闸门,别混:.env 伺候文件本身——文件里的 ${TAG} 这类占位在解析期被替换;environment 伺候容器——把值注入运行环境。写错闸门的典型症状是"变量明明写了却不生效",排查时先问自己:这个值该被文件读走,还是该被容器读走。
文件读懂了,下一节进入命令现场:up、down、logs 全家桶的实际操作。