Replace Docker on Your Raspberry Pi With Containerd

Replace Docker on Your Raspberry Pi With Containerd

Take your first steps with containerd and run your docker images as usual

Guillaume Vincent
Guillaume Vincent

In December 2020, the Kubernetes project has deprecated docker. Through this lecture, we are going to have a first look at the dockerhistory to understand the reasons for this deprecation. This will bring us next to discover containerdand figure out its advantages.

We will practice containerd by installing it on a Raspberry Pi. This target platform is a good scenario to dig into the different components needed to use containerd. There are no available binaries so we will build them from the sources. Once installed, we will see how to interact with it using ctrcommand and what there is possible to do.

The Docker Software History

Docker software was created in 2013 and contributed to making containerization famous and accessible. However, people are often confusing docker and containerization.

Docker ≠ containers

The containerization in Linux was possible with these two Linux kernel features:

  • Linux kernel namespace defines the boundaries of a process awareness of what else is running around it.
  • Control groups (cgroups) are a kernel feature that manages and isolates the resources (CPU, memory) affected by a process.

Linux Containers (LXC) was released in 2008 and relies on both previous kernel features. It provides an API to easily create and manage container application systems.

In its beginning, dockerwas using the LXC stack to isolate application resources. The dockerprowess was to create a standard software unit where the user can define images and launch them easily in containers.

Software architecture evolution

Based on LXC, dockerwas really dependent on its development. To remediate that, dockerstarted to implement libcontainers to launch containers without LXC.

In parallel at that time, there were many criticisms made against the monolithic architecture of dockercontaining the CLI and the daemon. Having taken into account these feedbacks docker started cutting out the daemon and the CLI in docker.

In 2015 the Open Container Initiative (OCI) was founded to create an application container standard. Docker company has been a major key player in its definition. Two standards emerged from this initiative which constitutes the OCI model :

opencontainers/runtime-spec
OCI Runtime Specification. Contribute to opencontainers/runtime-spec development by creating an account on GitHub.
opencontainers/image-spec
OCI Image Format. Contribute to opencontainers/image-spec development by creating an account on GitHub.

Docker company donated libcontainersto the OCI. It is now a part of the runc project which is the OCI runtime. Nowadays, dockeris no longer the monolithic block it once was. It uses containerdand runcto manage the run of the containers :

The actual docker architecture
The actual docker architecture

Containerd

containerdwas born out of dockerand was included from the 1.11 release :

Docker 1.11: The first runtime built on containerd and based on OCI technology - Docker Blog
Learn from Docker experts to simplify and advance your app development and management with Docker. Stay up to date on Docker events and new version announcements!

It is a runtime implementing the Container Runtime Interface (CRI) and presents interesting assets for hosted systems :

“containerd is an industry-standard container runtime with an emphasis on simplicity, robustness and portability. It is available as a daemon for Linux and Windows, which can manage the complete container lifecycle of its host system: image transfer and storage, container execution and supervision, low-level storage and network attachments, etc.” From https://github.com/containerd/containerd

Docker and Kubernetes

Before the 1.20 release, kuberneteswas using dockerto communicate with the containers. dockeritself calls containerd to manage the containers :

Kubernetes with Docker
Kubernetes with Docker


From v1.20 kubernetesdeprecates dockerin favor of runtimes using the Container Runtime Interface (CRI) such as containerdand cri-o. You will receive warnings if you still use dockerin this release. The change will be effective in the v1.22 release. The previous diagram looks like that now:

Kubernetes without Docker
Kubernetes without Docker

In spite of this kuberneteschange, you can continue to use Docker in your CI/CD or for development purposes. dockerbrings a lot of user-experience features to make the interaction easier. Nevertheless, a container orchestrator like kubernetesneeds only a container runtime to manage containers. Dealing with an extra layer can bring more complexity that does not create more value.

Containerd on a Raspberry Pi

Installation

I use a Raspberry Pi with armv6l processor architecture and Raspbian OS. You should check your processor architecture using uname and adapt the source code to your architecture.

We ensure the system is up-to-date:

$ sudo apt update
$ sudo apt full-upgrade
$ sudo rpi-update

We need some build tools to compile sources :

$ sudo apt install autoconf automake libtool curl unzip gcc make

We also need a recent golangversion installed :

$ wget https://golang.org/dl/go1.15.8.linux-armv6l.tar.gz
$ sudo tar -C /usr/local -xzf go1.15.8.linux-armv6l.tar.gz
$ echo 'PATH="$PATH:/usr/local/go/bin"' | tee -a $HOME/.profile
$ echo "export GOPATH=$(go env GOPATH)" | tee -a $HOME/.profile
$ source $HOME/.profile
$ go version
# version should be 1.15.8

Install libseccomp packages for seccomp support:

$ sudo apt install libseccomp2 libseccomp-dev

Install runc:

$ go get -v github.com/opencontainers/runc
$ cd $GOPATH/src/github.com/opencontainers/runc
$ make -j`nproc`
$ sudo env PATH="$PATH" make install

We need btrfspackages to prepare protobufinstallation:

sudo apt install btrfs-progs libbtrfs-dev

We download protobufsources and build them:

$ wget https://github.com/protocolbuffers/protobuf/archive/v3.14.0.tar.gz -O protobuf_v3.14.0.tar.gz
$ tar xzf protobuf_v3.14.0.tar.gz
$ cd protobuf-3.14.0/
$ ./autogen.sh
$ ./configure
$ make -j`nproc`
$ make -l2 -j`nproc` check
$ sudo make install

We download containerdsources and build them:

$ go get -v github.com/containerd/containerd
$ cd $GOPATH/src/github.com/containerd/containerd
$ make -j`nproc`
$ sudo env PATH="$PATH" make install

The containerd build is finished we can check the binary:

$ containerd --version
containerd github.com/containerd/containerd v1.5.0-beta.1 cfa842c278694860a7e32917066f4a24978f80d0

We deploy the provided systemdservice file to run containerdas a daemon:

cd $GOPATH/src/github.com/containerd/containerd
sudo cp containerd.service /etc/systemd/system/
sudo systemctl daemon-reload
sudo systemctl enable containerd.service
sudo systemctl start containerd.service

Interact with containerd

We are going to use ctr command to interact with containerd. It was included in the containerdinstallation:

NAME:
   ctr -
        __
  _____/ /______
 / ___/ __/ ___/
/ /__/ /_/ /
\___/\__/_/
containerd CLI
USAGE:
   ctr [global options] command [command options] [arguments...]
VERSION:
   v1.5.0-beta.1
DESCRIPTION:
ctr is an unsupported debug and administrative client for interacting
with the containerd daemon. Because it is unsupported, the commands,
options, and operations are not guaranteed to be backward compatible or
stable from release to release of the containerd project.
COMMANDS:
   plugins, plugin            provides information about containerd plugins
   version                    print the client and server versions
   containers, c, container   manage containers
   content                    manage content
   events, event              display containerd events
   images, image, i           manage images
   leases                     manage leases
   namespaces, namespace, ns  manage namespaces
   pprof                      provide golang pprof outputs for containerd
   run                        run a container
   snapshots, snapshot        manage snapshots
   tasks, t, task             manage tasks
   install                    install a new package
   oci                        OCI tools
   shim                       interact with a shim directly
   help, h                    Shows a list of commands or help for one command
GLOBAL OPTIONS:
   --debug                      enable debug output in logs
   --address value, -a value    address for containerd's GRPC server (default: "/run/containerd/containerd.sock") [$CONTAINERD_ADDRESS]
   --timeout value              total timeout for ctr commands (default: 0s)
   --connect-timeout value      timeout for connecting to containerd (default: 0s)
   --namespace value, -n value  namespace to use with commands (default: "default") [$CONTAINERD_NAMESPACE]
   --help, -h                   show help
   --version, -v                print the version

containerd can pull images from a container registry and it supports tags. We usectrto pull the nginx image:

$ sudo ctr image pull docker.io/library/nginx:latest

Using ctr we can have the list of images. We can ensure the nginx image has been pulled:

$ sudo ctr image ls
$ sudo ctr image ls -q
docker.io/library/nginx:latest

We have the nginximage and we can now run a container using it:

$ sudo ctr container create docker.io/library/nginx:latest webdemo

Is the container running? Let’s confirm it by listing the containers:

$ sudo ctr container list
CONTAINER    IMAGE                             RUNTIME
webdemo      docker.io/library/nginx:latest    io.containerd.runc.v2

If we delete the image the container is still running :

$ sudo ctr image remove docker.io/library/nginx:latest
docker.io/library/nginx:latest
$ sudo ctr image ls -q
$ sudo ctr container list
CONTAINER    IMAGE                             RUNTIME
webdemo      docker.io/library/nginx:latest    io.containerd.runc.v2

Now we can remove the container :

sudo ctr container delete webdemo

Conclusion

We had an overview of dockerhistory. We have seen it was monolithic software in the beginning. Docker has contributed to defining container standards in the OCI. Resulting in that, docker architecture has changed.

Initially, kuberneteswas using dockerbut decided in the 1.20 release to deprecate it. We have seen that dockercommunicates with containerdand runcto run containers. Its added value is to provide a great user-experience to manage images and resources for developers.

In the case of a distributed system like kubernetes, it can directly call the container runtime. An extra layer is not needed and can create complexity and more calls across the software layers.

Finally, we practiced containerdby installing and configuring it on a Raspberry Pi. It is a good target to test containerdbecause it has limited resources and most of the time you don’t build images on it. You just want to pull images and run them into containers. We have observed we can pull dockerimages and launch containers as usual with containerd.

Resources

Don’t Panic: Kubernetes and Docker
Authors: Jorge Castro, Duffie Cooley, Kat Cosgrove, Justin Garrison, Noah Kantrowitz, Bob Killen, Rey Lejano, Dan “POP” Papandrea, Jeffrey Sica, Davanum “Dims” SrinivasKubernetes is deprecating Docker as a container runtime after v1.20.You do not need to panic. It’s not as dramatic as it sounds.T…
containerd/containerd
An open and reliable container runtime. Contribute to containerd/containerd development by creating an account on GitHub.
What is containerd ? - Docker Blog
Learn from Docker experts to simplify and advance your app development and management with Docker. Stay up to date on Docker events and new version announcements!
Open Container Initiative - Open Container Initiative
Cloud-Native

Guillaume Vincent

DevOps Engineer & AWS Certified Solution Architect. Cloud enthusiast and automation addict