Docker Compose
Docker Compose 是用于定义和运行多容器 Docker 应用的工具。通过一个 YAML 配置文件,可以配置应用的服务、网络和数据卷,然后使用一条命令启动或停止整个应用栈。
Compose Specification 说明
Docker Compose 使用 YAML 文件定义应用配置。从 Compose v1.27.0 开始,Docker 引入了 Compose Specification,这是最新且推荐的文件格式。
Compose Specification 整合了旧版本 2.x 和 3.x 的所有功能,并引入了新特性。现在不再需要在文件开头指定 version 字段:
# 旧格式(已弃用)
version: "3.8"
services:
app:
image: nginx
# 新格式(推荐)
services:
app:
image: nginx
关键变化:
version字段已废弃,不再需要指定- 所有 2.x 和 3.x 的功能都已合并到 Compose Specification
- 默认文件名推荐使用
compose.yaml(也支持docker-compose.yml) - 新增了
include、develop、depends_on长语法等特性
为什么需要 Docker Compose
实际项目中,一个应用往往由多个服务组成。比如一个 Web 应用可能包含:
- Nginx 作为反向代理
- Node.js 或 Python 编写的 API 服务
- MySQL 或 PostgreSQL 数据库
- Redis 缓存服务
如果手动管理这些容器,需要逐个执行 docker run 命令,还要处理网络连接、数据卷挂载、环境变量等问题。Docker Compose 把这些配置集中在一个文件里,让多容器应用的管理变得简单。
安装
Docker Desktop(Windows 和 Mac)已经内置了 Docker Compose,安装 Docker Desktop 后直接可用。
Linux 系统需要单独安装 Docker Compose 插件:
# 安装 Docker Compose 插件(新版本方式)
sudo apt-get update
sudo apt-get install docker-compose-plugin
# 验证安装
docker compose version
新版 Docker Compose 使用 docker compose(空格),旧版使用 docker-compose(横线)。新版是 Docker CLI 的插件,性能更好。两种方式目前都支持,但推荐使用新版。
compose.yaml 文件结构
Docker Compose 使用 YAML 文件定义应用配置。默认文件名为 compose.yaml(也支持 docker-compose.yml)。
最小示例
services:
web:
image: nginx:alpine
ports:
- "8080:80"
api:
image: node:18-alpine
ports:
- "3000:3000"
这个配置定义了两个服务:web 和 api。运行 docker compose up 就能同时启动它们。
完整结构
一个完整的 compose.yaml 包含以下几个主要部分:
# Compose Specification(无需 version 字段)
services: # 服务定义(必须)
service-name:
# 服务配置...
networks: # 网络定义(可选)
network-name:
# 网络配置...
volumes: # 数据卷定义(可选)
volume-name:
# 卷配置...
configs: # 配置定义(可选,用于 Swarm)
config-name:
# 配置...
secrets: # 密钥定义(可选,用于 Swarm)
secret-name:
# 密钥...
文件格式说明:
Compose 文件使用 YAML 格式,支持以下顶层键:
| 键 | 说明 |
|---|---|
services | 定义应用的服务(必填) |
networks | 定义自定义网络 |
volumes | 定义命名数据卷 |
configs | 定义配置(主要用于 Swarm) |
secrets | 定义敏感数据(主要用于 Swarm) |
include | 引入其他 Compose 文件 |
name | 为项目设置自定义名称 |
服务配置
镜像和构建
服务可以从现有镜像启动,也可以从 Dockerfile 构建:
services:
# 方式一:使用现有镜像
redis:
image: redis:7-alpine
# 方式二:从当前目录的 Dockerfile 构建
api:
build: .
# 方式三:指定构建上下文和 Dockerfile
api:
build:
context: ./api
dockerfile: Dockerfile.prod
args:
NODE_VERSION: 18
端口映射
端口映射将容器内部端口暴露给主机:
services:
web:
ports:
- "8080:80" # 主机端口:容器端口
- "443:443"
- "53:53/udp" # 指定协议
# 仅暴露给其他容器,不映射到主机
internal-api:
expose:
- "3000"
环境变量
环境变量有多种设置方式:
services:
db:
# 直接在配置中设置
environment:
MYSQL_ROOT_PASSWORD: secret
MYSQL_DATABASE: myapp
# 从文件读取
env_file:
- .env
- .env.local
# 列表格式(等号连接)
environment:
- MYSQL_ROOT_PASSWORD=secret
- MYSQL_DATABASE=myapp
.env 文件示例:
MYSQL_ROOT_PASSWORD=secret
MYSQL_DATABASE=myapp
MYSQL_USER=appuser
MYSQL_PASSWORD=apppass
变量插值语法
Compose 文件支持使用变量实现更灵活的配置。变量可以在运行时从环境变量或 .env 文件中读取:
services:
web:
image: "webapp:${TAG}"
environment:
DATABASE_URL: "postgres://${DB_USER}:${DB_PASSWORD}@db:5432/myapp"
插值语法格式:
| 语法 | 说明 |
|---|---|
${VAR} | 直接替换为 VAR 的值 |
${VAR:-default} | VAR 未设置或为空时使用 default |
${VAR-default} | VAR 未设置时使用 default(为空则使用空值) |
${VAR:?error} | VAR 未设置或为空时报错并退出 |
${VAR?error} | VAR 未设置时报错并退出 |
${VAR:+replacement} | VAR 设置且非空时使用 replacement |
${VAR+replacement} | VAR 设置时使用 replacement(即使为空) |
使用示例:
services:
web:
# 带默认值的镜像标签
image: "myapp:${VERSION:-latest}"
# 必需的数据库密码(未设置时报错)
environment:
DATABASE_PASSWORD: "${DB_PASSWORD:?数据库密码未设置}"
# 可选的调试模式
environment:
DEBUG: "${DEBUG:-false}"
变量来源优先级(从高到低):
- Shell 环境变量
--env-file指定的文件- 项目目录下的
.env文件
验证变量配置:
# 查看解析后的配置
docker compose config
# 查看使用的环境变量
docker compose config --environment
env_file 高级配置
env_file 支持长语法,可以设置更多选项:
services:
app:
env_file:
# 必需的环境文件(默认)
- path: ./default.env
required: true
# 可选的环境文件,不存在时静默忽略
- path: ./override.env
required: false
# 使用原始格式(不解析引号和转义)
- path: ./raw.env
format: raw
| 参数 | 说明 |
|---|---|
path | 环境文件路径 |
required | 文件不存在时是否报错(默认 true) |
format | 文件格式:默认解析或 raw(原样保留) |
raw 格式说明:当 format: raw 时,Compose 不会解析文件中的引号和 $ 符号,值会原样传递。这对于包含 JSON 或特殊字符的值特别有用。
数据卷
数据卷用于持久化数据和共享文件:
services:
db:
volumes:
# 命名卷:由 Docker 管理,数据持久化
- db-data:/var/lib/mysql
# 绑定挂载:映射主机目录到容器
- ./data:/var/lib/mysql
# 只读挂载
- ./config:/etc/mysql/conf.d:ro
volumes:
db-data: # 声明命名卷
依赖关系
使用 depends_on 控制服务启动顺序:
services:
web:
depends_on:
- api
- db
api:
depends_on:
db:
condition: service_healthy
redis:
condition: service_started
db:
image: postgres:15
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 10s
timeout: 5s
retries: 5
依赖条件说明:
| 条件 | 含义 |
|---|---|
service_started | 服务已启动(默认) |
service_healthy | 健康检查通过 |
service_completed_successfully | 服务成功完成并退出 |
长语法的完整选项:
services:
web:
depends_on:
db:
condition: service_healthy
restart: true # 依赖服务更新时重启此服务
required: true # 必须存在,否则启动失败(默认)
redis:
condition: service_started
required: false # 可选依赖,不存在时仅警告
| 参数 | 说明 |
|---|---|
condition | 依赖满足的条件 |
restart | 依赖服务更新后是否重启此服务 |
required | 依赖是否必须存在(true 时不存在则报错,false 时不存在仅警告) |
required 参数详解:
required 参数控制当依赖服务不存在时的行为:
required: true(默认):依赖服务必须存在,否则启动失败并报错required: false:依赖服务不存在时仅发出警告,服务仍可正常启动
services:
# 核心服务
api:
image: myapi
depends_on:
db:
condition: service_healthy
required: true # 数据库必须存在
# 可选监控服务
app:
image: myapp
depends_on:
api:
condition: service_started
required: true
monitoring:
condition: service_started
required: false # 监控服务可选,不存在时仅警告
重启策略
配置容器异常退出时的重启行为:
services:
api:
restart: always # 总是重启
worker:
restart: on-failure # 仅在失败时重启
cron:
restart: unless-stopped # 除非手动停止,否则重启
deploy 部署配置
deploy 配置用于定义服务的部署行为,主要用于 Docker Swarm 模式。在非 Swarm 环境中,部分配置(如 resources)也被 Compose 支持。
services:
web:
image: nginx
deploy:
# 副本数量
replicas: 3
# 资源限制
resources:
limits:
cpus: '0.5'
memory: 512M
reservations:
cpus: '0.25'
memory: 256M
# 更新配置
update_config:
parallelism: 2
delay: 10s
failure_action: rollback
# 回滚配置
rollback_config:
parallelism: 1
delay: 5s
# 重启策略
restart_policy:
condition: on-failure
delay: 5s
max_attempts: 3
window: 120s
deploy 主要配置项:
| 参数 | 说明 |
|---|---|
mode | 运行模式:replicated(默认)、global、replicated-job、global-job |
replicas | 副本数量(replicated 模式) |
endpoint_mode | 端点模式:vip(虚拟IP,默认)、dnsrr(DNS轮询) |
resources | 资源限制和预留 |
update_config | 滚动更新配置 |
rollback_config | 回滚配置 |
restart_policy | 重启策略 |
placement | 节点放置约束 |
运行模式详解:
services:
# 副本模式:运行指定数量的副本
web:
deploy:
mode: replicated
replicas: 3
# 全局模式:每个节点运行一个实例
agent:
deploy:
mode: global
# 批处理任务模式:运行完成后退出
batch:
deploy:
mode: replicated-job
replicas: 5
# 全局任务模式:每个节点运行一次
maintenance:
deploy:
mode: global-job
端点模式:
services:
web:
deploy:
endpoint_mode: vip # 虚拟IP,负载均衡自动分发
# endpoint_mode: dnsrr # DNS轮询,客户端直接选择
放置约束:
services:
db:
deploy:
placement:
constraints:
- node.role==worker # 只在 worker 节点运行
- node.labels.disk==ssd # 需要 SSD 磁盘
preferences:
- spread: node.labels.zone # 按可用区均匀分布
资源限制
资源限制可以在 deploy.resources 或直接在服务级别设置:
方式一:deploy.resources(推荐):
services:
api:
deploy:
resources:
limits: # 硬限制,不可超过
cpus: '1.0'
memory: 512M
pids: 100 # 最大进程数
reservations: # 软限制,保证最少可用
cpus: '0.5'
memory: 256M
方式二:服务级别(非 Swarm 环境):
services:
api:
# CPU 限制
cpu_count: 2 # 可用 CPU 数量
cpu_percent: 50 # CPU 使用百分比
cpu_shares: 512 # CPU 权重(相对值)
cpuset: "0,1" # 绑定到特定 CPU 核心
# 内存限制
mem_limit: 512m # 内存限制
mem_reservation: 256m # 内存预留
memswap_limit: 1g # 内存+交换分区限制
# 进程限制
pids_limit: 100
** blkio 限制**(磁盘 IO):
services:
app:
blkio_config:
weight: 500 # IO 权重(10-1000)
weight_device:
- path: /dev/sda
weight: 400
device_read_bps:
- path: /dev/sda
rate: '10mb' # 读速度限制
device_write_bps:
- path: /dev/sda
rate: '5mb' # 写速度限制
device_read_iops:
- path: /dev/sda
rate: 1000 # 读 IOPS 限制
device_write_iops:
- path: /dev/sda
rate: 500 # 写 IOPS 限制
能力和安全配置
services:
app:
# 添加 Linux 能力
cap_add:
- NET_ADMIN
- SYS_TIME
# 移除 Linux 能力
cap_drop:
- ALL
# 安全配置
security_opt:
- no-new-privileges:true
- seccomp:seccomp-profile.json
# 只读根文件系统
read_only: true
# 临时文件系统
tmpfs:
- /tmp
- /run:size=100m
健康检查
健康检查用于监控服务状态:
services:
api:
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:3000/health"]
interval: 30s # 检查间隔
timeout: 10s # 超时时间
retries: 3 # 失败重试次数
start_period: 40s # 启动宽限期
网络配置
默认网络行为
Docker Compose 会自动创建一个网络,所有服务默认加入这个网络。服务之间可以通过服务名互相访问:
services:
web:
image: nginx
api:
image: node:18
# 自动创建的网络中,web 容器可以用 http://api:3000 访问 api 服务
自定义网络
可以创建多个网络实现服务隔离:
services:
nginx:
networks:
- frontend
api:
networks:
- frontend
- backend
db:
networks:
- backend
networks:
frontend:
backend:
internal: true # 内部网络,无法访问外部
这种配置下,nginx 可以访问 api,api 可以访问 db,但 nginx 无法直接访问 db。
使用外部网络
如果需要与其他 Compose 项目的服务通信,可以使用外部网络:
networks:
shared-network:
external: true
实战示例
Web 全栈应用
一个包含前端、后端、数据库、缓存的完整应用:
services:
# Nginx 反向代理
nginx:
image: nginx:alpine
ports:
- "80:80"
- "443:443"
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf:ro
- ./ssl:/etc/nginx/ssl:ro
depends_on:
- api
networks:
- frontend
# API 服务
api:
build: ./api
environment:
NODE_ENV: production
DATABASE_URL: postgres://user:pass@db:5432/myapp
REDIS_URL: redis://redis:6379
depends_on:
db:
condition: service_healthy
redis:
condition: service_started
networks:
- frontend
- backend
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:3000/health"]
interval: 30s
timeout: 10s
retries: 3
# PostgreSQL 数据库
db:
image: postgres:15-alpine
environment:
POSTGRES_USER: user
POSTGRES_PASSWORD: pass
POSTGRES_DB: myapp
volumes:
- postgres-data:/var/lib/postgresql/data
networks:
- backend
healthcheck:
test: ["CMD-SHELL", "pg_isready -U user -d myapp"]
interval: 10s
timeout: 5s
retries: 5
# Redis 缓存
redis:
image: redis:7-alpine
volumes:
- redis-data:/data
networks:
- backend
networks:
frontend:
backend:
volumes:
postgres-data:
redis-data:
开发环境
开发环境通常需要代码热重载和调试工具:
services:
app:
build:
context: .
dockerfile: Dockerfile.dev
ports:
- "3000:3000"
environment:
NODE_ENV: development
volumes:
- .:/app # 绑定挂载源代码
- /app/node_modules # 排除 node_modules(使用容器内的)
command: npm run dev
db:
image: postgres:15-alpine
environment:
POSTGRES_USER: dev
POSTGRES_PASSWORD: dev
POSTGRES_DB: devdb
ports:
- "5432:5432" # 暴露端口方便本地工具连接
volumes:
- dev-db-data:/var/lib/postgresql/data
adminer: # 数据库管理工具
image: adminer
ports:
- "8080:8080"
volumes:
dev-db-data:
常用命令
生命周期管理
# 启动所有服务(前台运行)
docker compose up
# 后台启动
docker compose up -d
# 重新构建并启动
docker compose up --build
# 启动前拉取最新镜像
docker compose up --pull always
# 启动特定服务及其依赖
docker compose up api db
# 使用环境变量文件
docker compose --env-file ./config/.env.prod up
# 使用多个 Compose 文件
docker compose -f compose.yaml -f compose.prod.yaml up
# 强制重新创建容器
docker compose up --force-recreate
# 不启动依赖服务
docker compose up --no-deps api
# 设置项目名称
docker compose -p myproject up
# 停止所有服务
docker compose stop
# 停止特定服务
docker compose stop api
# 停止并移除容器
docker compose down
# 停止并移除容器、网络、数据卷
docker compose down -v
# 停止并移除镜像
docker compose down --rmi all
# 重启服务
docker compose restart
# 暂停和恢复服务
docker compose pause
docker compose unpause
查看状态和日志
# 查看运行中的服务
docker compose ps
# 查看所有服务(包括已停止的)
docker compose ps -a
# 查看服务资源使用
docker compose top
# 查看日志
docker compose logs
# 实时跟踪日志
docker compose logs -f
# 查看特定服务的日志
docker compose logs api
# 查看最后 100 行日志
docker compose logs --tail=100 api
# 显示时间戳
docker compose logs -t
# 查看指定时间后的日志
docker compose logs --since="2024-01-01T00:00:00"
docker compose logs --since=30m # 最近 30 分钟
# 查看端口映射
docker compose port api 3000
执行命令
# 在运行中的容器内执行命令
docker compose exec api bash
# 以 root 用户执行
docker compose exec -u root api bash
# 设置环境变量
docker compose exec -e DEBUG=true api bash
# 指定工作目录
docker compose exec -w /app api bash
# 启动新容器执行一次性命令
docker compose run --rm api npm test
# 运行后删除容器
docker compose run --rm api bash
# 不启动依赖服务
docker compose run --no-deps api npm test
构建和镜像管理
# 构建镜像
docker compose build
# 构建时不使用缓存
docker compose build --no-cache
# 拉取所有服务的镜像
docker compose pull
# 推送镜像到仓库
docker compose push
# 查看服务使用的镜像
docker compose images
其他命令
# 验证配置文件
docker compose config
# 查看解析后的完整配置
docker compose config --resolve-image-digests
# 列出所有服务名
docker compose config --services
# 列出所有数据卷
docker compose config --volumes
# 不解析环境变量
docker compose config --no-interpolate
# 扩展服务实例数量
docker compose up -d --scale api=3
# 查看进程
docker compose top
# 复制文件
docker compose cp api:/app/logs ./logs
docker compose cp ./config.json api:/app/
# 查看事件
docker compose events
# 暂停/取消暂停服务
docker compose pause api
docker compose unpause api
高级特性
Profiles 服务分组
Profiles 允许将服务分组,按需启动不同组合:
services:
# 核心服务(无 profile,始终启动)
app:
image: myapp
# 开发工具(dev profile)
db:
image: postgres
profiles: ["dev"]
adminer:
image: adminer
profiles: ["dev"]
# 监控工具(monitoring profile)
prometheus:
image: prom/prometheus
profiles: ["monitoring"]
grafana:
image: grafana/grafana
profiles: ["monitoring"]
使用方式:
# 只启动核心服务
docker compose up -d
# 启动 dev 配置的服务
docker compose --profile dev up -d
# 启动多个 profile
docker compose --profile dev --profile monitoring up -d
YAML 锚点复用配置
使用 YAML 的锚点(anchor)和别名(alias)复用配置:
x-common-env: &common-env
TZ: Asia/Shanghai
LOG_LEVEL: info
services:
api:
environment:
<<: *common-env
APP_NAME: api
worker:
environment:
<<: *common-env
APP_NAME: worker
include 引入外部配置
将大型配置拆分成多个文件,实现模块化和复用:
短语法:
# compose.yaml
include:
- ./docker/compose.database.yaml
- ./docker/compose.cache.yaml
services:
app:
image: myapp
depends_on:
- db
- redis
短语法只定义文件路径,被引入的文件使用其父目录作为项目目录,可以包含可选的 .env 文件定义默认值。
长语法(更多控制选项):
include:
# 基本引入
- path: ./docker/compose.database.yaml
# 项目目录,默认为被引入文件的目录
project_directory: ./docker
# 环境文件,默认为项目目录下的 .env
env_file: ./docker/.env.db
# 引入多个文件合并为一个项目
- path:
- ./docker/compose.base.yaml
- ./docker/compose.override.yaml
env_file:
- ./docker/.env.common
- ./docker/.env.override
# 使用变量动态指定路径
- path: ./services/${SERVICE_NAME}/compose.yaml
env_file: ./services/${SERVICE_NAME}/.env
include 参数说明:
| 参数 | 说明 |
|---|---|
path | Compose 文件路径,可以是字符串或列表 |
project_directory | 项目目录,用于解析相对路径 |
env_file | 环境变量文件,用于变量插值 |
include 特性:
- 递归引入:被引入的文件中可以继续使用
include - 变量插值:路径支持使用环境变量
- 资源共享:引入文件中定义的 volumes、networks 等可被当前项目使用
- 冲突处理:同名资源会发出警告,不会自动合并
典型应用场景:
# 主项目 compose.yaml
include:
- ./infrastructure/database.yaml # 数据库服务
- ./infrastructure/cache.yaml # 缓存服务
- ./infrastructure/monitoring.yaml # 监控服务
services:
api:
build: ./api
depends_on:
- db # 来自 database.yaml
- redis # 来自 cache.yaml
- prometheus # 来自 monitoring.yaml
这种方式让团队可以独立管理各基础设施组件,同时保持整体项目的清晰结构。
多环境配置
使用多个配置文件覆盖实现多环境:
# 开发环境
docker compose -f compose.yaml -f compose.dev.yaml up
# 生产环境
docker compose -f compose.yaml -f compose.prod.yaml up -d
compose.prod.yaml 示例:
services:
app:
build:
dockerfile: Dockerfile.prod
environment:
NODE_ENV: production
deploy:
replicas: 3
resources:
limits:
cpus: '1'
memory: 512M
开发环境热重载(develop)
develop 配置用于定义开发环境的行为,配合 docker compose watch 命令实现代码修改后自动同步和重建。这是 Compose v2.22.0 引入的重要特性,极大提升了开发体验。
工作原理:
Compose 监视本地文件系统的变化,根据配置的规则自动执行相应动作。这消除了手动重启容器的繁琐,让开发者专注于代码本身。
services:
app:
build: .
develop:
watch:
# 同步文件到容器(适用于源代码)
- action: sync
path: ./src
target: /app/src
ignore:
- node_modules/
- "*.test.js"
# 重建镜像(适用于依赖变更)
- action: rebuild
path: ./package.json
# 同步并重启服务(适用于配置文件)
- action: sync+restart
path: ./config
target: /app/config
# 同步后执行命令(适用于需要重载的场景)
- action: sync+exec
path: ./nginx.conf
target: /etc/nginx/nginx.conf
exec:
command: nginx -s reload
watch 动作类型:
| 动作 | 说明 | 版本要求 |
|---|---|---|
sync | 同步文件到容器,不重启服务 | v2.22.0+ |
rebuild | 重新构建镜像并重建容器 | v2.22.0+ |
sync+restart | 同步文件后重启容器 | v2.23.0+ |
sync+exec | 同步文件后执行命令 | v2.32.0+ |
restart | 仅重启容器 | v2.32.0+ |
watch 配置选项详解:
| 选项 | 说明 |
|---|---|
path | 监视的本地路径(相对于项目目录) |
action | 变化时执行的动作 |
target | 容器内目标路径(sync相关动作必需) |
ignore | 忽略的文件模式列表 |
include | 只包含的文件模式(与ignore互补) |
initial_sync | 启动时检查文件同步状态 |
exec 配置选项(用于 sync+exec 动作):
| 选项 | 说明 |
|---|---|
command | 执行的命令(必需) |
user | 执行命令的用户 |
privileged | 是否以特权模式执行 |
working_dir | 工作目录 |
environment | 环境变量 |
ignore 和 include 模式语法:
模式匹配语法与 .dockerignore 相同:
*匹配任意数量字符?匹配单个字符**匹配任意层级的目录
develop:
watch:
- action: sync
path: ./src
target: /app/src
ignore:
- "**/*.test.js" # 忽略所有测试文件
- "**/__pycache__/" # 忽略Python缓存目录
- action: rebuild
path: ./src
include: "*.go" # 只监视.go文件
启动开发模式:
# 启动服务并监视文件变化
docker compose watch
# 或先启动服务,再监视
docker compose up -d
docker compose watch
# 只监视特定服务
docker compose watch app
典型应用场景:
| 场景 | 推荐配置 |
|---|---|
| 前端开发 | sync 同步静态资源,rebuild 处理依赖变更 |
| 后端 API | sync+restart 同步代码后重启服务 |
| 配置文件 | sync+exec 同步后重载配置(如 nginx -s reload) |
| 数据库迁移 | rebuild 或手动触发 |
最佳实践:
- 区分文件类型:源代码用
sync,依赖文件用rebuild - 合理使用 ignore:排除测试文件、临时文件,避免不必要的触发
- 注意循环触发:避免同步触发生成新文件,再次触发同步
- 测试环境使用:
develop配置主要服务于开发环境,生产环境通常不使用
当源代码发生变化时,Docker Compose 会自动同步文件或重建镜像,无需手动重启服务。
继承服务配置(extends)
extends 允许从其他服务或文件继承配置,减少重复代码:
# compose.yaml
services:
# 基础服务配置
base:
image: node:18-alpine
working_dir: /app
environment:
NODE_ENV: production
restart: unless-stopped
# 继承基础配置
api:
extends:
service: base
command: node api.js
ports:
- "3000:3000"
worker:
extends:
service: base
command: node worker.js
从其他文件继承:
# compose.yaml
services:
web:
extends:
file: ./common/base.yaml
service: webapp
environment:
APP_ENV: production
继承规则:
- 映射类型(如 environment、labels):子服务覆盖父服务的同名键
- 序列类型(如 ports、volumes):合并两个序列
- 标量类型:子服务覆盖父服务
最佳实践
1. 使用明确的镜像版本
# 不推荐:可能因版本更新导致问题
image: nginx
# 推荐:指定版本
image: nginx:1.25-alpine
2. 配置健康检查
对关键服务配置健康检查,确保依赖服务能正确等待:
services:
db:
image: postgres:15
healthcheck:
test: ["CMD-SHELL", "pg_isready"]
interval: 10s
timeout: 5s
retries: 5
3. 网络隔离
按照服务职责划分网络,提高安全性:
networks:
public: # 对外服务
internal: # 内部服务
internal: true
4. 数据持久化
数据库等需要持久化数据的服务使用命名卷:
volumes:
- db-data:/var/lib/mysql
volumes:
db-data:
5. 不要在镜像中存放敏感信息
使用环境变量或 secrets 传递敏感配置:
services:
api:
environment:
- DATABASE_URL=${DATABASE_URL}
# 或使用 Docker Secrets
secrets:
- db_password
常见问题
服务启动顺序问题
问题:服务启动顺序不正确,导致依赖服务未就绪。
解决方案:使用 depends_on 配合 healthcheck:
services:
app:
depends_on:
db:
condition: service_healthy
redis:
condition: service_started
db:
image: postgres:15
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 10s
timeout: 5s
retries: 5
环境变量不生效
问题:.env 文件中的变量没有被正确读取。
解决方案:
- 确保
.env文件位于项目根目录 - 使用
docker compose config验证变量是否被正确解析 - 检查
.env文件格式,确保没有多余的空格或特殊字符 - 变量名不要使用小写,Compose 只识别大写变量名
# 调试变量配置
docker compose config --environment
容器内访问主机服务
问题:容器内需要访问主机上运行的服务。
解决方案:
services:
app:
extra_hosts:
- "host.docker.internal:host-gateway"
# 或使用特殊域名(Docker Desktop 自动提供)
# host.docker.internal
在容器内可以通过 host.docker.internal 访问主机。
网络隔离问题
问题:服务之间无法通信。
解决方案:
- 确保服务在同一个网络中
- 检查是否使用了默认 bridge 网络(不支持服务名解析)
- 创建自定义网络
services:
app:
networks:
- app-net
db:
networks:
- app-net
networks:
app-net:
数据持久化丢失
问题:容器重启后数据丢失。
解决方案:使用命名卷而非绑定挂载:
services:
db:
volumes:
- db-data:/var/lib/mysql # 命名卷
volumes:
db-data: # 声明命名卷
配置更新不生效
问题:修改 Compose 文件后重新启动,配置没有生效。
解决方案:
# 强制重新创建容器
docker compose up -d --force-recreate
# 或先停止再启动
docker compose down
docker compose up -d
磁盘空间不足
问题:Docker 占用磁盘空间过大。
解决方案:
# 清理未使用的资源
docker compose down -v --rmi all
# 清理悬空镜像
docker image prune
# 查看磁盘使用
docker system df
容器时间不正确
问题:容器内时间与主机不一致。
解决方案:
services:
app:
environment:
- TZ=Asia/Shanghai
volumes:
- /etc/localtime:/etc/localtime:ro
日志过大
问题:容器日志占用大量磁盘空间。
解决方案:
services:
app:
logging:
driver: json-file
options:
max-size: "10m"
max-file: "3"
小结
Docker Compose 是管理多容器应用的标准工具,核心要点如下:
- compose.yaml 文件的基本结构和语法
- 服务配置:镜像、端口、环境变量、数据卷、依赖关系
- 网络和服务隔离
- 常用命令的使用
- 多环境配置方法
- Profiles、YAML 锚点等高级特性
练习
- 创建一个包含 Nginx、Node.js API、PostgreSQL 的 Web 应用栈
- 配置服务健康检查和依赖关系
- 使用多配置文件实现开发和生产环境分离
- 练习常用命令:启动、停止、查看日志、进入容器