Learning K8s on PI – CRI-O

Docker is by far the de-facto runtime for kubernetes, at least in my opinion. The ability to build on the same machine that your are deploying is quite handy for learning. However, at some point you will start thinking, “I want to play with other run-times, whats out there to try?” Run-times aren’t huge differentiators until they absolutely ARE! Myself, I haven’t found a use case where one is better than the other, so this is focusing on learning and growing.

Now everything you just did in “Learning K8s on PI – Kubeadm” is exactly the same steps, as kubeadm, kubelet, and kubectl still need to be deployed in the same fashion with the same networking configs. These steps just replace the Docker installation within the kubernetes cluster. In fact, I’m going to verify these steps then kick this off to make sure that everything runs in the proper format.

In fact, I think I should add a script to this that allows you to set the hostname, version, OS, of the machine then you run it and everything just works. May make everyone’s life a lot easier, and make it much faster to get these brambles up and running. But I digress…


CRI-O is an awesome container alternative to docker. In fact, a couple stories in the news are saying that docker may not be the continued runtime for kubernetes and may be phased out! OH NO! This is the fun side of kubernetes and the CNCF, is there are always things changing and new things being added.

Couple things to be aware of before you try to install CRI-O. You need to set your version for your OS via an environmental variable: You can find the list here. You can see I’m using ubuntu20.04, and set CRI-O as a static version(list here ), to ensure that your running a proper version. I’ve had a couple tests with setting the cri-o version as an environmental variable, and it never worked so I’d suggest you do it statically(see below). Also be sure to update your OS before running these steps.

After those are set, run the following(each line is a step)…

sudo su


. /etc/os-release

sudo sh -c "echo 'deb http://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable/x${NAME}_${VERSION_ID}/ /' > /etc/apt/sources.list.d/devel:kubic:libcontainers:stable.list"

wget -nv https://download.opensuse.org/repositories/devel:kubic:libcontainers:stable/x${NAME}_${VERSION_ID}/Release.key -O- | sudo apt-key add -

The next two commands have the static version of the OS and of CRI-O, So set these to the appropriate versions. If your having issues then I’d suggest running these as set and you should be able to get it going.

sudo sh -c "echo 'deb http://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable:/cri-o:/1.18/xUbuntu_20.04/ /' > /etc/apt/sources.list.d/devel:kubic:libcontainers:stable:cri-o:1.18.list"

wget -nv https://download.opensuse.org/repositories/devel:kubic:libcontainers:stable:cri-o:1.18/xUbuntu_20.04/Release.key -O- | sudo apt-key add -

apt-get update
apt install -y cri-o cri-o-runc

systemctl enable crio.service
systemctl start crio.service

cat <<EOF > init.yaml
apiVersion: kubelet.config.k8s.io/v1beta1
kind: KubeletConfiguration
cgroupDriver: systemd
apiVersion: kubeadm.k8s.io/v1beta2
kind: ClusterConfiguration
podSubnet: ""

You have to do a couple cgroup settings with raspberry pi, so let’s do those quickly:

sudo nano /boot/firmware/cmdline.txt

At the end of the file add the following line: (NOTE: It should all be one line), and then enable the following settings

cgroup_enable=cpuset cgroup_memory=1 cgroup_enable=memory

cat <<EOF | sudo tee /etc/modules-load.d/k8s.conf
cat <<EOF | sudo tee /etc/sysctl.d/k8s.conf
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
sudo sysctl --system

echo 1 > /proc/sys/net/ipv4/ip_forward

iptables -I INPUT -j ACCEPT

The Kube stuff

Now, you can follow kubernetes.io/docs for setting up a cluster with kubeadm. I’ll walk it through:

  • sudo apt-get install -y apt-transport-https ca-certificates curl
  • sudo curl -fsSLo /usr/share/keyrings/kubernetes-archive-keyring.gpg https://packages.cloud.google.com/apt/doc/apt-key.gpg
  • echo "deb [signed-by=/usr/share/keyrings/kubernetes-archive-keyring.gpg] https://apt.kubernetes.io/ kubernetes-xenial main" | sudo tee /etc/apt/sources.list.d/kubernetes.list
  • sudo apt-get update (Updates repos with new google target)
  • sudo apt-get install -y kubelet kubeadm kubectl (does the bizness)
  • sudo apt-mark hold kubelet kubeadm kubectl (Keeps "apt upgrade" from touching these unless we want to do it ourselves"

REBOOT NOW!! Seriously reboot to ensure everything we’ve done take effect.

Ok, now if everything WORKED, then this next part will work… *fingers crossed*

kubeadm init --config init.yaml

now you can install the CNI, which I would suggest to use Weave:

kubectl apply -f "https://cloud.weave.works/k8s/net?k8s-version=$(kubectl version | base64 | tr -d '\n')"

After you install CRI-O you can go ahead and install all the other steps found in https://nerdynate.life/2021/03/14/learning-k8s-on-pi-kubeadm/ to enable the single host or multiple, and also to enable the CNI.

This took a long time to figure out for something that’s really small changes. The CRI or Container Runtime Interface is very much a random thing to go over as many people don’t really play with this stuff. CRI-O is everything you need in a runtime with nothing you don’t. So if you’re comparing it to docker, then it could give you some resources back, especially on something as lightweight as a Raspberry Pi.

I seriously hope this helps you learn about CRI-O and kubeadm. Its a fun solution to grow from and learn. I hope you have fun with this, and hit me up if you need help or have issues.