Lesson 9: Setting Up Docker or Container Runtime

Building a production-ready Kubernetes cluster from scratch / Preparing the Environment for Kubernetes

In this lesson, we will set up containerd as the container runtime on each Raspberry Pi device. Containerd is a lightweight and efficient container runtime that is widely used in Kubernetes environments due to its simplicity and compatibility with Kubernetes’ container runtime interface (CRI).

This is the 9th lesson of the guide Building a production-ready Kubernetes cluster from scratch. Make sure you have completed the previous lesson before continuing here. The full list of lessons in the guide can be found in the overview.

WARNING: All commands used in this lesson require sudo privileges. Either prepend sudo to each command or switch to the root user using sudo -i.

Installing containerd on Each Raspberry Pi

To begin, make sure you are connected to each Raspberry Pi via SSH. Perform the following steps on each device:

Update the package list and install required dependencies:

$ apt update
$ apt install -y apt-transport-https curl gnupg2 software-properties-common

Next you can install containerd using the following commands:

$ apt install -y containerd

Preparing the containerd Configuration

Once containerd is installed, it needs to be configured properly to work with Kubernetes.

Create a default configuration file for containerd:

$ mkdir -p /etc/containerd
$ containerd config default | tee /etc/containerd/config.toml

Configuring containerd to Use the NVMe Drive

Configure containerd to use the path /mnt/nvme/containerd as the root dir, so that containerd can store its data on the NVMe drive:

$ mkdir -p /mnt/nvme/containerd

Open the configuration file with a text editor like vi or nano to modify the root setting:

$ vi /etc/containerd/config.toml

Find the line that specifies the root setting (typically under the [plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc.options] section). This section is the configuration related to the runc runtime, which is the default runtime used by containerd:

[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc.options]
  root = "/mnt/nvme/containerd"

Save the changes and exit the editor (in vi, press Esc followed by :wq and Enter).

Configuring containerd for Kubernetes

We need to configure the system cgroup driver to systemd because we are using the systemd cgroup driver. cgroup is a Linux kernel feature that limits the resources that can be used by a process.

In the same section as the root setting, we need to configure the SystemdCgroup setting to true:

[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc.options]
  SystemdCgroup = true

Save the changes and exit the editor (in vi, press Esc followed by :wq and Enter).

Even though we have configured containerd to use the NVMe drive, we need to add a symbolic link to the containerd directory to allow containerd to store its data on the NVMe drive. This is because some Kubernetes components expect the containerd data to be stored at the default location.

Create a symbolic link to the containerd directory:

$ ln -s /mnt/nvme/containerd /var/lib/containerd

Restart containerd to apply the configuration changes and enable it to start on boot:

$ systemctl restart containerd
$ systemctl enable containerd

Verifying containerd Installation

To confirm that containerd is installed and configured correctly, checkout the status of the containerd service:

$ systemctl status containerd
● containerd.service - containerd container runtime
     Loaded: loaded (/lib/systemd/system/containerd.service; enabled; preset: enabled)
     Active: active (running) since Sun 2025-01-12 20:16:00 CET; 21s ago
       Docs: https://containerd.io
   Main PID: 4629 (containerd)
      Tasks: 10
        CPU: 86ms
     CGroup: /system.slice/containerd.service
             └─4629 /usr/bin/containerd

Jan 12 20:16:00 kubernetes-node-1 containerd[4629]: time="2025-01-12T20:16:00.483721289+01:00" level=info msg="Start subscribing containerd event"
Jan 12 20:16:00 kubernetes-node-1 containerd[4629]: time="2025-01-12T20:16:00.483770622+01:00" level=info msg="Start recovering state"
Jan 12 20:16:00 kubernetes-node-1 containerd[4629]: time="2025-01-12T20:16:00.483840678+01:00" level=info msg="Start event monitor"
Jan 12 20:16:00 kubernetes-node-1 containerd[4629]: time="2025-01-12T20:16:00.483866549+01:00" level=info msg="Start snapshots syncer"
Jan 12 20:16:00 kubernetes-node-1 containerd[4629]: time="2025-01-12T20:16:00.483879086+01:00" level=info msg="Start cni network conf syncer for default"
Jan 12 20:16:00 kubernetes-node-1 containerd[4629]: time="2025-01-12T20:16:00.483890030+01:00" level=info msg="Start streaming server"
Jan 12 20:16:00 kubernetes-node-1 containerd[4629]: time="2025-01-12T20:16:00.484237568+01:00" level=info msg=serving... address=/run/containerd/containerd.sock.ttrpc
Jan 12 20:16:00 kubernetes-node-1 containerd[4629]: time="2025-01-12T20:16:00.484282883+01:00" level=info msg=serving... address=/run/containerd/containerd.sock
Jan 12 20:16:00 kubernetes-node-1 systemd[1]: Started containerd.service - containerd container runtime.
Jan 12 20:16:00 kubernetes-node-1 containerd[4629]: time="2025-01-12T20:16:00.485584240+01:00" level=info msg="containerd successfully booted in 0.038755s"

As you can see, the output shows that the containerd service is active and running.

Lesson Conclusion

Congratulations! With containerd installed and configured, your Raspberry Pi devices are now ready to run containers as part of the part of the Kubernetes cluster. You have completed this lesson and you can now continue with the next one.

Help improve this content
I strive to create helpful and accurate content, but there's always room for improvement! Whether you notice a typo, have ideas to make this clearer, or want to share your thoughts, I warmly welcome your feedback. Together, we can make this content even better for everyone.
Edit this page   |   Create an issue