Docker Tips : get a shell on the host

If you are using Docker on MacOS or Windows 10 Pro, chances are that you use the dedicated Docker for Mac or Docker for Windows products. Both of them use a hypervisor (xhyve / HyperV) to run a VM with the Docker daemon. The Docker client running on the host sends requests to the Docker daemon running inside the VM.

It’s useful from time to time to get a shell directly in the VM. For instance, this can be helpful is you want to explore the /var/lib/docker folder where the Docker daemon stores all its stuff, to inspect the network interfaces / bridges created in the VM, or for other debug purposes. In this context you may already have seen / use the the following command :

$ docker run --privileged --pid=host -it alpine:3.8 \
nsenter -t 1 -m -u -n -i sh

It basically runs a container, based on the Alpine image, and launches a nsenter command with a bunch of parameters.

Let’s review the options used to better understand how this is working under the hood. At first, there are the options provided to the docker run command :

  • --rm : removes the container after it is stopped
  • -ti (or -t -i) : adds a tty and leaves the standard input opened
  • --privileged : grants additional permissions to the container, it allows the container to gain access to the devices of the host (/dev)
  • --pid=host : allows the containers to use the processus tree of the Docker host (the VM in which the Docker daemon is running)

From the options above, we know the newly created container will run in the host’s process namespace and then will be able to view all the process running on the host (among them the process with PID 1).

Let’s now check the available options of the nsenter utility, which allows to run a process in existing namespaces (the building blocks that provide isolation to containers).

$ docker run alpine:3.8 nsenter --help
BusyBox v1.28.4 (2018–07–17 15:21:40 UTC) multi-call binary.
Usage: nsenter [OPTIONS] [PROG [ARGS]]
-t PID Target process to get namespaces from
-m[FILE] Enter mount namespace
-u[FILE] Enter UTS namespace (hostname etc)
-i[FILE] Enter System V IPC namespace
-n[FILE] Enter network namespace
-p[FILE] Enter pid namespace
-U[FILE] Enter user namespace
-S UID Set uid in entered namespace
-G GID Set gid in entered namespace
—-preserve-credentials Don’t touch uids or gids
-r[DIR] Set root directory
-w[DIR] Set working directory
-F Don’t fork before exec’ing PROG

As we can see from this list, the options provided to nsenter (-t 1 -m -u -n -i sh) allows to run the process sh in the same isolation context as the process with PID 1. The whole command will then provide an interactive sh shell in the VM.