跳到主要内容

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
  • 新增了 includedevelopdepends_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}"

变量来源优先级(从高到低):

  1. Shell 环境变量
  2. --env-file 指定的文件
  3. 项目目录下的 .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(默认)、globalreplicated-jobglobal-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 参数说明

参数说明
pathCompose 文件路径,可以是字符串或列表
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 处理依赖变更
后端 APIsync+restart 同步代码后重启服务
配置文件sync+exec 同步后重载配置(如 nginx -s reload)
数据库迁移rebuild 或手动触发

最佳实践

  1. 区分文件类型:源代码用 sync,依赖文件用 rebuild
  2. 合理使用 ignore:排除测试文件、临时文件,避免不必要的触发
  3. 注意循环触发:避免同步触发生成新文件,再次触发同步
  4. 测试环境使用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 文件中的变量没有被正确读取。

解决方案

  1. 确保 .env 文件位于项目根目录
  2. 使用 docker compose config 验证变量是否被正确解析
  3. 检查 .env 文件格式,确保没有多余的空格或特殊字符
  4. 变量名不要使用小写,Compose 只识别大写变量名
# 调试变量配置
docker compose config --environment

容器内访问主机服务

问题:容器内需要访问主机上运行的服务。

解决方案

services:
app:
extra_hosts:
- "host.docker.internal:host-gateway"
# 或使用特殊域名(Docker Desktop 自动提供)
# host.docker.internal

在容器内可以通过 host.docker.internal 访问主机。

网络隔离问题

问题:服务之间无法通信。

解决方案

  1. 确保服务在同一个网络中
  2. 检查是否使用了默认 bridge 网络(不支持服务名解析)
  3. 创建自定义网络
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 锚点等高级特性

练习

  1. 创建一个包含 Nginx、Node.js API、PostgreSQL 的 Web 应用栈
  2. 配置服务健康检查和依赖关系
  3. 使用多配置文件实现开发和生产环境分离
  4. 练习常用命令:启动、停止、查看日志、进入容器

参考资料