【问题标题】:Why is docker build running a command in an intermediate container that is then removed resulting in the command being ignored?为什么 docker build 在中间容器中运行命令,然后将其删除导致命令被忽略?
【发布时间】:2019-09-12 05:37:34
【问题描述】:

由于无法确定应用于 Linux 容器的 docker 默认名称服务器地址的原因,导致无法解析外部地址。我正在尝试通过在 resolv.conf 文件上使用 sed 命令来更新名称服务器地址,但是在命令运行后,docker 似乎删除了运行它的图像,导致名称服务器没有被更新。

当 docker build 在我的 Windows 机器上创建 Linux 容器时,生成的容器在 resolv.conf 中的名称服务器值为 192.168.65.1。我无法解决任何设置为这样的uris。我什至无法 ping google.com。如果我更新名称服务器以使用 Google 的 DNS 8.8.8.8,我可以 ping 其他主机并成功运行引发问题的命令(dotnet restore)。

我构建了一个将我的文件复制到 /src 的映像,然后以交互方式运行它以尝试调试。我通过运行以下命令解决了我的问题

# copy resolv.conf because I can't run sed on it directly
RUN cp /etc/resolv.conf /etc/resolv.conf.temp
# make my change to the temp file
RUN sed -i 's/192.168.65.1/8.8.8.8/' /etc/resolv.conf.temp
# copy the modified file over original
RUN cp /etc/resolv.conf.temp /etc/resolv.conf    

在容器中以交互方式运行,然后我可以在我的 src 文件上成功调用 dotnet restore。

但是,当我在 Dockerfile 中包含这些指令并构建映像时,复制发生了,sed 命令发生在临时文件上,并且 copyover 命令似乎发生了,但生成的映像仍然具有原始的 192.168.65.1 名称服务器值。

在第二个cp之后添加这个命令:

RUN cat /etc/resolv.conf

确认运行 cat 命令时原始 resolv.conf 内容完好无损。

这是构建输出的相关部分:

Step 9/12 : RUN cp /etc/resolv.conf /etc/resolv.conf.temp
 ---> Running in cf8e037f5675
Removing intermediate container cf8e037f5675

 ---> 53f1c8bb86c6
Step 10/12 : RUN sed -i 's/192.168.65.1/8.8.8.8/' /etc/resolv.conf.temp
 ---> Running in 14b6a8381261
Removing intermediate container 14b6a8381261
 ---> 22039e11f812

Step 11/12 : RUN cp /etc/resolv.conf.temp /etc/resolv.conf
 ---> Running in 46d295d869bf
Removing intermediate container 46d295d869bf
 ---> ea1a18576f87

Step 12/12 : RUN cat /etc/resolv.conf
 ---> Running in 6cb4726e58cb
# This configuration is written to the config.iso
nameserver 192.168.65.1
search mycompany.local
domain mycompany.local
Removing intermediate container 6cb4726e58cb
 ---> 5ad060514a74
Successfully built 5ad060514a74

我希望构建的映像具有从步骤 10 和 11 设置的新名称服务器值,但事实并非如此,看起来工作正在进行中,但中间映像被丢弃,我不明白为什么以及是什么正确的解决方法是。

【问题讨论】:

  • Dockerfile 的基础镜像是什么?
  • microsoft/dotnet:2.2-sdk
  • 在这里使用sed -i 完全没有意义。 -i 本身告诉sed 创建一个临时文件,将更改写入其中,然后用该临时文件覆盖原始文件。为什么要使用该操作修改本身就是一个临时文件的东西,而不是直接在/etc/resolv.conf 上使用sed -i
  • @CharlesDuffy 关于为什么我首先在​​原始 resolv.conf 上创建临时文件而不是 sed -i。根据this unix.se question中的响应者,不允许更改 docker inode。我得到了在尝试在最初安装的文件上运行 sed -i 的问题中描述的相同行为。 unix.stackexchange.com/questions/404189/…

标签: docker dockerfile


【解决方案1】:

名称服务器可以通过将它们传递给 docker daemon 来添加到 docker 容器中。

在文件 /etc/docker/daemon.json 中,添加 "dns":["172.16.3.241", "127.0.0.1", "8.8.8.8", "8.8.4.4"] 或添加 dns--dns 127.0.0.1 --dns 8.8.8.8 --dns 8.8.4.4 到 docker daemon。

【讨论】:

  • 我正在使用 Docker for Windows。我试图将 Docker 桌面客户端中的 DNS 设置从自动更改为固定(8.8.8.8),但没有成功。根据 Microsoft 文档,我还尝试添加具有以下值的配置文件:{ "dns": ["8.8.8.8"] } 到 C:\ProgramData\Docker\config\config.json 但也没有变化。生成的 Linux 容器 resolv.conf 最终名称服务器值为 192.168.65.1
  • 只是想确认一下,你在修改配置后重启了docker。
  • 我重新启动了 Docker 服务,没有任何变化,我继续完全重新启动并重建了映像,但生成的容器没有任何变化。
【解决方案2】:

您可以在构建容器映像后更改容器的 DNS 设置,参见。 the Docker docs.

小例子:

Dockerfile:

FROM alpine

CMD ["cat", "/etc/resolv.conf"]

在同一个文件夹中,运行:

docker build --tag foo . && docker run --rm --dns-search=foo.bar --dns=8.8.8.8 foo

输出将显示:

search foo.bar
nameserver 8.8.8.8

【讨论】:

  • 不幸的是,我需要更改名称服务器才能成功完成构建。以下是操作的顺序: 1. 复制源文件 2. 运行 dotnet restore (.net 包管理器) 3. 运行 dotnet build 如果在运行第 2 步之前名称服务器保持 192.168 值,则包管理器无法解析源和失败。
  • 我不确定我是否完全理解这个问题。 192.* 在你的resolv.conf 中是dotnet restore 的条件吗?我不熟悉这个包管理器。 echo "nameserver 8.8.8.8" >> /etc/resolv.conf 不会解决你的问题吗?如果不是,为什么?
  • echo 命令本身确实有效,我认为问题在于 docker 立即删除了执行命令的中间容器。来自 docker build 输出:Step 9/10 : RUN echo "nameserver 8.8.8.8" >> /etc/resolv.conf ---> Running in 57838da7f84c Removing intermediate container 57838da7f84c
  • 移除中间容器是 Docker 做的正常事情。您可以在构建映像时使用--rm=false 避免这种情况。虽然我认为这不是一个好的解决方案 - 为什么 echo 方式在您的情况下还不够?
  • 您在这里找到解决方案了吗?您是否尝试将echo 部分放在与dotnet restore 发生的相同RUN 部分中,或者任何需要其他DNS 服务器的命令?
猜你喜欢
  • 2018-05-20
  • 1970-01-01
  • 2020-06-24
  • 1970-01-01
  • 2017-07-10
  • 2019-03-08
  • 2023-02-04
  • 1970-01-01
  • 2021-04-08
相关资源
最近更新 更多