如何在Dockerfile中处理类似于-h选项的特定主机名

31

我正在使用CentOS 7作为Docker守护进程主机和centos:6 Docker映像。

我想安装一些需要可解析主机名的软件,作为非环回地址。如果我运行一个带有-h选项的Docker映像,例如:

docker run -i -t -h myhost centos:6 /bin/bash

那么我可以安装该软件,因为容器内的 /etc/hosts 已自动配置好,如下所示:

[root@myhost /]# cat /etc/hosts
172.17.0.7  myhost
127.0.0.1   localhost    

[root@myhost /]# ping myhost
PING myhost (172.17.0.7) 56(84) bytes of data.
64 bytes from myhost (172.17.0.7): icmp_seq=1 ttl=64 time=0.033 ms

但是如果我从Dockerfile创建一个镜像,就不能使用同样的方法。我测试了以下Dockerfile来创建一个镜像:

FROM centos:6

ENV HOSTNAME myhost
RUN ping myhost

在 Docker 构建过程中,分配的主机名无法像以下动态 IP 地址一样解析:
$ docker build -t testimage .
Sending build context to Docker daemon 2.048 kB
Sending build context to Docker daemon
Step 0 : FROM centos:6
 ---> a30bc9f3097e
Step 1 : ENV HOSTNAME myhost
 ---> Using cache
 ---> e73bf592389e
Step 2 : RUN ping myhost
 ---> Running in ca54c8eac073
ping: unknown host myhost
INFO[0000] The command [/bin/sh -c ping myhost] returned a non-zero code: 2

如何将特定的主机名解析为动态容器IP地址并使用?

6个回答

16

在 Dockerfile 中通常无法做到这一点。

根据软件的不同,您可能可以尝试某种解决方法。例如,您可以尝试类似于以下内容的操作:

RUN echo $(grep $(hostname) /etc/hosts | cut -f1) my.host.name >> /etc/hosts && install-software

在安装软件时,在同一RUN命令中设置主机名,它将发生在容器的同一层内。Docker稍后将覆盖主机名,并且运行时您必须重新设置它,但您的软件可能可以接受这种情况。

如果您需要经常执行此操作,则可以尝试使用Packer构建容器。它可以构建Docker容器,但不使用多个层次结构。这使得重建变慢,下载生成的映像变快,并且更方便在镜像上执行多个操作,然后将其冻结为容器。


1
谢谢!您的建议真正解决了我想要解决的问题。我没有注意到如果我不指定-h选项,可以编辑/ etc / hosts,并且在一个RUN步骤中编写命令将会生效。此外,我会考虑在Dockerfile试用之后使用Packer。 - dempasong

12

至于解决方法,您可以使用 docker-composedocker stack 来构建具有特定 hostname 的容器,例如:

version: '3'
services:
  all:
    image: testimage
    container_name: myname
    hostname: myhost
    build:
      context: .

然后以以下方式运行:

docker-compose --build up

或者使用Docker堆栈

docker stack deploy -c docker-compose.yml mystack

10

如果 /etc/hosts 无法解决问题,我会替换 hostname 可执行二进制文件。

RUN mv /usr/bin/hostname{,.bkp}; \
  echo "echo myhost.local" > /usr/bin/hostname; \
  chmod +x /usr/bin/hostname

...

RUN mv /usr/bin/hostname{.bkp,}

2
现在是2020年 :) 我已经阅读和测试了几个小时,这是唯一有效的方法。虽然有点老,但仍然很珍贵。 - RASG

4

我认为以下方法更好,因为Docker容器通常没有安装“hostname”,因此我会使用head命令:

echo $(head -1 /etc/hosts | cut -f1) $HOST_NAME >> /etc/hosts

2

1

可能有点晚了,但是...

准备你自己的脚本命名为“hostname”(回显任何你想要的内容),将其复制到图像的某个位置,并在dockerfile中插入ENV PATH=:$PATH

它似乎运行得很好。 至少与iRedMail一起使用 :-)

如果需要,您可以轻松地通过实现-a、-f或-d选项来扩展您的脚本。


新的PATH应该是这种形式:PATH=你的主机名脚本路径:$PATH,当然要包含$PATH。我使用了<和>,但它们消失了,包括它们之间的所有内容。 - DLL

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