Docker Compose 语法
适用版本:Docker Compose v2(v5.3.0+),基于 Compose Specification
一、核心概念
1.1 是什么
Docker Compose 是 Docker 官方的多容器编排工具,通过一个 YAML 配置文件定义、启动和管理多个容器。
1.2 与旧版(v1)的核心区别
| 对比项 | 旧版(v1) | 新版 v2(Compose Spec) |
|---|---|---|
version 字段 | 必须指定(如 version: "3.9") | 删除,不再需要 |
| 命令格式 | docker-compose(带横杠) | docker compose(无横杠) |
| 配置文件 | 支持多个文件合并 | 支持多个文件合并 |
| 部署(deploy) | Swarm 模式专用 | 扩展了更多配置能力 |
1.3 语法规则
| 规则 | 说明 |
|---|---|
| 缩进 | 2 个空格,禁用 Tab |
| 冒号 | 键后必须加空格(image: nginx ✔) |
| 注释 | 使用 # 开头 |
二、配置文件结构(新版)
# version: "3.9" 新版中直接删除,不再需要
services: # 服务定义(必填)
web:
# 服务配置...
networks: # 自定义网络(可选)
frontend:
volumes: # 数据卷(可选)
db-data:
configs: # 配置(可选,Swarm 模式)
secrets: # 密钥(可选,Swarm 模式)
三、顶层字段详解
3.1 services — 服务定义
所有容器的定义都在这里:
services:
web:
image: nginx:alpine
db:
image: mysql:8.0
3.2 networks — 自定义网络
networks:
frontend:
driver: bridge
backend:
driver: bridge
internal: true # 内部网络,不对外暴露
3.3 volumes — 数据卷声明
volumes:
db-data:
driver: local
app-logs:
external: true # 使用已存在的外部卷
四、服务配置字段
4.1 image / build — 镜像来源
services:
# 直接使用镜像
web:
image: nginx:1.24-alpine
# 从 Dockerfile 构建
app:
build: ./app
# 构建详细配置
app:
build:
context: ./app
dockerfile: Dockerfile.prod
args:
BUILD_ENV: production
target: production # 多阶段构建目标
cache_from:
- myapp:latest
4.2 container_name — 容器命名
services:
web:
image: nginx
container_name: my-nginx-server
生产环境建议不写,让 Compose 自动生成名称,避免扩容时冲突。
4.3 ports / expose — 端口配置
services:
web:
ports:
- "8080:80"
- "127.0.0.1:8080:80"
- "80" # 随机宿主机端口
- "443:443/tcp"
- "53:53/udp"
# 长语法(推荐)
- target: 80
published: 8080
protocol: tcp
mode: host
db:
expose:
- "3306"
4.4 environment / env_file — 环境变量
services:
db:
image: mysql:8.0
environment:
MYSQL_ROOT_PASSWORD: secret123
MYSQL_DATABASE: myapp
app:
image: myapp
env_file:
- .env
- .env.production
优先级:environment > env_file > Dockerfile 中的 ENV
4.5 volumes — 数据卷挂载
services:
web:
image: nginx
volumes:
# 命名卷(推荐)
- app-data:/app/data
# 宿主机目录
- ./html:/usr/share/nginx/html
# 只读挂载
- ./nginx.conf:/etc/nginx/nginx.conf:ro
# 长语法
- type: volume
source: app-data
target: /app/data
read_only: false
4.6 depends_on + healthcheck — 依赖与健康检查
services:
web:
image: nginx
depends_on:
db:
condition: service_healthy
redis:
condition: service_started
db:
image: mysql:8.0
environment:
MYSQL_ROOT_PASSWORD: secret
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
interval: 10s
timeout: 5s
retries: 3
start_period: 30s
depends_on 的 condition 可选值:
| 值 | 说明 |
|---|---|
service_started | 等待容器启动(默认) |
service_healthy | 等待健康检查通过 |
service_completed_successfully | 等待容器正常退出 |
4.7 restart — 重启策略
services:
web:
image: nginx
restart: unless-stopped
| 策略 | 说明 |
|---|---|
no | 不重启(默认) |
always | 任何情况都重启 |
on-failure | 异常退出时重启 |
unless-stopped | 除手动停止外都重启(生产推荐) |
4.8 networks — 网络配置
services:
web:
image: nginx
networks:
- frontend
- backend
# 或指定详细配置
networks:
frontend:
aliases:
- web.local
backend:
ipv4_address: 172.20.0.10
4.9 resources — 资源限制
services:
app:
image: myapp
deploy:
resources:
limits:
cpus: '1.0'
memory: 1g
reservations:
cpus: '0.5'
memory: 512m
非 Swarm 模式也支持:
services:
app:
image: myapp
mem_limit: 1g
mem_reservation: 512m
cpus: '1.0'
4.10 command / entrypoint
services:
app:
image: python:3.10
entrypoint: ["/bin/sh", "-c"]
command: ["python app.py --port 8080"]
4.11 logging — 日志配置
services:
web:
image: nginx
logging:
driver: json-file
options:
max-size: "50m"
max-file: "5"
compress: "true"
4.12 profiles — 条件启动
services:
web:
image: nginx
profiles:
- production
debug-tools:
image: alpine
profiles:
- debug
db:
image: mysql # 默认启动
docker compose --profile production up
docker compose --profile production --profile debug up
4.13 extends — 配置继承
# docker-compose.base.yml
services:
web-base:
image: nginx
restart: always
# docker-compose.yml
services:
web:
extends:
file: docker-compose.base.yml
service: web-base
ports:
- "80:80"
4.14 其他常用字段
| 字段 | 说明 |
|---|---|
user | 运行用户 |
working_dir | 工作目录 |
hostname | 容器主机名 |
privileged | 特权模式 |
cap_add / cap_drop | Linux 能力管理 |
sysctls | 内核参数 |
tmpfs | 内存文件系统 |
stdin_open | 交互模式 |
tty | 分配伪终端 |
五、变量替换与 .env 文件
5.1 基础用法
# docker-compose.yml
services:
db:
image: mysql:${MYSQL_VERSION:-8.0}
environment:
MYSQL_ROOT_PASSWORD: ${DB_PASSWORD}
# .env
MYSQL_VERSION=8.0
DB_PASSWORD=secret123
5.2 变量优先级
Shell 环境变量 > .env 文件 > Dockerfile 中的 ENV
六、多文件组合
# 开发环境(自动加载 override)
docker compose up
# 生产环境
docker compose -f docker-compose.yml -f docker-compose.prod.yml up -d
七、常用命令(v2 版)
注意:新版命令是
docker compose(无横杠),不是docker-compose
| 命令 | 说明 |
|---|---|
docker compose up -d | 后台启动所有服务 |
docker compose down | 停止并删除服务 |
docker compose down -v | 删除数据卷 |
docker compose start/stop/restart | 启停/重启 |
docker compose ps | 查看状态 |
docker compose logs -f 服务名 | 查看日志 |
docker compose build --no-cache | 构建镜像 |
docker compose exec web bash | 进入容器 |
docker compose config | 验证语法 |
八、完整生产级示例(新版)
# 注意:没有 version 字段
# ========== 网络 ==========
networks:
frontend:
driver: bridge
backend:
driver: bridge
internal: true
# ========== 数据卷 ==========
volumes:
db-data:
redis-data:
app-logs:
# ========== 服务 ==========
services:
# -------- Nginx --------
nginx:
image: nginx:1.24-alpine
ports:
- "80:80"
- "443:443"
volumes:
- ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro
- ./ssl:/etc/nginx/ssl:ro
- app-logs:/var/log/nginx
depends_on:
- app
restart: unless-stopped
networks:
- frontend
healthcheck:
test: ["CMD", "nginx", "-t"]
interval: 30s
timeout: 10s
retries: 3
logging:
driver: json-file
options:
max-size: "50m"
max-file: "3"
# -------- 应用 --------
app:
build:
context: ./app
args:
BUILD_ENV: production
environment:
- NODE_ENV=production
- DB_HOST=db
- REDIS_HOST=redis
volumes:
- app-logs:/app/logs
depends_on:
db:
condition: service_healthy
redis:
condition: service_started
restart: unless-stopped
networks:
- frontend
- backend
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:3000/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 60s
deploy:
resources:
limits:
cpus: '1'
memory: 1g
reservations:
cpus: '0.5'
memory: 512m
logging:
driver: json-file
options:
max-size: "50m"
max-file: "3"
# -------- MySQL --------
db:
image: mysql:8.0
environment:
MYSQL_ROOT_PASSWORD: ${DB_ROOT_PASSWORD}
MYSQL_DATABASE: ${DB_NAME}
MYSQL_USER: ${DB_USER}
MYSQL_PASSWORD: ${DB_PASSWORD}
volumes:
- db-data:/var/lib/mysql
- ./mysql/init:/docker-entrypoint-initdb.d:ro
ports:
- "3306:3306"
restart: unless-stopped
networks:
- backend
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-u", "root", "-p${DB_ROOT_PASSWORD}"]
interval: 10s
timeout: 5s
retries: 5
start_period: 60s
deploy:
resources:
limits:
memory: 2g
logging:
driver: json-file
options:
max-size: "50m"
max-file: "3"
# -------- Redis --------
redis:
image: redis:7.2-alpine
command: redis-server --requirepass ${REDIS_PASSWORD} --appendonly yes
volumes:
- redis-data:/data
ports:
- "6379:6379"
restart: unless-stopped
networks:
- backend
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 10s
timeout: 3s
retries: 3
deploy:
resources:
limits:
memory: 256m
logging:
driver: json-file
options:
max-size: "20m"
max-file: "3"
九、常见踩坑
踩坑 1:version 字段警告
问题:新版 Docker Compose 提示 version 字段已弃用。
解决:直接删除 version 行。
踩坑 2:命令写错
问题:使用 docker-compose 命令报错。
解决:新版使用 docker compose(无横杠)。
踩坑 3:down -v 误删数据
解决:使用命名卷并声明在顶层 volumes 中。
踩坑 4:env_file 变量不被 Compose 自身解析
解决:变量放在同目录的 .env 文件中用于 Compose 替换,env_file 仅用于容器内环境变量。
十、快速检查清单
- 所有镜像固定了版本(不用
latest) - 有状态服务使用了命名卷(
volumes:顶层声明) - 敏感信息用了
.env或env_file,没有硬编码 - 服务间依赖使用了
depends_on(如需就绪等待,配置了healthcheck) - 生产环境配置了
restart: unless-stopped - 生产环境配置了日志轮转(
logging) - 生产环境配置了资源限制(
deploy.resources) - 自定义网络已声明(如需要)
- 端口映射没有冲突
container_name没有写死(除非有特殊需求)- 执行
docker-compose config验证语法通过