At Evolving Web we love using Docker! So when I needed to do work on several different sites, I just spun up a few Docker containers, and now I've got this:
Three shells in three different containers, and it's super hard to tell which is which.The hostnames are just random hex strings—so confusing!
If I had thought ahead, I could have set the hostnames with the --hostname
option to docker run
. But I forgot, and now I can't change it:
docker@378dd3233752:/drupal/docroot$ sudo hostname "prototypes"
hostname: you must be root to change the host name
That's weird: I'm using sudo, but it still says I must be root! It looks like Docker limits the kernel capabilities of its containers, so I can't change hostnames from within a container. Am I just stuck with these random hostnames? I better learn more about how this whole container thing works.
Containers are just namespaces
So how does each container have a separate hostname, anyway? I know that containers are just processes in Linux namespaces—so there must be a namespace for hostnames. I can use the lsns
command to explore all my namespaces:
vasi$ sudo lsns
NS TYPE NPROCS PID USER COMMAND
4026531836 pid 84 1 root init
4026531837 user 142 1 root init
4026531857 mnt 1 14 root kdevtmpfs
4026531957 net 84 1 root init
4026532300 mnt 17 1778 root /usr/bin/python /usr/local/bin/supervisord -c
4026532301 uts 17 1778 root /usr/bin/python /usr/local/bin/supervisord -c
4026532302 ipc 17 1778 root /usr/bin/python /usr/local/bin/supervisord -c
4026532303 pid 17 1778 root /usr/bin/python /usr/local/bin/supervisord -c
...
There are so many different types of namespaces: pid
, user
, ipc
, uts
, mnt
, net
. I have no idea which one involves hostnames, so I checked Wikipedia: It's uts
that manages that! Each uts
namespace has one hostname, which is shared among all the processes in that namespace.
That gives me an idea: I can't change the hostname from a container because of limited capabilities. But I could totally launch a new process in the same namespace, and this new process would have no capability limits—so it could change the hostname. And that change would be shared with the container! Let's try it!
I'll use the nsenter
command to get inside the right namespace for container 378dd3233752
. We have to give nsenter
a process ID, not a container ID—but no worries, Docker can translate for me:
vasi$ docker inspect -f '{{ .State.Pid }}' 378dd3233752
2868
Now I have all I need to run nsenter
. It gives me a shell in the right namespace, where I can just set the hostname:
vasi$ sudo nsenter --target 2868 --uts
378dd3233752$ hostname "prototypes"
Success!
When I login to the container again, I see the hostname prototypes
instead of a bunch of hex characters! Now it's easy to tell which shell is which:
I'm sure tons of other things become so much easier when you understand namespaces. What cool tricks have you found?
Discuss on Reddit