DEBUG.WIKI
ZgoCloud:多地区部署,按需选节点;日本、美国、香港、德国
雨云;给项目一台云服务器
RackNerd;$21.99/年 · 1GB KVM

Dockerfile 写入 /etc/hosts 报 Read-only file system

Linux BuildKit 为 RUN 提供受管的只读 hosts 挂载。通过构建参数 add-host 传入名称映射,分别核对构建端点、实际连接和运行时配置。

Dockerfile 在 RUN 中向 /etc/hosts 追加映射,构建直接失败:

/bin/sh: 1: cannot create /etc/hosts: Read-only file system

若使用 Linux BuildKit 构建,这通常不是基础镜像的普通文件权限问题。构建执行环境会把自己管理的 hosts 文件以只读绑定挂载提供给 RUN;切换到 root 或给文件 chmod,不能把只读挂载变成可写。

这篇文章针对构建期间需要访问固定名称的场景。运行中的服务容器如何解析名称,是另一份容器配置,不能靠把构建环境的 hosts 文件烘焙进镜像来替代。

确认出错的是哪一次构建执行

先定位日志中失败的 Dockerfile 行。如果它试图执行 echo ... >> /etc/hosts,而错误明确为只读文件系统,就应检查构建器提供的这个特殊挂载,而不是先修改整个镜像目录的所有权。

Linux BuildKit 的受管挂载包括构建环境的 /etc/hosts。这不表示所有容器中的这个路径都永远只读,也不表示基础镜像的整个根文件系统不能写。不能拿一次 docker run 后的手动编辑结果,推断 RUN 里的挂载状态。

可记录实际构建端点:

docker context show
docker buildx ls
docker buildx inspect

客户端在本地,不保证 builder 也在本地。远程 builder、Docker Desktop 的 Linux 环境或独立 BuildKit 实例,有各自的网络可达范围。给名称填入笔记本上能访问的 IP,并不保证构建容器也能访问。

通过构建参数传入映射

如果构建步骤确实需要一个静态主机映射,删除 Dockerfile 中试图改写 hosts 的 RUN,保留原来的实际下载或编译步骤,在构建命令中传入 --add-host:

docker buildx build \
  --add-host artifacts.example.test:192.0.2.10 \
  --progress=plain \
  --load \
  -t myapp:hosts-check \
  .

artifacts.example.test、192.0.2.10 和镜像标签都是示例,必须替换成已确认的名称、builder 能到达的真实地址及自己的测试标签。最后的 . 表示当前构建上下文;原流程使用其他上下文、Dockerfile、平台或 builder 时,应保留那些参数。

--add-host 将记录交给构建器,让它生成 RUN 所见的 hosts 文件。这个入口不需要让 Dockerfile 获得改写该文件的权限。多个映射可以重复指定该选项,但不要为同一个名称传入互相冲突的地址。

示例的 --load 适用于单平台测试镜像,将结果载入本地镜像存储。已有多平台或推送流水线应保留自己的输出方式,不能为了修 hosts 就无条件改成这个单平台测试命令。

静态映射应由构建配置或 CI 的受控参数管理。地址经常变化且已有可靠 DNS 时,优先核对 builder 的正常名称解析路径;不断修改固定 IP 不是长期替代 DNS 的办法。

分开验证名称映射与实际连接

在允许的本机测试构建中,可以临时加入一个只读 RUN,查看 /etc/hosts 中是否包含预期记录,然后移除诊断输出。文件含有内部地址时,日志也需要按项目的数据访问要求保存。

出现映射只证明构建器把配置传入了 RUN。接下来应让原来失败的只读下载或探测步骤执行,核对它实际连接的服务、响应内容和版本。应用若绕过系统解析、使用自己的 DNS 客户端,可能不查询 hosts 文件;只运行 DNS 查询工具也不能据此判定 hosts 映射失效。

如果名称已经解析,错误变成连接拒绝或超时,应检查目标端口、监听地址、builder 路由及防火墙。不要继续往 hosts 里追加同一名称。若失败的是 HTTPS 证书校验,应保持证书检查,核对域名是否与服务证书匹配,不能因为改了地址就顺手关闭 TLS 验证。

构建使用缓存时,某个 RUN 显示 CACHED 不能证明它这一次重新连接了目标。验收需要确认相关步骤实际执行;按原项目的构建验证策略处理缓存,不为了排查一个名称就删除全部镜像或构建缓存。

构建映射不会成为运行环境的持久配置

构建容器的 hosts 记录用于构建时执行。最终镜像在其他环境启动后,容器运行时仍会准备自己的 hosts 文件。如果应用运行阶段也要使用该名称,应单独配置部署环境并验证,不要把构建成功当成运行时解析已经完成。

同样,不要把宿主机整份 /etc/hosts 复制进镜像:其中可能包含只适用于该机器的记录或内部信息,也不能替代受管的运行环境文件。这里要修的是构建输入,而不是扩大镜像文件的访问权限。

修改前保留 Dockerfile、构建参数和已验收镜像。新构建通过后先核对所需资产,再进入原有应用测试和发布流程。需要回退时恢复构建配置并继续使用上一可用镜像;本次修复不要求变更生产容器、删除数据卷或重启 Docker 服务。