Docker run all the things with user namespaces

Friday, January 8, 2016 ยท 3 min read

If you weren’t aware user namepace support was added to Docker awhile back in the “Experimental” builds. But with the upcoming release of Docker Engine 1.10.0, Phil Estes is working on moving it into stable. Now this is all super exciting and blah blah blah, but what I am going to talk about today is how I started running all the containers from my Docker Containers on the Desktop with the new user namespace support. The containers/images in that post were already doing some linux-y magic, but with a little more, they are perfect. I’m not going to go through them all but I will go through some interesting ones, including even how to run Docker-in-Docker.

Chrome

This one was shockingly easy. The only things I needed to add to my original command were --group-add video and --group-add audio. Makes sense right.. we obviously want to be a member of those groups to watch Taylor Swift music videos.

The full command is below. I even made a custom seccomp whitelist for chrome, you can view it in my dotfiles repo: github.com/jessfraz/dotfiles. Seccomp will be shipped in 1.10 as well, along with a default whitelist! (But I degress that is not the point of this blog post.)

Dockerfile

$ docker run -d \
    --memory 3gb \
    -v /etc/localtime:/etc/localtime:ro \
    -v /tmp/.X11-unix:/tmp/.X11-unix \
    -e DISPLAY=unix$DISPLAY \
    -v $HOME/Downloads:/root/Downloads \
    -v $HOME/.chrome:/data \
    -v /dev/shm:/dev/shm \
    --security-opt seccomp:/etc/docker/seccomp/chrome.json \
    --device /dev/snd \
    --device /dev/dri \
    --device /dev/video0 \
    --group-add audio \
    --group-add video \
    --name chrome \
    jess/chrome --user-data-dir=/data

Notify-osd and Irssi

Now I have always run my notifications daemon in a container, because that stuff is nasty to install, so many dependencies, ewwww. This one was a bit more tricky beacuase it involves dbus but it is a way cleaner solution than the way I was originally running it.

Dockerfile

$ docker run -d \
    -v /etc/localtime:/etc/localtime:ro \
    -v /tmp/.X11-unix:/tmp/.X11-unix \
    -v /etc \
    -v /home/user/.dbus \
    -v /home/user/.cache/dconf \
    -e DISPLAY=unix$DISPLAY \
    --name notify_osd \
    jess/notify-osd

# you can test with
$ docker exec -it notify_osd notify-send hello

Not to bad right? I am creating those volumes on run so that we can then share them with our irssi container. This way when someone pings me I get a notification, duh!

Dockerfile

$ docker run --rm -it \
    -v /etc/localtime:/etc/localtime:ro \
    -v $HOME/.irssi:/home/user/.irssi \
    --volumes-from notify_osd \
    -e DBUS_SESSION_DBUS_ADDRESS="unix:abstract=/home/user/.dbus/session-bus/$(docker exec notify_osd ls /home/user/.dbus/session-bus/)" \
    --name irssi \
    jess/irssi

So this is pretty simple as well even considering the real gross part is trying to get the DBUS_SESSION_DBUS_ADDRESS from our notify_osd container.

Let’s get into the fun part.

Docker-in-Docker

When running the docker daemon with user namespace support, you cannot use docker run flags like --privileged, --net host, --pid host, etc. These are for pretty obvious reasons so I’m not going to get into it, if you want to know more RTFM.

Okay so we can’t use --privileged, but but but that’s how I run docker-in-docker… ok let’s think about it. What is --privileged actually doing? Well for starters it’s allowing all capabilites, but… do we really need them all? The answer is no.. all we really need is CAP_SYS_ADMIN and CAP_NET_ADMIN. So that gets us pretty far but we also need to disable the default seccomp profile (because it drops clone args, mount, and a bunch of others). Lastly we need to run with a different apparmor profile so we can have more capabilities as well.

This leaves us with: