用一个 YAML 文件定义多个容器,一个命令启动整个应用栈。本篇采用 Compose v2 风格的
docker composeCLI;具体 profiles/watch/develop 功能要求对应版本,第三方兼容实现应逐项验证。
Compose 是什么?#
# 没有 Compose:手动逐条启动
docker network create appnet
docker run -d --name db --network appnet -e POSTGRES_PASSWORD_FILE=/run/secrets/db_password --mount type=bind,src=/path/to/protected-password-file,dst=/run/secrets/db_password,readonly -v pgdata:/var/lib/postgresql/data postgres:16-alpine
docker run -d --name api --network appnet -e DB_HOST=db -p 3000:3000 myapi
docker run -d --name web -p 80:80 --network appnet nginx
# 有 Compose:一个文件 + 一个命令
docker compose up -dcompose.yaml 结构#
# compose.yaml(默认文件名)
# 注意:v2 不再需要 version: 字段!
services: # 所有服务定义
db:
image: postgres:16-alpine
restart: always
environment:
POSTGRES_PASSWORD: ${DB_PASSWORD:?provide a local database password} # 插值示意;生产考虑 secret 文件
POSTGRES_DB: app
volumes:
- pgdata:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 5s
retries: 10
start_period: 30s
api:
build: ./api # 从 ./api/Dockerfile 构建(而不是拉现成镜像)
restart: always
ports:
- "3000:3000"
environment:
DATABASE_URL: postgresql://postgres:${DB_PASSWORD}@db:5432/app
depends_on:
db:
condition: service_healthy # 等 db 健康检查通过后再启 api
develop: # watch mode(compose v2.22+)
watch:
- action: sync
path: ./api/src
target: /app/src
web:
image: nginx:alpine
restart: always
ports:
- "80:80"
volumes:
- ./nginx.conf:/etc/nginx/conf.d/default.conf:ro
depends_on:
- api
volumes:
pgdata: # 声明命名卷常用命令#
# 启动(构建 + 创建 + 启动所有服务)
docker compose up -d
# └┘ 后台模式
# 启动并重新构建(代码改了需要重新 build)
docker compose up -d --build
# 只启动指定服务 + 依赖
docker compose up -d api
# 查看所有服务状态
docker compose ps
# 查看日志
docker compose logs -f # 所有服务
docker compose logs -f api # 只看 api
# 在运行中的服务里执行命令
docker compose exec api bash
# 停止所有服务
docker compose stop
# 停止并删除容器、网络(保留卷)
docker compose down
# 还删除声明的非 external 命名卷及匿名卷;先备份,external 卷不由 down 删除
docker compose down -v
# 重启单个服务
docker compose restart api
# 拉取所有服务的最新镜像
docker compose pullProfiles:按场景启停服务#
同一份 compose 文件,按需启用不同服务:
services:
api:
image: myapp:latest # 没有 profiles → 总是启动
db:
image: postgres:16-alpine
profiles: [full, production] # 只在指定 profile 下启动
redis:
image: redis:alpine
profiles: [production]
pgadmin:
image: dpage/pgadmin4
profiles: [tools] # 开发时才用的管理工具
mailhog:
image: mailhog/mailhog
profiles: [dev] # 开发时捕获邮件# 默认只启动无 profile 的服务(api)
docker compose up -d
# 启动 full profile 下所有服务(api + db)
docker compose --profile full up -d
# 启动多个 profile
docker compose --profile dev --profile tools up -dWatch Mode:开发时自动同步#
Compose v2.22+ 可使用 watch;sync+restart 需 2.23.0+,其他动作按对应文档核对:
services:
api:
build: .
develop:
watch:
- action: sync # 文件变了 → 直接同步到容器(快)
path: ./src
target: /app/src
- action: rebuild # package.json 变了 → 重新构建镜像(慢)
path: ./package.json # rebuild 使用构建上下文,不需 target
- action: sync+restart # 配置文件变了 → 同步 + 重启容器
path: ./config
target: /app/configdocker compose up --watch
# 修改 ./src 代码 → 自动同步到容器
# 修改 package.json → 自动重新构建环境变量与 Secrets#
.env 文件
下面是不可直接执行的占位格式;真实凭据应由受控文件或秘密管理工具提供,不能把它们写入公共示例。
# .env(放在 compose.yaml 同级目录,加入 .gitignore)
DB_PASSWORD=<从受控凭据来源提供>
API_KEY=<从受控凭据来源提供># compose.yaml 中引用
services:
db:
environment:
POSTGRES_PASSWORD: ${DB_PASSWORD} # 自动从 .env 读取Compose 文件 secrets 与 Swarm secrets
# 以下 external secret 由 Swarm 管理;普通 Compose 可改用 file: 来源
secrets:
db_password:
external: true # 预先用 docker secret create 创建
services:
db:
secrets:
- db_password
environment:
POSTGRES_PASSWORD_FILE: /run/secrets/db_password覆盖文件(Override)#
多环境管理:基础文件 + 环境覆盖文件。
# compose.yaml(基础配置)
services:
api:
image: myapp:latest
ports:
- "3000:3000"
db:
image: postgres:16-alpine# compose.prod.yaml(生产环境覆盖)
services:
api:
restart: always
deploy:
resources:
limits:
memory: 512M
environment:
NODE_ENV: production
db:
restart: always
volumes:
- prod-pgdata:/var/lib/postgresql/data
volumes:
prod-pgdata:# 开发环境(只用基础文件)
docker compose up -d
# 生产环境(基础 + 覆盖)
docker compose -f compose.yaml -f compose.prod.yaml up -d生产环境使用建议#
详细生产实践见 第六篇 生产部署实践。关键原则:
| 原则 | 做法 |
|---|---|
不要用 latest 标签 |
固定版本或 digest |
| 选择合适的 restart 策略 | 处理退出;单机 unhealthy 状态不自动触发 restart |
| 设置健康检查 | 配合 depends_on condition: service_healthy |
| 限制资源 | deploy.resources.limits |
| 用覆盖文件管理环境 | -f compose.yaml -f compose.prod.yaml |
审查后使用 --remove-orphans |
会删除本项目未再声明的服务容器,先确认数据和范围 |
普通 Compose 也支持 secrets
secrets:
db_password:
file: ./protected/db_password.txt
services:
db:
image: postgres:16-alpine
secrets: [db_password]
environment:
POSTGRES_PASSWORD_FILE: /run/secrets/db_password普通 Compose 从受控源文件挂载 secret,不自动获得 Swarm 的 Raft 加密和分发机制;保护源文件与部署权限。.env 用于插值,不会自动把所有变量注入容器,也不是加密凭据存储,docker compose config 输出可能包含插值后的秘密,避免公开。
启动与依赖边界
短格式 depends_on 只排序启动,不保证应用已经就绪;健康条件等待检查成功,但不持续保证依赖之后永远健康。连接重试和故障处理仍由应用承担。无 profile 的服务默认启用,显式指定带 profile 的服务还会启动该服务及必要依赖,并不自动启用同 profile 的所有其他服务。固定 host ports 的服务不能简单扩成多个副本。
profiles、override 和 secret 各节是独立配置片段,需合并完整服务的镜像、数据库凭据、健康工具和端口设置后才可运行;此处不是经过运行验证的完整项目。
参考与延伸
根据技术笔记重新整理,示例使用通用名称。