目录
compose.yaml 语法详解教程:掌握常用配置项
compose.yaml 顶层主要有四个区块:
name: myapp # 项目名称(可选,默认是文件夹名称)
services: # 要运行的容器
...
volumes: # 命名 Volume
...
networks: # 自定义网络(可选,默认会自动创建一个)
...
下面按用途说明 services 下最常用的配置,最后通过一个完整示例实际运行。
image 与 build
使用现成的镜像:
services:
redis:
image: redis:8-alpine
从 Dockerfile 构建:
services:
app:
build: . # 使用当前文件夹中的 Dockerfile
需要更多选项时:
services:
app:
build:
context: ./backend
dockerfile: Dockerfile.prod
target: prod # 多阶段构建的目标阶段
args:
APP_VERSION: "1.4.2"
image: myorg/app:1.4.2 # 构建后的镜像名称
同时写 build 和 image 时,Compose 会将构建结果命名为 image 的值,之后可以运行 docker compose push。
ports:端口
ports:
- "8080:80" # 主机:容器
- "127.0.0.1:5432:5432" # 仅开放本机
- "9000-9002:9000-9002" # 范围
请加上引号。YAML 会把某些 数字:数字 格式解读成六十进制数,导致奇怪的错误。
expose 只是说明用途,不会对外开放;同一网络中的服务本来就可以互相连接。
volumes:挂载
services:
db:
image: postgres:18
volumes:
- pgdata:/var/lib/postgresql # 命名 Volume
- ./init.sql:/docker-entrypoint-initdb.d/init.sql:ro # Bind mount(相对路径)
volumes:
pgdata:
-
以
./或../开头的是相对于compose.yaml的 Bind mount。 -
只写名称的是命名 Volume,必须在顶层的
volumes:中声明,实际名称会加上项目名称前缀(例如shop_pgdata)。 -
想使用在 Compose 之外创建的 Volume:
volumes: pgdata: external: true
environment 与 env_file
environment:
NODE_ENV: production
DATABASE_URL: postgres://app:${DB_PASSWORD}@db:5432/app
env_file:
- .env.app
${...} 的值来自 .env 文件或当前环境变量,详见环境变量与 .env 文件。
depends_on 与 healthcheck:等待数据库真正准备就绪
depends_on 只控制启动顺序:保证 db 容器先启动,但不保证数据库已经可以连接。PostgreSQL 启动需要几秒,应用程序可能因无法连接而失败。配合 healthcheck 和 condition: service_healthy,Compose 会等健康检查通过后才启动应用程序。
实际示例(compose.yaml):
name: shop
services:
app:
image: postgres:18
command: ["psql", "-h", "db", "-U", "shop", "-c", "SELECT 'app connected' AS status;"]
environment:
PGPASSWORD: ${DB_PASSWORD}
depends_on:
db:
condition: service_healthy
db:
image: postgres:18
environment:
POSTGRES_USER: shop
POSTGRES_PASSWORD: ${DB_PASSWORD:?DB_PASSWORD is required}
POSTGRES_DB: shop
volumes:
- pgdata:/var/lib/postgresql
healthcheck:
test: ["CMD-SHELL", "pg_isready -h 127.0.0.1 -U shop -d shop"]
interval: 2s
timeout: 3s
retries: 20
adminer:
image: adminer
ports:
- "8081:8080"
profiles: [tools]
volumes:
pgdata:
app 使用 PostgreSQL 客户端模拟一个“启动时需要连接数据库”的应用程序。在 .env 中设置 DB_PASSWORD=change-me。
先单独启动 db,观察健康状态的变化:
$ docker compose up -d db
[+] up 3/3
✔ Network shop_default Created 0.0s
✔ Volume shop_pgdata Created 0.0s
✔ Container shop-db-1 Started 0.3s
$ docker compose ps
NAME IMAGE COMMAND SERVICE CREATED STATUS PORTS
shop-db-1 postgres:18 "docker-entrypoint.s…" db 1 second ago Up Less than a second (health: starting) 127.0.0.1:5432->5432/tcp
几秒后:
$ docker compose ps
NAME IMAGE COMMAND SERVICE CREATED STATUS PORTS
shop-db-1 postgres:18 "docker-entrypoint.s…" db 10 seconds ago Up 9 seconds (healthy) 127.0.0.1:5432->5432/tcp
状态从 health: starting 变为 healthy。关闭后从头启动 app:
$ docker compose up app
[+] up 3/3
✔ Network shop_default Created 0.0s
✔ Container shop-db-1 Created 0.0s
✔ Container shop-app-1 Created 0.1s
Attaching to app-1
Container shop-db-1 Waiting
Container shop-db-1 Healthy
app-1 | status
app-1 | ---------------
app-1 | app connected
app-1 | (1 row)
app-1 |
app-1 exited with code 0
w Enable Watch d Detach
Compose 先启动 db,显示 Waiting,等到 Healthy 后才启动 app,因此 app 第一次连接就成功了(app connected)。如果没有 condition: service_healthy,app 会在数据库还没准备好时就尝试连接。
(最后一行 w Enable Watch d Detach 是 Compose 在前台运行时显示的快捷键提示。)
健康检查中的
pg_isready加了-h 127.0.0.1。如果不加,数据库在第一次初始化期间就会被判定为 healthy,应用程序反而会连接失败。实际测试见 PostgreSQL。MySQL 也有同样的问题,见 MySQL。
condition 可用的值:
| 值 | 含义 |
|---|---|
service_started | 容器已启动(默认) |
service_healthy | 健康检查通过 |
service_completed_successfully | 该服务已执行完毕且退出代码为 0,适合数据库迁移等一次性任务 |
此外,在 depends_on 下添加 restart: true,db 重启时 app 也会随之重启。
restart
restart: unless-stopped
可用值:no、always、on-failure、unless-stopped(行为见容器生命周期)。
command 与 entrypoint
覆盖镜像的 CMD / ENTRYPOINT:
command: ["npm", "run", "dev"]
entrypoint: ["/app/docker-entrypoint.sh"]
networks
默认情况下,所有服务都在同一个 项目名称_default 网络中。需要隔离时,可以自定义网络:
services:
web:
image: nginx:1.30-alpine
networks: [frontend]
app:
build: .
networks: [frontend, backend]
db:
image: postgres:18
networks: [backend]
networks:
frontend:
backend:
web 可以连接 app,但无法连接 db。
profiles:选择性启动服务
上面示例中的 adminer 配置了 profiles: [tools]:
$ docker compose config --services
db
app
$ docker compose --profile tools config --services
db
app
adminer
未指定 profile 时,adminer 不会启动;加上 --profile tools 才会启动。适合放置管理工具、测试用邮件服务器等“需要时才启动”的服务。
资源限制与其他常用配置
services:
app:
image: myorg/app:1.4.2
container_name: app # 固定容器名称(之后无法 scale)
user: "1000:1000"
working_dir: /app
mem_limit: 512m
cpus: 1.5
init: true # 等同于 docker run --init
logging:
driver: json-file
options:
max-size: "10m"
max-file: "3"
extra_hosts:
- "host.docker.internal:host-gateway"
compose.override.yaml:合并配置
Compose 会自动合并 compose.yaml 和 compose.override.yaml。示例文件夹中还有这个文件:
# compose.override.yaml
services:
db:
ports:
- "127.0.0.1:5432:5432"
使用 docker compose config 查看合并后的最终配置(注意最后的 ports):
$ docker compose config db
name: shop
services:
db:
environment:
POSTGRES_DB: shop
POSTGRES_PASSWORD: change-me
POSTGRES_USER: shop
image: postgres:18
networks:
default: null
volumes:
- type: volume
source: pgdata
target: /var/lib/postgresql
volume: {}
healthcheck:
test:
- CMD-SHELL
- pg_isready -h 127.0.0.1 -U shop -d shop
timeout: 3s
interval: 2s
retries: 20
ports:
- mode: ingress
host_ip: 127.0.0.1
target: 5432
published: "5432"
protocol: tcp
networks:
default:
name: shop_default
volumes:
pgdata:
name: shop_pgdata
使用 -f compose.yaml 明确指定单个文件时,就不会合并 override,ports 也会消失:
$ docker compose -f compose.yaml config db
name: shop
services:
db:
environment:
POSTGRES_DB: shop
POSTGRES_PASSWORD: change-me
POSTGRES_USER: shop
image: postgres:18
networks:
default: null
volumes:
- type: volume
source: pgdata
target: /var/lib/postgresql
volume: {}
healthcheck:
test:
- CMD-SHELL
- pg_isready -h 127.0.0.1 -U shop -d shop
timeout: 3s
interval: 2s
retries: 20
networks:
default:
name: shop_default
volumes:
pgdata:
name: shop_pgdata
docker compose config 还会将简写展开为完整格式(例如 pgdata:/var/lib/postgresql 会变成 type: volume、source、target),并替换 ${DB_PASSWORD}。配置看起来没有生效时,第一步就是用它确认 Compose 实际读取的内容。
常见的分工:
compose.yaml:所有环境共用的配置。compose.override.yaml:仅用于开发(挂载源代码、开放调试端口),在本机运行docker compose up时自动应用。compose.prod.yaml:生产环境,通过docker compose -f compose.yaml -f compose.prod.yaml up -d指定。
重点回顾
image使用现成镜像,build从 Dockerfile 构建。depends_on+condition: service_healthy才会等待服务真正就绪。profiles让管理工具等服务只在需要时启动。compose.override.yaml会自动合并,可用docker compose config检查最终配置。
动手练习
练习 1:为本章的 db 服务添加 restart: unless-stopped,并将内存限制设为 512 MB。
答案
db:
image: postgres:18
restart: unless-stopped
mem_limit: 512m
修改后运行 docker compose up -d 应用配置。
练习 2:adminer 配置了 profiles: [tools],如何一起启动它?
答案
docker compose --profile tools up -d
常见问题
depends_on 为什么没有等到数据库准备好?
只写 depends_on: [db] 只能保证启动顺序。要等到数据库可以连接,需要添加 healthcheck 和 condition: service_healthy。健康检查的写法见本章和 [PostgreSQL](/zh/docker/postgresql/)。
YAML 缩进错误会怎样?
docker compose config 会报错,例如 did not find expected key,详见[常见错误信息](/zh/docker/errors/)。只能使用空格,不能使用 Tab。
还需要写 version: '3.8' 吗?
不需要。Compose 规范已经不再使用 version 字段,新版会忽略它并显示警告。
更新于 2026年10月14日