Skip to content

Docker Compose 配置详解

Compose 用一个 YAML 文件描述一组容器及其关系。端口决定宿主机暴露边界,卷决定容器重建后数据是否保留,网络决定服务如何互相发现。

本文按 Compose Specification 解释常用字段、短语法与长语法、多文件覆盖和生命周期命令。2026-09-11 在 Apple silicon macOS、Docker Desktop 4.86.0、Engine 29.7.2 和 Compose 5.3.1 环境实测通过完整示例的配置解析、容器启动、健康检查、HTTP 响应、绑定挂载更新和 Redis 卷持久化。本机 8080 已被占用,实测将宿主机端口改为 18080,容器端口仍为 80;正文保留更常见的 8080 并给出冲突处理方法。其他字段片段用于解释配置关系,具体项目仍应采用官方镜像、容器路径和健康检查。

Compose 文件和项目范围

推荐文件名是 compose.yaml。Compose 以项目为管理边界,默认从文件所在目录推导项目名;可以通过顶层 name、命令行 -p 或环境变量显式设置。服务、网络和命名卷的实际资源名通常带有项目前缀,因此同一配置可以在不同项目名下并存。

bash
docker compose -p demo config
docker compose -p demo up -d

现代 Compose Specification 不要求顶层 version。旧文件中的 version: "3" 可能仍可读取,但不会替代当前 Compose 实现对字段的实际支持判断。

完整配置示例

yaml
services:
  web:
    image: nginx:stable
    ports:
      - "127.0.0.1:8080:80"
    volumes:
      - type: bind
        source: ./html
        target: /usr/share/nginx/html
        read_only: true
    networks:
      frontend:
        aliases: [site]
    depends_on:
      cache: {condition: service_healthy}
    restart: unless-stopped
  cache:
    image: redis:7-alpine
    volumes: [redis_data:/data]
    networks: [frontend]
    healthcheck:
      test: ["CMD", "redis-cli", "ping"]
      interval: 10s
      timeout: 3s
      retries: 5
networks:
  frontend:
    driver: bridge

volumes:
  redis_data:
bash
mkdir -p html
echo 'Compose works' > html/index.html
docker compose config --quiet
docker compose up -d
docker compose ps
curl -fsS http://127.0.0.1:8080

顶层配置

Compose 常用顶层元素包括:

字段作用
name设置 Compose 项目名
services定义需要运行的服务
networks声明服务使用的网络
volumes声明 Docker 管理的命名卷
configs向服务挂载非敏感配置
secrets向服务提供敏感文件

顶层 volumesnetworks 只负责声明资源;具体服务仍需在自身的 volumesnetworks 中引用。已有外部资源可以使用 external: true,此时 Compose 不负责创建或删除。

services:镜像、构建与启动命令

image 使用仓库、名称和标签引用镜像。build 从 Dockerfile 构建镜像;两者同时存在时,拉取和构建行为还受 pull_policy 影响。长期运行的配置应固定经过验证的标签或镜像标识。

yaml
services:
  api:
    build:
      context: .
      dockerfile: Dockerfile
    image: example/api:1.0.0
    command: ["./app", "serve"]

command 覆盖镜像默认 CMDentrypoint 覆盖镜像默认 ENTRYPOINT。修改前先阅读镜像文档;错误覆盖可能跳过初始化脚本。

environment、env_file 与变量插值

environment 把变量传入容器;env_file 从文件加载容器环境变量。Compose 自身还会从 Shell、.env 和命令行参数读取插值值,两者用途不同。

yaml
services:
  api:
    env_file:
      - ./app.env
    environment:
      APP_MODE: production
      DATABASE_PASSWORD: ${DATABASE_PASSWORD:?请在 .env 中设置}

使用 ${NAME:-default} 提供默认值,使用 ${NAME:?message} 在缺少必填值时失败。docker compose config 会渲染变量并可能显示敏感值,共享输出前必须脱敏。

ports 与 expose

短语法通常写为 [HOST_IP:]HOST_PORT:CONTAINER_PORT[/PROTOCOL]

yaml
ports:
  - "127.0.0.1:8080:80"
  - "127.0.0.1:8443:443"

省略 HOST_IP 通常会绑定所有主机接口。反向代理后的应用宜绑定 127.0.0.1;数据库和缓存通常不发布宿主机端口。同一 Compose 网络内的服务使用服务名和容器端口通信。

expose 声明容器端口,但不会发布到宿主机。镜像的 EXPOSE 也不等同于宿主机端口映射。

volumes:命名卷与绑定挂载

命名卷由 Docker 管理,适合数据库和应用数据:

yaml
services:
  db:
    volumes:
      - db_data:/var/lib/postgresql/data
volumes:
  db_data:

绑定挂载把宿主机路径映射到容器。相对路径按主 Compose 文件的目录解析:

yaml
services:
  app:
    volumes:
      - ./config:/app/config:ro

短语法适合简单映射;长语法可以明确 typesourcetargetread_only 和绑定选项。docker compose down 默认保留命名卷,down -v 会删除项目卷。

networks:隔离与服务发现

未显式声明网络时,Compose 会创建默认网络。自定义 bridge 网络可以隔离服务并提供基于服务名和 alias 的 DNS:

yaml
services:
  api:
    networks: [backend]
  db:
    networks: [backend]
networks:
  backend:
    driver: bridge

应用连接数据库时使用 db:5432,不要使用宿主机映射端口;容器内的 127.0.0.1 指向当前容器。固定子网仅用于确有路由要求的场景,并需避免与宿主机、VPN 和其他 Docker 网络冲突。

depends_on、healthcheck 与 restart

短格式 depends_on 只表达启动和停止顺序。需要等待依赖健康时使用长格式,并在依赖服务定义真实 healthcheck

yaml
depends_on:
  db:
    condition: service_healthy

healthcheck 的命令在容器内执行,必须保证镜像包含对应工具。restart: unless-stopped 负责进程退出后的重启,不证明应用可用,也不能替代应用连接重试和外部监控。

configs 与 secrets

configs 适合非敏感配置文件,secrets 适合密码、证书或令牌文件。两者在顶层声明并由服务引用:

yaml
services:
  app:
    configs: [app_config]
    secrets: [database_password]
configs:
  app_config:
    file: ./app.conf
secrets:
  database_password:
    file: ./secrets/database-password.txt

本地 Compose 的文件型 secret 仍依赖宿主机文件权限。不要把 secret 源文件提交到公开仓库。

profiles 与可选服务

profiles 让调试或管理服务只在指定场景启动:

yaml
services:
  toolbox:
    image: alpine:3.21
    command: ["sleep", "infinity"]
    profiles: [debug]

默认执行 docker compose up -d 不会启动 toolbox;使用 docker compose --profile debug up -d 才会启用。

多文件合并与复用

基础配置和生产覆盖可以分开保存:

bash
docker compose -f compose.yaml -f compose.prod.yaml config
docker compose -f compose.yaml -f compose.prod.yaml up -d

后一个文件会按 Compose 合并规则覆盖或追加字段,路径解析和序列合并并不都等同于简单文本覆盖。发布前必须检查最终 config 输出。x- 扩展字段和 YAML anchors 可以减少重复,但过度复用会降低可读性。

日志与资源设置

日志轮转可以限制本地日志增长:

yaml
logging:
  driver: json-file
  options: {max-size: "10m", max-file: "3"}

资源限制的可用字段取决于 Compose 实现和运行模式。不要默认认为 Swarm 的 deploy.resources 在所有单机 Compose 环境中具有完全相同的行为。

生产环境安全加固

限制发布端口,保护 .env 和 Docker socket,配置日志轮转,并在执行删除卷前先备份。

生命周期与更新

bash
docker compose pull
docker compose up -d
docker compose logs --tail=100 web
docker compose restart web
docker compose stop
docker compose down

升级前先备份卷和数据库,运行 docker compose config --quiet,保留旧镜像和配置。数据库迁移可能不可逆,回滚应恢复升级前备份。危险操作: docker compose down -v 和全局 prune 命令可能删除数据,执行前先备份并确认范围。

验证配置与运行结果

bash
docker compose ps
docker compose logs --tail=100 web
docker inspect "$(docker compose ps -q cache)" --format '{{json .State.Health}}'
curl -fsS http://127.0.0.1:8080

修改 html/index.html 后无需重建容器;再次请求页面应立即看到新内容,证明绑定挂载有效。

只运行 docker compose config --quiet 属于静态校验;只有启动容器并检查状态、日志、应用响应和数据持久化后,才能声称完成运行验证。

常见问题

服务无法连接缓存

确认服务加入同一网络,并使用 cache:6379;执行 docker network inspect 检查成员。

端口冲突

bash
ss -ltnp | grep ':8080 ' || true

更换宿主机端口,容器端口保持 80。

网络地址池耗尽

检查 docker network lsdocker network inspect bridgeip route,确认 VPN 与 Docker 子网不重叠。

配置完成后

将 Compose 文件纳入版本控制,将 .env 交给密钥管理,为卷和数据库设置异机备份,并在升级前完成恢复演练。

总结

Compose 把服务、构建、命令、变量、端口、卷、网络、依赖和健康检查集中到一个可审阅文件。先用 docker compose config 查看最终模型,再执行启动和分层验收,可以在修改生效前发现大部分配置错误。

参考资料

全部公开文章由同一个站点构建和发布。