应使用 extends 实现模块化复用,核心是将共性配置抽为独立服务模板(如 base-app、redis-base),主文件按需继承并轻量覆盖;路径与变量自动重解析,避免与 override 混用。

直接用 extends 实现模块化复用,关键不在“能不能写”,而在“怎么分层才不打架、不隐晦、不难维护”。核心是把共性抽成可继承的“配置块”,再按场景精准扩展,而不是堆砌 YAML 技巧。
把基础能力拆成独立服务模板
不要在主 docker-compose.yml 里定义具体业务服务时顺手写一堆通用配置。先建一个 common-services.yml,只放真正跨项目、跨环境都一致的骨架:
- 用
services.base-app定义镜像、日志驱动、健康检查、默认资源限制等基础项 - 用
services.redis-base封装 Redis 的标准启动命令、持久化卷、网络策略 - 每个模板只做一件事,不带端口、不挂本地路径、不写环境变量值(留占位符)
主文件中按需继承 + 轻量覆盖
在项目自己的 docker-compose.yml 中,用 extends 引入模板,再只加差异化部分:
-
web:→extends: {file: common-services.yml, service: base-app},再补ports和environment -
worker:→ 同样继承base-app,但覆盖command和deploy.resources - 所有继承来的字段(如
volumes、networks)自动生效,无需重复声明
路径与变量必须对齐,否则继承失效
extends 不是简单复制粘贴,它会重解析路径和变量作用域:
- 外部文件中的
build: ./src,会被自动转为相对于主 compose 文件的路径 -
env_file: .env在模板里写,实际加载的是主文件所在目录下的.env - 环境变量如
${DB_HOST}仍由主文件的环境或.env提供,模板里不预设值
避免和 override 混用导致行为不可控
extends 是编译期继承,-f docker-compose.prod.yml 是运行时合并 —— 两者逻辑不同,强行混用容易覆盖错:
- 想统一改所有服务的日志大小?在
common-services.yml的base-app里改 - 只想让生产环境关掉调试日志?用
docker-compose.prod.yml单独覆盖environment - 不要在一个 override 文件里又写
extends,会增加理解成本和调试难度











