Runc Containers on the Desktop

Tuesday, January 19, 2016

Almost exactly a year ago, I wrote a post about running Docker Containers on the Desktop. Well it is a new year, and I have ended up converting all my docker containers to runc configs, so it’s the perfect time for a new blog post.

For those of you unfamiliar with the Open Container Initiative you should check out opencontainers.org.

Why the switch? you ask… well let me explain.

Our fellow Docker maintainer and pal Phil Estes made an awesome patch to add user namespaces to Docker.

Now me, being the completely insane containerizer that I am, desperately wanted to run all my crazy sound/video device mounting containers in user namespaces.

Well the way this could work is by having a custom gid_map for the audio and video groups to map to the host groups so we can have permission to access these devices in the container. In layman’s terms, I basically wanted to poke a teeny tiny map in the user namespace to be able to have permission to use my sound and video devices.

Obviously this was not the design of the feature, but since runc exposes the uidMappings and gidMappings, I knew I could have the power to do as I please. This is the awesome thing about runc. You, the user, have all the control.

So for chrome, this is what you get for mappings: github.com/jessfraz/containers:chrome/config.json#L223. If you look closely, or know what you are looking at, you can see group 29 and 44 are mapped to the same group ids as the host.

Then you can do cool things like listen to Taylor Swift in a container with a user namespace.

chrome-userns

Pretty cool right. So I went all OCD on this, like most things I encounter, and I converted all my containers. Obviously I found a way to generate them.

Riddler

Introducing github.com/jessfraz/riddler! riddler will take a running/stopped docker container and convert the inspect information into the oci spec (which can be run by runc, or any other oci compatible tool).

It has some opinionated features in that it will always try to set up a gid_map that works with your devices. You can also pass custom hooks to automatically add to the runc config as prestart, poststart, or poststop hooks. Which leads me to the next tool I built.

Netns

Say hello to github.com/jessfraz/netns! So you want your runc containers to have networking, eh? How about something super simple like a bridge? netns does just that. It sets up a bridge network for all your runc containers when added via the prestart hook.

It’s actually super simple code as well thanks to the awesome netlink pkg from vishvananda.

netns even saves the ip for the container in a .ip file in the directory with your config. Then other hooks can use this to do other things. For instance I use the hostess cli to then add an entry to my host’s /etc/hosts file, so I don’t have to remember the ip for the container when I want to reach it.

You can find all my hook scripts in github.com/jessfraz/containers:hack/scripts.

Magneto

The last tool I made was a copy of docker stats for runc. But what I really wanted was the new pids cgroup stats, that Aleksa Sarai added to the kernel and runc (and soon docker ;).

runc has a command runc events which outputs json stats in an interval. All you have to do is pipe that to magneto to get the awesome ux.

The following is for my chrome container:

$ sudo runc events | magneto

magneto

All the configs

If you are interested in all the configs for my containers, checkout github.com/jessfraz/containers.

I even included a systemd service file that can easily run any container (without a tty) in this directory via:

$ sudo systemctl start [email protected]

# for example:
$ sudo systemctl start [email protected]

NOTE: Keep in mind since these are generated a lot of the filepaths are hardcoded for things on my host. So if you try to run these and aren’t me I don’t want to hear any whining.

Happy namespacing!