Following on from looking at katacontainers and gVisor, I thought it might be interesting to look at the containerd project and the idea of using containerd and runc without docker to run containers. Looking round the documentation, I couldn’t find a good look at getting containerd and runc setup together without installing Docker, so lets do that.

Installation Notes

For this install we’re working from a default Ubuntu 18.04 server install.

Step one - Get Containerd

First step is to get the containerd binaries, they’re available on the release page of the containerd github site here


tar -xzvf containerd-1.1.2.linux-amd64.tar.gz

sudo cp bin/* /usr/local/bin/

This should place the binaries in a location on the path. In addition to the daemon files there’s a copy of the ctr binary which is used as a client.

Step two - Get runc

We can get the runc binary from their Github page here. We’ll get the AMD64 binary and put it in the same dir as the containerd files


sudo cp runc.amd64 /usr/local/bin/runc

sudo chmod +x /usr/local/bin/runc

Step three - Containerd configuration

Now we’ll need to provide containerd some configuration and setup the systemd entry so that we can start it automatically on boot. Containerd has a handy command for generating a default configuration , so we can use that.

containerd config default > config.toml

sudo mkdir /etc/containerd

sudo cp config.toml /etc/containerd/

Next up, setting up systemd. The containerd project provides a systemd unit file on their github repo. so we can get that and use it.


sudo cp containerd.service /etc/systemd/system

sudo systemctl daemon-reload

sudo systemctl start containerd

If you want containerd to start on boot you can also add

sudo systemctl enable containerd

Running containers with Containerd

If all has gone well we should now have a running containerd/runc setup, so next up is getting and running a container. This is a little more involved than the easy Docker process, and there’s a couple of different command to know, but nothing too heavy.

First up we can check that the client can connect to the daemon ok with sudo ctr version . If this works, you should see something like

  Version:  v1.1.2
  Revision: 468a545b9edcd5932818eb9de8e72413e616e86e

  Version:  v1.1.2
  Revision: 468a545b9edcd5932818eb9de8e72413e616e86e

Pulling an image is done with ctr image pull. An important note is that unlike Docker this doesn’t hard code a default registry, so you need to specify the Docker hub URL if you’re pulling from there. sudo ctr image pull should download an Alpine 3.7 image.

Next up we need to create a container. This is done with ctr container create and you just pass the image and a name so something like sudo ctr container create -t myfirstcontainer should work. One point to note is that we’re passing the -t switch here to provide a TTY to the container

Now at this point you might be wondering “hey why am I not in my container?”. In containerd land you need to start the task after creating the container, so sudo ctr task start myfirstcontainer should work and put you in your container.

Looking around you’ll notice that whilst most things are similar to where you were running with docker, there are some differences, notably that you’ve got no networking past the lo interface. That’s provided by Docker. You can work round this using --net-host on the container create statement to get access to the host’s network, but that’s a little hacky. Past that it should be possible to hook up other container networking solutions to this, but that’s a topic for another blog post!


Security Geek, Kubernetes, Docker, Ruby, Hillwalking