I'd expect Python's socket.gethostname()
to be just a thin wrapper around the gethostname
system call, which on Ubuntu (using glibc) is in turn a wrapper for the uname
system call:
C library/kernel differences
The GNU C library does not employ the gethostname() system call; instead, it implements
gethostname() as a library function that calls uname(2) and copies up to len bytes from
the returned nodename field into name.
And for uname(2)
:
This is a system call, and the operating system presumably knows its name, release, and
version. It also knows what hardware it runs on. So, four of the fields of the struct
are meaningful. On the other hand, the field nodename is meaningless: it gives the name
of the present machine in some undefined network, but typically machines are in more than
one network and have several names. Moreover, the kernel has no way of knowing about such
things, so it has to be told what to answer here. The same holds for the additional
domainname field.
To this end, Linux uses the system calls sethostname(2) and setdomainname(2). Note that
there is no standard that says that the hostname set by sethostname(2) is the same string
as the nodename field of the struct returned by uname() (indeed, some systems allow a
256-byte hostname and an 8-byte nodename), but this is true on Linux. The same holds for
setdomainname(2) and the domainname field.
So:
It depends on what does sethostname()
. In the case of Docker containers, that's Docker itself.
I don't know.
Just ask Docker to set whatever hostname you want for the container:
% docker run --rm -it python:3.9 python -c 'import socket; print(socket.gethostname())'
dd247ca179da
% docker run --rm -it --hostname my-own-hostname python:3.9 python -c 'import socket; print(socket.gethostname())'
my-own-hostname
Here's the relevant portion of the source code, for Python 3.11.3:
#ifdef HAVE_GETHOSTNAME
/* Python interface to gethostname(). */
/*ARGSUSED*/
static PyObject *
socket_gethostname(PyObject *self, PyObject *unused)
{
if (PySys_Audit("socket.gethostname", NULL) < 0) {
return NULL;
}
#ifdef MS_WINDOWS
// snip
#else
char buf[1024];
int res;
Py_BEGIN_ALLOW_THREADS
res = gethostname(buf, (int) sizeof buf - 1);
Py_END_ALLOW_THREADS
if (res < 0)
return set_error();
buf[sizeof buf - 1] = '\0';
return PyUnicode_DecodeFSDefault(buf);
#endif
}