docker 构建的 Dockerfile HOSTNAME 说明 docker 运行 -h
Dockerfile HOSTNAME Instruction for docker build like docker run -h
我试图在构建期间在 docker 容器内设置主机名,因为某些软件安装使用发现的随机生成的主机名并将该主机名永久烘焙到配置中。
虽然可以通过 运行 -h 以交互方式设置主机名 运行,但使用 Dockerfile 构建时无法使用相同的功能。
解决此问题的唯一方法是使用 LD_PRELOAD hack,这样我就可以将主机名设置为 localhost。 LD_PRELOAD hacks 有一些我无法解决的不良副作用。使用 "docker run -it -h localhost ".
时,软件安装没有问题
strace 报告安装程序调用 uname 确定主机名。
uname({sys="Linux", node="12b0c7c7eacb", ...}) = 0
有谁知道如何解决这个限制?
更新 1
这不是问题 的重复,因为它专门讨论动态生成的文件引起的“/etc/hosts”问题。这很容易解决,因为它是一个可写文件。
这是关于试图通过系统调用(例如 uname 和 gethostname)解析主机名的软件安装。据我所知,这是无法解决的,因为无法在 运行ning docker 容器中更改主机名。 uname 系统调用可能引用 /proc/sys/kernel/hostname,这是只读的,无法更改。通常 hostname 命令可以是 运行,但是这个命令会产生一个错误,即使你是 root,你也必须是 root。解决方法是使用 -h 标志,这在构建中不可用。
更新 2
对于在这里寻找解决方法的任何人来说,这只需要在 docker 构建期间使用,如果您需要使用 docker 自定义主机名,请使用 -h 标志 运行。这是基于别人的工作。
Docker 文件:
RUN gcc -o fakehostname.o -c -fPIC -Wall fakehostname.c
RUN gcc -o libfakehostname.so -shared -W1,export-dynamic fakehostname.o -ldl
RUN ..
export LD_PRELOAD=/u01/app/oracle/libfakehostname.so;\
installer section
..
C 来源:
#define _GNU_SOURCE
#include <unistd.h>
#include <sys/syscall.h>
#include <sys/types.h>
#include <sys/utsname.h>
#include <stdio.h>
#include <string.h>
static int (*real_gethostname)(char *name, size_t len);
int uname(struct utsname *buf)
{
int ret;
ret = syscall(SYS_uname, buf);
strcpy(buf->nodename, "localhost");
return ret;
}
int gethostname(char *name, size_t len)
{
const char *val;
/* Override hostname */
val = "localhost";
if (val != NULL)
{
strncpy(name, val, len);
return 0;
}
/* Call real gethostname() */
return real_gethostname(name, len);
}
http://github.com/docker/docker/issues 根据 into_the_void 因为这个问题没有解决方案。
让我看看我是否理解你的问题,你想构建一个图像,当 运行 作为容器时具有 运行 时间主机名,即使用于构建的主机名不是相同的。正确的?如果是这样,我想问你的问题是,你能在安装软件后重新配置软件以使用新的主机名吗?
如果可能的话,我建议编写一个能够修改主机名的脚本并将此脚本用作 ENTRYPOINT
。通过这种方式,您可以保证在容器为 运行(使用任何命令)时随时更正主机名,并且您不会花时间在构建时尝试强制支持特定主机名,这由您自己录取,难做。
您可以使用 docker-compose
构建映像并分配主机名,例如
version: '3'
services:
all:
image: testimage
container_name: myname
hostname: myhost
build:
context: .
运行为:docker-compose --build up
.
我最近遇到了类似的问题。
对我有用的解决方案是在容器命名空间中设置主机名。
为了自动执行此操作,我整理了以下 docker 构建脚本:
docker build . | tee >((grep --line-buffered -Po '(?<=^change-hostname ).*' || true) | while IFS= read -r id; do nsenter --target "$(docker inspect -f '{{ .State.Pid }}' "$id")" --uts hostname 'new-hostname'; done)
最后 new-hostname
可以替换为所需的主机名。
我的 Dockerfile 如下所示:
RUN echo "change-hostname $(hostname)"; \
sleep 1; \
printf '%s\n' "$(hostname)" > /etc/hostname; \
printf '%s\t%s\t%s\n' "$(perl -C -0pe 's/([\s\S]*)\t.*$//m' /etc/hosts)" "$(hostname)" > /etc/hosts; \
echo 'Installing more stuff...'
打印出 change-hostname $(hostname)
的第一行(其中主机名应打印出当前容器 ID)指示构建脚本更改该容器的主机名。然后构建脚本查询容器的 pid 并在其 uts 命名空间中执行 hostname 'new-hostname'
。 sleep 1
只是给构建脚本一些时间来正确调整主机名。然后我修改 /etc/hostname
和 /etc/hosts
以包含新设置的主机名。
这甚至改变了 uname -n
的输出,所以我很确定它可以作为原始问题的解决方案。
我试图在构建期间在 docker 容器内设置主机名,因为某些软件安装使用发现的随机生成的主机名并将该主机名永久烘焙到配置中。
虽然可以通过 运行 -h 以交互方式设置主机名 运行,但使用 Dockerfile 构建时无法使用相同的功能。
解决此问题的唯一方法是使用 LD_PRELOAD hack,这样我就可以将主机名设置为 localhost。 LD_PRELOAD hacks 有一些我无法解决的不良副作用。使用 "docker run -it -h localhost ".
时,软件安装没有问题strace 报告安装程序调用 uname 确定主机名。
uname({sys="Linux", node="12b0c7c7eacb", ...}) = 0
有谁知道如何解决这个限制?
更新 1
这不是问题
这是关于试图通过系统调用(例如 uname 和 gethostname)解析主机名的软件安装。据我所知,这是无法解决的,因为无法在 运行ning docker 容器中更改主机名。 uname 系统调用可能引用 /proc/sys/kernel/hostname,这是只读的,无法更改。通常 hostname 命令可以是 运行,但是这个命令会产生一个错误,即使你是 root,你也必须是 root。解决方法是使用 -h 标志,这在构建中不可用。
更新 2
对于在这里寻找解决方法的任何人来说,这只需要在 docker 构建期间使用,如果您需要使用 docker 自定义主机名,请使用 -h 标志 运行。这是基于别人的工作。
Docker 文件:
RUN gcc -o fakehostname.o -c -fPIC -Wall fakehostname.c
RUN gcc -o libfakehostname.so -shared -W1,export-dynamic fakehostname.o -ldl
RUN ..
export LD_PRELOAD=/u01/app/oracle/libfakehostname.so;\
installer section
..
C 来源:
#define _GNU_SOURCE
#include <unistd.h>
#include <sys/syscall.h>
#include <sys/types.h>
#include <sys/utsname.h>
#include <stdio.h>
#include <string.h>
static int (*real_gethostname)(char *name, size_t len);
int uname(struct utsname *buf)
{
int ret;
ret = syscall(SYS_uname, buf);
strcpy(buf->nodename, "localhost");
return ret;
}
int gethostname(char *name, size_t len)
{
const char *val;
/* Override hostname */
val = "localhost";
if (val != NULL)
{
strncpy(name, val, len);
return 0;
}
/* Call real gethostname() */
return real_gethostname(name, len);
}
http://github.com/docker/docker/issues 根据 into_the_void 因为这个问题没有解决方案。
让我看看我是否理解你的问题,你想构建一个图像,当 运行 作为容器时具有 运行 时间主机名,即使用于构建的主机名不是相同的。正确的?如果是这样,我想问你的问题是,你能在安装软件后重新配置软件以使用新的主机名吗?
如果可能的话,我建议编写一个能够修改主机名的脚本并将此脚本用作 ENTRYPOINT
。通过这种方式,您可以保证在容器为 运行(使用任何命令)时随时更正主机名,并且您不会花时间在构建时尝试强制支持特定主机名,这由您自己录取,难做。
您可以使用 docker-compose
构建映像并分配主机名,例如
version: '3'
services:
all:
image: testimage
container_name: myname
hostname: myhost
build:
context: .
运行为:docker-compose --build up
.
我最近遇到了类似的问题。
对我有用的解决方案是在容器命名空间中设置主机名。 为了自动执行此操作,我整理了以下 docker 构建脚本:
docker build . | tee >((grep --line-buffered -Po '(?<=^change-hostname ).*' || true) | while IFS= read -r id; do nsenter --target "$(docker inspect -f '{{ .State.Pid }}' "$id")" --uts hostname 'new-hostname'; done)
最后 new-hostname
可以替换为所需的主机名。
我的 Dockerfile 如下所示:
RUN echo "change-hostname $(hostname)"; \
sleep 1; \
printf '%s\n' "$(hostname)" > /etc/hostname; \
printf '%s\t%s\t%s\n' "$(perl -C -0pe 's/([\s\S]*)\t.*$//m' /etc/hosts)" "$(hostname)" > /etc/hosts; \
echo 'Installing more stuff...'
打印出 change-hostname $(hostname)
的第一行(其中主机名应打印出当前容器 ID)指示构建脚本更改该容器的主机名。然后构建脚本查询容器的 pid 并在其 uts 命名空间中执行 hostname 'new-hostname'
。 sleep 1
只是给构建脚本一些时间来正确调整主机名。然后我修改 /etc/hostname
和 /etc/hosts
以包含新设置的主机名。
这甚至改变了 uname -n
的输出,所以我很确定它可以作为原始问题的解决方案。