I am attempting to set the hostname inside a docker container during the build since certain software installs use the discovered randomly generated hostname and permanently bake that hostname into the configuration.
While it is possible to set the hostname when you run interactively via run -h, the same functionality is not available using build via the Dockerfile.
The only way to work around this is to use LD_PRELOAD hacks so that I can set the hostname to localhost. The LD_PRELOAD hacks have unwanted sideeffects that I am having trouble working around. The software install works without issue when using "docker run -it -h localhost ".
strace reports that the installer make a call to uname determine the hostname.
uname({sys="Linux", node="12b0c7c7eacb", ...}) = 0
Does anyone know how it might be possible to work around this limitation?
Update 1
This is not a duplicate of the question How to handle specific hostname like -h option in Dockerfile as that is talking specifically about "/etc/hosts" problems arising from that file being dynamically generated. This is easily worked around since it is a writable file.
This is about software installs that attempt to resolve the hostname from system calls such as uname and gethostname. From what I can tell this cannot be worked around since the hostname cannot be changed within a running docker container. The uname system call likely references /proc/sys/kernel/hostname, this is read only and cannot be changed. Normally the hostname command could be run, but this command generates an error that you must be root even if you are root. The workaround for this is to use the -h flag, this is not available in builds.
Update 2
For anyone looking for a workaround here it is, this only needs to be used during the docker build, use the -h flag if you need to customize the hostname with docker run. This is based on someone else's work.
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 Source:
#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 as per into_the_void as there is no solution to this problem.
I have recently had a similar issue.
The solution that worked for me was to set the hostname in the container namespace. To do that automatically I have put together the following docker build script:
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)
Right at the end new-hostname
can be replaced with the desired hostname.
My Dockerfile looks like this:
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...'
The first line that prints out change-hostname $(hostname)
(where hostname should print out the current container id) signals the buildscript to change the hostname for that container. The build script then queries the pid for the container and executes hostname 'new-hostname'
in its uts namespace. The sleep 1
just gives the build script some time to adjust the hostname properly. Then I modify /etc/hostname
and /etc/hosts
to include the newly set hostname.
This even changes the output of uname -n
so I am pretty sure it would work as a solution for the original question.
Let me see if I understand your question, you would like to build an image that when run as a container has the runtime hostname even if the hostname used for building is not the same. Correct? If so, my question to you is the following, are you able to reconfigure the software to have a new hostname after it is installed?
If this is possible, I would recommend writing a script that is able to modify the hostname and use this script as an ENTRYPOINT
. This way you can guarantee that you have corrected the hostname anytime your container is run (with any command) and you don't spend time trying to force support for a particular hostname through at build time, which, by your own admission, is difficult to do.
You can use docker-compose
to build your image and assign the hostname, e.g.
version: '3'
services:
all:
image: testimage
container_name: myname
hostname: myhost
build:
context: .
The run as: docker-compose --build up
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With