如何在Docker镜像的“docker build”过程中更新/etc/hosts文件

195

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

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

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

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


你是否正在使用boot2docker来执行你的docker构建? - VonC
不,我正在使用 Docker 1.8 的 Linux 版本。 - Prakash
1
当您将图像作为容器运行时,它的 /etc/hosts 是否保持不变?还是您指的是 Linux 主机的 /etc/hosts? - VonC
8
Docker构建镜像成功,但使用相同镜像运行容器后,我检查了/etc/hosts文件,发现更改并没有生效。 - Prakash
1
如果在构建时没有添加主机的方法,则使用Asad在https://dev59.com/w1oT5IYBdhLWcg3wrA-5#55656083中记录的“docker run --add-host”是100%最佳解决方案。使用“docker build --add-host”将无法解决此问题。 - Oliver
11个回答

247
使用更新版本的docker,可以通过docker-compose及其extra_hosts指令来完成此操作。

Add hostname mappings.
Use the same values as the docker run client --add-host parameter (which should already be available for docker 1.8).

extra_hosts:
  - "somehost:162.242.195.82"
  - "otherhost:50.31.209.229"
简而言之:在运行容器时修改其/etc/hosts,而不是在构建容器时修改。
在Docker 17.x+中,你可以使用docker build --add-host命令(如下所述),但正如在issue 34078this answer中所评论的那样:

--add-host功能在构建过程中被设计为允许覆盖主机设置,但不会将该配置持久化到镜像中。

这些链接指向解决问题的策略:
  • 运行内部DNS;你可以在守护进程中设置默认的DNS服务器,这样每个启动的容器都会自动使用配置的默认DNS。
  • 使用Docker Compose并为开发人员提供一个docker-compose.yml文件。
    Docker Compose文件允许你指定启动容器时应使用的所有选项,因此开发人员只需执行docker compose up即可使用所需的所有选项启动容器。
这些解决方案可以利用之前在答案中提到的docker-compose方法,并使用其extra_hosts指令。

28
我想要更改 Docker 镜像中的 /etc/hosts 文件。 - Prakash
1
@PrakashSingh 我同意,但似乎这并不容易做到。 - VonC
2
@PrakashSingh 你可以通过 docker exec -it <容器名称> /bin/bash 在机器上打开一个 bash 实例,然后使用你喜欢的命令行编辑器(vim、emacs、nano、echo '' . >>/etc/host)更新 docker 容器主机下的 /etc/host。 - NateAGeek
1
@PrakashSingh 是的,我们可以(听起来很熟悉...)。但是当我们通过构建镜像更改主机条目时,它看起来只是 Docker 的一种 hack。Docker 网络设计是应用程序驱动的(来自 docker.com)。由于主机条目是 Docker 网络的一部分,因此最好在从镜像运行容器时定义它。如果您确实需要添加一些主机条目,则不要每次都通过构建镜像来添加它们,而是将它们添加到基础镜像中一次。这是最佳实践。 - Light.G
2
在 Docker 构建过程中,当使用 rocker/shiny 安装包时出现问题,通过添加参数 --add-host:cran.rstudio.com:<IPaddress> 可以解决该问题。 - bvanlew
显示剩余6条评论

40

使用RUN步骤中的echo无法修改映像中的主机文件,因为当您从该映像启动容器时,Docker守护程序将维护文件(/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


1
如果您正在寻找Kubernetes解决方案,可以使用hostAliases。就像Docker Compose的extra_hosts一样。https://kubernetes.io/docs/concepts/services-networking/add-entries-to-pod-etc-hosts-with-host-aliases/ - Shubham Singh
更准确地说,ENTRYPOINT 不是镜像的指令。它只是在我们从该镜像运行容器时标记一个入口点,这意味着主机的入口点仅在容器运行后存在。我不认为这个要求是必要的。一定有一些误解。 - Light.G

29

3
在CentOS上,Docker 12版本提供了--add-host功能。该功能可用于添加主机名和IP地址映射。 - chutz
9
我想强调的是,“添加了此标志的主机仅在构建过程中使用;它故意不应保留在映像中”。(原文链接:https://github.com/moby/moby/issues/34078) - Sida Zhou

15

由于这个问题仍然出现在谷歌搜索结果的第一个答案中,我来贡献一种可能的解决方案。

以下命令取自此处,出乎意料的对我很有效 (Docker 1.13.1, Ubuntu 16.04):

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

不相关但仍有价值。谢谢。 - Light.G
2
当您重新启动容器时,此内容将被覆盖为原始内容! - Frank

12

当运行docker时,您可以使用以下命令:

docker run [OPTIONS] --add-host example.com:127.0.0.1 <your-image-name>:<your tag>

在此示例中,我将example.com映射到本地主机127.0.0.1,并且它正在工作。


1
如果在构建时没有添加主机的方法,那么这是100%的下一个最佳解决方案。 - Oliver

5
如果有人需要的话,HOSTALIASES环境变量对我很有用:
echo "fakehost realhost" > /etc/host.aliases
export HOSTALIASES=/etc/host.aliases

9
你是不是把Docker和Kubernetes搞混了?我在Docker文档中没有看到HOSTALIASES变量。 - Adrien Lemaire
HOSTALIASES 是一个基于 glibc 的环境变量,因此您可以在“任何”地方使用它(除非您是 root,否则它无法与 setuid 可执行文件一起使用,除非您安装了 dnsmasq,否则它也无法与 IP 地址一起使用)。 - Compholio

4
你可以在docker运行时使用--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

0

我刚刚创建了一个 sh 脚本,并在启动 Docker 时运行它。

在这个脚本中,我启动所有服务并更新 hosts 文件:

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

-2

以下方法对我有效,是在docker运行时挂载文件而不是在docker构建时进行的

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

使用卷添加文件会增加额外的复杂性,每个主机都必须拥有该文件。 - Shubham Singh

-2
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"
  • 信息
  • 用户必须以超级用户身份运行

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接