如何在“docker build”期间更新 Docker 映像中的 /etc/hosts 文件

Posted

技术标签:

【中文标题】如何在“docker build”期间更新 Docker 映像中的 /etc/hosts 文件【英文标题】:How to update /etc/hosts file in Docker image during "docker build" 【发布时间】:2016-11-13 03:50:30 【问题描述】:

我想在“docker build”期间更新我的/etc/hosts 文件。

我在 Dockerfile 中添加了以下行,但它既没有更新 /etc/hosts 文件也没有给出任何错误。

RUN echo "192.168.33.11    mynginx" >> /etc/hosts

我需要更新/etc/hosts。有人可以就此提出建议吗?

【问题讨论】:

你在使用 boot2docker 来执行你的 docker build 吗? 不,我使用的是 docker 1.8 的 Linux 版本。 当您将镜像作为容器运行时,它的 /etc/hosts 是否不变?还是您指的是您的 Linux 主机 /etc/hosts? 在 docker build 映像成功构建期间。但是当我使用相同的映像运行容器并检查 /etc/hosts 文件时,没有更改。 【参考方案1】:

对于更新版本的 docker,这可以通过 docker-compose 及其 extra_hosts directive 来完成

添加主机名映射。 使用与docker run client --add-host parameter 相同的值(应该已经可用于 docker 1.8)。

extra_hosts:
 - "somehost:162.242.195.82"
 - "otherhost:50.31.209.229"

简而言之:在运行容器时修改/etc/hosts,而不是在构建容器时。


使用 Docker 17.x+,你有一个 docker build --add-host 提到 below,但是,正如 issue 34078 和 this answer 中所评论的:

构建期间的--add-host 功能旨在允许在构建期间覆盖主机,但不会将该配置保留在映像中。

提到的解决方案确实参考了我上面建议的 docker-compose:

运行内部 DNS;您可以设置在守护程序中使用的默认 DNS 服务器;这样,每个启动的容器都会默认自动使用配置的 DNS
使用 docker compose 并向您的开发人员提供 docker-compose.yml。 docker compose 文件允许您指定启动容器时应使用的所有选项,因此开发人员只需 docker compose up 即可使用他们需要设置的所有选项来启动容器。

【讨论】:

我想更改 docker 镜像中的 /etc/hosts。 @PrakashSingh 我同意,但这似乎并不容易做到。 @PrakashSingh 你可以通过docket exec -it <container name> /bin/bash在机器上打开一个bash实例,然后用你喜欢的命令行编辑器(vim、emacs、nano、echo)更新/ect/host下的docker容器主机'' . >>/>). @PrakashSingh 是的,我们可以(听起来很熟悉......)。但是当我们通过构建镜像而不是运行容器来更改主机条目时,它看起来就像 Docker 的一种黑客攻击。 Docker 网络设计是应用程序驱动的(来自 docker.com)。由于 hosts 入口是 docker 网络的一部分,我们最好在从镜像运行容器时定义它。如果你真的需要添加一些hosts入口,你不要每次都通过build image来添加它们,你将它们添加到base image中一次。这是最佳做法。 在 docker build --add-host:cran.rstudio.com 期间解决 rocker/shiny install.packages 的问题: 为我解决了这个问题。【参考方案2】:

您不能在RUN 步骤中使用echo 修改映像中的主机文件,因为当您从映像启动容器时,docker daemon 将维护文件(/etc/hosts)及其内容(主机条目) .

但是可以使用以下方法来实现相同的目的:

ENTRYPOINT ["/bin/sh", "-c" , "echo 192.168.254.10   database-server >> /etc/hosts && echo 192.168.239.62   redis-ms-server >> /etc/hosts && exec java -jar ./botblocker.jar " ]

这里要注意的关键是使用 docker 文档建议的 exec 命令。使用 exec 将使 java 命令成为容器的 PID 1。 Docker 中断只会对此做出响应。

见https://docs.docker.com/engine/reference/builder/#entrypoint

【讨论】:

泰!这是一个很好的解决方案 如果您正在寻找 kubenetes 解决方案,您可以使用 hostAliases。 kubernetes.io/docs/concepts/services-networking/… 就像 docker compose extra_hosts。 更准确地说,ENTRYPOINT 不是图像指令。它仅在我们从该镜像运行容器时标记一个入口点,这意味着主机条目仅在容器运行后才存在。我不认为这个要求是必要的。一定是有什么误会。【参考方案3】:

我认为 docker 最近在 docker build 中添加了 --add-host 标志,这真的很棒。

[编辑] 所以这个功能更新在17.04.0-ce

有关如何将docker build--add-host 标志一起使用的更多详细信息,请访问:https://docs.docker.com/edge/engine/reference/commandline/build/

【讨论】:

--add-host 功能在 CentOS 上的 Docker 12 上可用。 我想强调“带有这个标志的主机只在构建过程中使用;它故意不应该保留在镜像中”github.com/moby/moby/issues/34078【参考方案4】:

由于这仍然是 Google 中的第一个答案,我将提供可能的解决方案。

来自here 的命令出人意料地为我工作(Docker 1.13.1,Ubuntu 16.04):

docker exec -u 0 <container-name> /bin/sh -c "echo '<ip> <name> >> /etc/hosts"

【讨论】:

不相关但仍然有价值。谢谢。 当你重新启动容器时,它会被原来的容器覆盖!!!【参考方案5】:

你可以在运行docker的时候用下面的命令来做

docker run [OPTIONS] --add-host example.com:127.0.0.1 &lt;your-image-name&gt;:&lt;your tag&gt;

在这里,我将 example.com 映射到本地主机 127.0.0.1 及其工作。

【讨论】:

【参考方案6】:

如果这对任何人有用,HOSTALIASES 环境变量对我有用:

echo "fakehost realhost" > /etc/host.aliases
export HOSTALIASES=/etc/host.aliases

【讨论】:

你不是把 docker 和 kubernetes 搞混了吗?我在 docker 文档中没有看到任何 HOSTALIASES 变量【参考方案7】:

您可以在 docker run 期间使用 --add-host 选项。

对于您的情况,请使用: docker run --add-host mynginx:192.168.33.11 [image_name]:[tag]

这将更新您的 /etc/hosts

您可以使用以下命令进行检查:

docker exec -it [container_id] sh

如果 sh 不适合你,那么你可以试试 bash/bin/sh/bin/bash

cat /etc/hosts

【讨论】:

【参考方案8】:

我刚刚创建了一个 sh 脚本并在启动 docker 上运行它。

在此脚本中,我启动所有服务并更新主机文件:

在 Dockerfile 上:

CMD /tmp/init_commands.sh & sleep infinity 

init_comands.sh

any other commands...
echo "192.168.11.5    XXXXXXX" >> /etc/hosts
echo "192.168.11.6    XXXXXXY" >> /etc/hosts
echo "192.168.11.7    XXXXXXZ" >> /etc/hosts

【讨论】:

【参考方案9】:
Tis is me Dockefile
FROM XXXXX
ENV DNS_1="10.0.0.1 TEST1.COM"
ENV DNS_1="10.0.0.1 TEST2.COM" 
CMD ["bash","change_hosts.sh"]`

#cat change_hosts.sh
su - root -c "env | grep DNS | akw -F "=" 'print $2' >> /etc/hosts"
信息 用户必须su

【讨论】:

【参考方案10】:

通过在 docker run 而不是 docker build 期间挂载文件,以下对我有用

docker service create --name <name>  --mount type=bind,source=/etc/hosts,dst=/etc/hosts   <image>

【讨论】:

使用卷添加文件会增加复杂性,并且每个主机都必须拥有该文件。【参考方案11】:

使用以下方式运行容器的快速答案:

docker exec -it <container name> /bin/bash

一旦容器打开:

cd ..

然后

`cd etc`

然后你就可以了

cat hosts

或:

apt-get update
apt-get vim

或任何你喜欢的编辑器并在vim中打开它,在这里你可以修改你的启动ip为0.0.0.0

【讨论】:

以上是关于如何在“docker build”期间更新 Docker 映像中的 /etc/hosts 文件的主要内容,如果未能解决你的问题,请参考以下文章

为啥 docker build 中的 COPY 未检测到更新

Dockerfile: Docker build 无法下载包: centos->yum, debian/ubuntu->apt-get 内网后面

docker build时如何使用代理?

docker build时如何使用代理?

如何为Docker build设置http

Docker compose 不执行 .sql