Compose 服务能解析内网域名,构建 RUN 却解析失败
服务 networks 不决定构建 RUN 的网络。区分 BuildKit 网络模式与项目网络,并在固定端点场景配置构建侧名称映射。
同一个 Compose 项目中,启动后的服务能解析内网仓库域名,docker compose build 却在 Dockerfile 的 RUN 步骤里报 Could not resolve host。给服务添加 networks,或修改顶层 networks.default 后,构建仍然失败。
服务容器加入的网络与构建器执行 RUN 时使用的网络是两套配置。运行中的服务解析成功,不能证明构建步骤使用同一个 DNS 环境;项目网络名叫 default,也不表示构建器的 default 模式会连接它。
下面针对现代 Docker Compose V2、BuildKit 和 Linux 容器,处理构建过程中访问内网依赖的场景。镜像仓库登录、拉取 FROM 镜像失败,以及已经能解析但连接超时,不能仅凭相同项目名归到这个原因。
先确认失败发生在 RUN 内
保留第一次失败日志,找到报错前的构建步骤。如果已经开始执行 RUN 里的包管理器、Git 或下载程序,再检查它实际访问的域名。请求经代理发出时,还应分清无法解析的是代理地址还是目标地址。
核对使用的工具与构建器:
docker version
docker compose version
docker buildx ls
记录实际选中的 builder、驱动和服务端位置。远程构建器不在本机网络中;本机能解析某个名称,不能证明远端构建进程也能解析。保留原来的 Compose -f、项目、环境文件以及 --builder 参数,避免诊断时换了一套构建环境。
随后检查合并后的 Compose 模型,重点对照目标服务的 build.network、build.extra_hosts 与服务级 networks。完整 docker compose config 输出可能包含敏感值,只在可信终端查看,不直接上传日志。
build.network 的 default 不是项目的 default 网络
在当前 BuildKit 配置中,build.network 选择的是构建网络模式:default、none 或 host。它不是对顶层 networks 键的引用。把项目里的 backend、myproject_default 填进去,不应被当作通用的“让构建加入服务网络”方案。
以下片段只说明两处配置的位置:
services:
app:
build:
context: .
network: default
networks:
- backend
networks:
backend: {}
backend 用于启动后的 app 服务;RUN 仍按 builder 的 default 模式执行。如果实际合并配置中是 build.network: none,构建步骤没有网络访问能力,应先核对是否误用了离线构建配置。
旧构建器能够接受自定义网络名称的配置,不足以证明现代 BuildKit 也支持相同写法。升级之后应核对实际构建器能力,不能通过创建更多同名 Compose 网络来修复模式不支持的错误。
只有少量固定内网端点时,配置构建侧名称映射
若已经确认失败仅在名称解析层,目标有经过管理员确认的固定地址,而且该地址从构建网络可达,可以在 build.extra_hosts 中加入映射。下面是需合并到现有目标服务中的片段:
services:
app:
build:
context: .
network: default
extra_hosts:
- "packages.internal.example=192.0.2.20"
域名与 192.0.2.20 都是占位值,后者属于文档示例地址,必须换成获准使用的真实端点。保留原有 Dockerfile、构建参数、上下文路径等配置;不要用片段覆盖完整部署文件。
这里的 extra_hosts 位于 build 内部,给构建步骤提供名称映射。在服务下与 build 同级添加的 extra_hosts 用于运行中的服务,不能代替这一项。它也不是给构建器增加一台 DNS 服务器,而是为指定名称提供固定地址。
静态映射只解决符合上述条件的名称解析问题,不会增加路由、开放防火墙、启动另一个服务,也不会替应用完成身份验证。HTTPS 请求仍应使用原域名,保留证书验证;不要改成 IP URL 后再加 -k 绕过名称与证书不匹配。
若目标地址会变、域名数量多,或应用使用自己的 DNS 查询方式,应修正所选 builder 的解析与网络接入,而不是长期维护一大串 hosts 条目。构建器由独立容器、远端节点或集群托管时,应在对应构建基础设施上处理,不要把本机运行服务的网络配置当作其配置入口。
不把 host 模式当作默认绕过办法
build.network: host 会改变构建步骤的网络隔离边界,需要构建端允许 network.host 权限。是否可用还取决于驱动、平台与构建服务的策略,不能把它等同于“直接使用正在敲命令的电脑的网络”。
仅当构建代码可信、确有此需求且基础设施允许时,才按该构建环境的权限规则评估使用。不要为了让一个私有域名解析成功,就给不可信 Dockerfile 开放宿主网络、暴露数据库端口,或关闭现有网络隔离。
如果构建步骤实际上依赖 Compose 中另一个运行服务,先明确依赖的生命周期与可重现方式。单独改 build.network 不负责启动或等待这个服务;修复 DNS 也不能保证它已经准备好。
在同一构建阶段验证,并保留回退配置
保存改动前的 Compose 文件,然后先做配置检查。在隔离的测试构建环境中重建目标服务,保留原有连接和项目参数:
docker compose config --quiet
docker compose build --no-cache app
先确认配置检查成功,再执行构建。--no-cache 会重新执行构建步骤,可能重新下载依赖并执行 Dockerfile 中的程序;这里只用于受控验证,不能把它当作无副作用的网络探针,也不需要清空所有构建缓存。
验收要看原先失败的 RUN 是否真正执行、访问了预期依赖并完成正常校验。命中旧缓存没有验证这次解析配置;错误变成证书、认证或连接超时,也不表示整个构建已修好,应按新的失败层继续处理。
记录固定映射的维护责任和有效范围。端点调整或此次修改不符合预期时,恢复原配置并重新验证构建;配置回退不会删除已经产生的镜像或撤销构建脚本的外部副作用。确认新镜像通过原有测试与发布检查后,再走部署流程,诊断构建不应顺带更新正在运行的服务。


