DEBUG.WIKI
V.PS:让项目靠近用户,亚太、欧洲、北美 KVM VPS
IPPeak:从目标地区访问网页,住宅代理、SEO 监测、广告验证
ZgoCloud:多地区部署,按需选节点;日本、美国、香港、德国

Docker Compose 覆盖网络配置后报 network_mode 与 networks 互斥

覆盖文件新增 networks 不会自动删除基础文件的 network_mode。通过 !reset 清除继承值,核对实际 Compose 版本、文件顺序及切换网络后的通信变化。

基础文件中的服务使用 network_mode,在覆盖文件里给同一个服务添加 networks 后,Compose 拒绝加载项目:

service app declares mutually exclusive `network_mode` and `networks`: invalid compose project

这是合并后的配置同时保留了两种网络声明。覆盖文件不会把服务定义整体替换掉:新增 networks,并不会自动删除基础文件中的 network_mode。反复创建 Docker 网络不能消除这个配置冲突。

下面讨论用多个 Compose 文件切换网络模式的情况,处理方式要求当前 Compose 实现支持 !reset 标签。如果部署平台还会生成额外配置,要检查它最终提交给 Compose 的文件,而不只是编辑器中的源文件。

先确认参与合并的文件和顺序

在执行部署的同一环境检查插件版本,并用实际文件列表查看合并结果:

docker compose version
docker compose -f compose.yaml -f compose.override.yaml config

文件名是示例,应与部署命令使用的路径和顺序一致。后面的文件覆盖或补充前面的文件;如果 CI 又追加了第三个文件,也要一起检查。

config 本身也可能因为互斥声明而失败。这说明模型仍未通过验证,不必先启动容器。修正后再运行它,核对完整结果。配置输出可能包含插值后的环境变量,保存或分享前应检查敏感值。

Compose 文件里的 version: '3.4' 不是安装的 Compose 程序版本,不能用它判断标签支持情况。应看部署环境的 docker compose version,尤其不要只在个人电脑上检查,而忽略 CI 或远程面板使用的另一个版本。

添加 networks 的同时清除 network_mode

假设基础文件 compose.yaml 包含:

services:
  peer:
    image: example/peer:approved
  app:
    image: example/app:approved
    network_mode: "service:peer"

这里的两个镜像名是占位值,实际使用时替换为已批准的应用镜像。基础配置让 app 共享 peer 的网络命名空间。

如果新环境要让 app 独立加入 appnet,覆盖文件应显式清除原声明:

services:
  app:
    network_mode: !reset ""
    networks:
      - appnet

networks:
  appnet: {}

!reset 表示清除从前面文件继承的值,将目标属性重置为其类型默认值或空值。这里保留一个合法的空字符串值供标签处理;真正起清除作用的是标签,而不是把 networks 写在后面。

不要给整段 !reset "" 加上引号,那会把标签变成普通字符串。也不要把本例理解为“服务只剩覆盖文件中的字段”:基础文件里的镜像和其他未被覆盖的配置仍会参与合并。

修改后再次运行相同的 config 命令,预期 app 的最终配置包含 appnet,且不再保留原来的非空 network_mode。peer 服务仍然存在;清除网络模式不会顺便删除它。

标签不被识别时,检查执行工具

如果实际 Compose 命令报未知 YAML 标签,先处理工具支持问题。编辑器单独标红不等于 Compose 一定不能运行;反过来,编辑器没有提示也不能替代命令行验证。

可更新到组织允许、支持该语法的 Compose 版本,再复核最终模型。暂时不能更新时,可以为该环境维护一个完整的独立 Compose 文件,去掉不需要的 network_mode,写入需要的 networks,然后只加载这一份文件。不要把这个完整文件仍作为覆盖文件追加到原基础文件后,否则旧字段可能再次进入合并结果。

独立文件需要保留原部署必需的卷、环境变量、健康检查和其他设置,也会增加后续维护工作。相比为了消除一个错误就删除共享基础文件中的网络声明,这种做法更容易限定影响范围。

配置通过后核对通信方式

从 network_mode: "service:peer" 改为独立网络后,app 不再与 peer 共享网络命名空间。之前通过 localhost 访问同伴进程的地址可能需要调整。

如果还需要通过 Compose 服务名访问 peer,两者应加入同一个合适的网络,并使用对方实际监听的容器端口。仅在顶层声明 appnet 不会自动把所有服务加入它。本例只给 app 加入了该网络,不应据此假设它已经能解析和访问 peer。

如果原来的同伴承担 VPN、代理或网络隔离职责,改成独立网络还可能改变流量路径。应先确认这是预期的部署变化;若仍需共享同伴网络,就保留 network_mode,不要添加相冲突的 networks。

确认通信设计后,在维护窗口保存原配置、镜像版本及必要数据备份,再使用与检查相同的文件组合更新服务:

docker compose -f compose.yaml -f compose.override.yaml up -d app

配置变化可能导致容器被重新创建并短暂中断连接。已有应用应安排停机影响与恢复路径,不要为清理这个错误执行删除卷操作。

更新后检查应用启动状态、实际网络连接及必要的进出站请求。config 通过只说明模型有效,不证明应用的监听地址、DNS 名称和依赖连接已经正确。若网络切换不符合预期,恢复之前保存的文件组合并重新应用;仅把旧文件放回磁盘,不会自动改变已经创建的容器。