我正在尝试在构建期间在docker容器中设置主机名,因为某些软件安装使用发现的随机生成的主机名并将该主机名永久地烘焙到配置中。
虽然可以通过run -h以交互方式运行时设置主机名,但使用Dockerfile构建时无法使用相同的功能。
解决此问题的唯一方法是使用LD_PRELOAD hacks,以便我可以将主机名设置为localhost。 LD_PRELOAD黑客有不必要的副作用,我无法解决。使用" docker run -it -h localhost"时,软件安装没有问题。
strace报告安装程序调用uname确定主机名。
uname({sys="Linux", node="12b0c7c7eacb", ...}) = 0
有谁知道如何解决这个限制?
更新1
这不是问题How to handle specific hostname like -h option in Dockerfile的重复,因为那是专门讨论" / etc / hosts"由该文件动态生成引起的问题。这很容易解决,因为它是一个可写文件。
这是关于尝试从系统调用(例如uname和gethostname)解析主机名的软件安装。据我所知,由于无法在正在运行的docker容器中更改主机名,因此无法解决此问题。 uname系统调用可能引用/ proc / sys / kernel / hostname,这是只读的,不能更改。通常可以运行hostname命令,但是此命令会生成一个错误,即使您是root用户,也必须是root用户。解决方法是使用-h标志,这在构建中不可用。
更新2
对于任何寻找解决方法的人来说,这只需要在docker构建期间使用,如果需要使用docker run自定义主机名,请使用-h标志。这是基于别人的工作。
Dockerfile:
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 ,因为此问题无法解决。
答案 0 :(得分:1)
让我看看我是否理解了您的问题,您希望构建一个图像,当作为容器运行时,即使用于构建的主机名不同,它也具有运行时主机名。正确?如果是这样,我的问题如下,您是否能够在安装软件后重新配置软件以获得新的主机名?
如果可以,我建议编写一个能够修改主机名的脚本,并将此脚本用作ENTRYPOINT
。通过这种方式,您可以保证在运行容器时(使用任何命令)更正了主机名,并且您不会花时间在构建时强制支持特定主机名,这可以由您自己承认,很难做到。
答案 1 :(得分:1)
您可以使用docker-compose
来构建图片并分配主机名,例如
version: '3'
services:
all:
image: testimage
container_name: myname
hostname: myhost
build:
context: .
运行方式为:docker-compose --build up
。
答案 2 :(得分:1)
我最近有一个类似的问题。
对我有用的解决方案是在容器名称空间中设置主机名。 为此,我将以下泊坞窗构建脚本放在一起:
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.*$/$1/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
的输出,因此我很确定它可以作为原始问题的解决方案。