Containers (in the modern sense) are a technology that allows you to run Linux processes that are isolated from one another.
Docker is an American corporation that builds platform software to help users work with Linux containers.
One piece of software provided by Docker Inc. is Docker Desktop, which will allow you to run Docker container images on non-Linux computers.
Docker Desktop does not run processes directly on your Mac or Windows machine — instead Docker Desktop provides a virtual machine that runs Linux, and when you ask Docker to run a command it will run that command on this virtual machine.
This is useful technology and makes Docker available to most working programmers. However, it can be hard to watch what, exactly, your containers are doing when you have this extra layer of virtualization in the middle of things.
There are a few ways to work around this problem that, like everything these days, are archived in a gist created by a random friendly human.
First, Docker makes a debugging socket available that gives us access to a shell inside the Linux virtual machine where your containers are running. On macOS, we can find the debugging socket at
~/Library/Containers/com.docker.docker/Data/debug-shell.sock
The most universal way of using this shell is with the program netcat
% nc -U ~/Library/Containers/com.docker.docker/Data/debug-shell.sock
/ # ^[[23;5R
You’ll get a really weird looking prompt, but you should be able to run commands.
/ # ^[[23;5Rps aux | grep docker
ps aux | grep docker
1108 root 1:51 /usr/bin/containerd-shim-runc-v2 -namespace services.linuxkit -id docker -address /run/containerd/containerd.sock
1131 root 0:57 /usr/bin/docker-init /usr/bin/entrypoint.sh
1411 root 0:01 /usr/bin/trim-after-delete -- /sbin/fstrim /var/lib/docker
1669 root 0:01 /usr/bin/logwrite -n dockerd /usr/local/bin/dockerd --containerd /var/run/desktop-containerd/containerd.sock --pidfile /run/desktop/docker.pid --config-file /run/config/docker/daemon.json --swarm-default-advertise-addr=eth0 --host-gateway-ip 192.168.65.2
1674 root 5:17 /usr/local/bin/dockerd --containerd /var/run/desktop-containerd/containerd.sock --pidfile /run/desktop/docker.pid --config-file /run/config/docker/daemon.json --swarm-default-advertise-addr=eth0 --host-gateway-ip 192.168.65.2
5933 root 0:00 grep docker
When you use netcat
you’re issuing commands directly to the socket without any of the usual nice features (a reasonable command prompt, shell history, etc) that come along with a modern shell environment. Running one of the following commands will get you a much nicer shell experience
% docker run -it --privileged --pid=host debian nsenter -t 1 -m -u -n -i sh
% docker run -it --rm --privileged --pid=host justincormack/nsenter1
The first command runs the Linux program nsenter
, which is a command that will let you run a specific Linux program in a specific process namespace. This command uses the Docker Hub Debian image to run nsenter
(which is part of a stock Debian install) and nsenter
is running the sh
shell.
The second command is running the justincormack/nsenter1
container (Docker Hub and repo). The justincormack/nsenter1
container has a build of a nsenter
like program that allows you to omit all those arguments. The Dockerfile
is an interesting one — it uses alpine Linux to compile the nsenter1
program, and then adds nsenter1
to a FROM scratch
image.
Both of these docker run
invocations don’t (appear to?) use the debugging socket. Instead the magic is in “--pid=host
“, which tells Docker to run the command in the process space of the host OS, which for Docker Desktop will be the virtual machine where these commands run. (also notice that Docker uses the language of VMs here (“host” OS)).
If you don’t quite follow that, don’t worry, you don’t need to. (I only vaguely grasp the implications). All you need to know is you can get a shell into your Docker Desktop VM by running the following
% docker run -it --rm --privileged --pid=host justincormack/nsenter1
and then poke around your Linux machine. For example, if you wanted to see how Docker stores all the layers for its container images you’d just
% docker run -it --rm --privileged --pid=host justincormack/nsenter1
/ # ls /var/lib/docker/overlay2/
3f5896f765b32aae99ce5438549cbf63e6b300f98a09a98d65cccd8e2e312e13
3f5896f765b32aae99ce5438549cbf63e6b300f98a09a98d65cccd8e2e312e13-init
3kwa3cw2gqhyyzj9o6klw7nro
8crhoels0omzrfafpmk9xvn6w
cb891d75ec97ee49e230d2b99d1313b21cf8f7483bdcc7529c8dbf3d6cf130bb
e4feafcb6867b603b9805b1f2a38a93e0d40d5114522205c8e52f8ac02af6eee
igluqjpeomstq9zw0mdkgmpad
iqqd91k86cr1wygxofzdc4s0x
l
nmlli3bpts1sfdcsu8v09jygg
ri9ymazsv0g54omflyy4z72w7
tbkxsdlbk154vm57rkbiwy0ld
vxe4nhs6h1geva8qhukr5qkag
zri9zy0m3kfopmb7ux7drsb4g