K3s Knative Ubuntu Raspberry Pi

Featured image

K3s Knative Ubuntu Raspberry Pi

Knative is a super exciting solution for serverless and event driven applications. Personally, I have been using it as a part of my inner loop development. I can deploy dozens of workloads. All scaled down to zero when they aren’t being used. All responding and starting up quickly when they are needed.

I ran into a couple of problems with Envoy on Raspberry Pi OS. After investigating, it is a known issue in the Raspberry Pi OS kernel. In order to keep going forward with my project I had to choose between fixing the kernel or trying Ubuntu.

This is an overview of how to get Knative Serving working on a Raspberry Pi device with K3s and Ubuntu.

Install Ubuntu Server

Use RPI Imager. Select Ubuntu Server 22.10 64-bit from the list of other distributions. Boot the new image.

I was happy to see that SSH and the default user were configured as expected by using the advanced settings options.

Upgrade the stuff

# Grab the latest repository info
sudo apt update 
# Install one prerequisite package that isn't installed by default
sudo apt install linux-modules-extra-raspi -y
# Upgrade everything that can be upgraded
sudo apt dist-upgrade -y

Fix cgroup

# Add this to the beginning of /boot/firmware/cmdline.txt
# cgroup_enable=cpuset cgroup_memory=1 cgroup_enable=memory
sudo nano -w /boot/firmware/cmdline.txt

Reboot after making this change.

sudo shutdown -r now

Install k3s via k3sup

From my laptop, not one of the Raspberry Pi nodes, run k3sup, it’s super easy. If you haven’t figured it out by now, I’m a big fan of k3sup.

export CONTROL_NODE_IP=10.0.0.10
# Disable Traefik because we will use kourier for knative
k3sup install --ip $CONTROL_NODE_IP --user pi --k3s-extra-args '--disable traefik' --merge --local-path ~/.kube/config --context cluster00
# Knative-Serving with Kourier works on a single Raspberry Pi 4 with 8GB
# Optionally add other nodes
k3sup join --ip 10.0.0.11 --server-ip $CONTROL_NODE_IP --user pi
k3sup join --ip 10.0.0.12 --server-ip $CONTROL_NODE_IP --user pi

Deep breath

This is where I struggled with how to deliver this example. The Knative install documentation is awesome. I’ve been through it dozens of times!

I tried to simplify this for you. I want to give you the ’easy button’ experience. I created a repository with all the YAML you need to deploy Knative Serving to this K3s cluster.

Knative Serving with Kourier

git clone https://github.com/dashaun/knative-serving-raspberry-pi
cd knative-serving-raspberry-pi/operator-serving-kourier
# Use the `default` namespace in the Kubernetes cluster
kubectl config set-context --current --namespace=default
# Deploy the Knative operator
kubectl apply -f operator.yaml
# Check the deployment status
kubectl get deployment knative-operator

Continue when Ready status is 1/1

NAME               READY   UP-TO-DATE   AVAILABLE   AGE
knative-operator   1/1     1            1           19h
# Install Knative Serving custom resource and Kourier
kubectl apply -f knative-serving.yaml
# Check the custom resource status
kubectl get KnativeServing knative-serving -n knative-serving

Continue when READY is True

NAME              VERSION   READY   REASON
knative-serving   1.8.0     True
# Check the deployment status
kubectl get deployment -n knative-serving

Continue when READY are all 1/1

NAME                     READY   UP-TO-DATE   AVAILABLE   AGE
activator                1/1     1            1           23m
autoscaler               1/1     1            1           23m
controller               1/1     1            1           23m
domain-mapping           1/1     1            1           23m
domainmapping-webhook    1/1     1            1           23m
autoscaler-hpa           1/1     1            1           23m
3scale-kourier-gateway   1/1     1            1           23m
webhook                  1/1     1            1           23m
net-kourier-controller   1/1     1            1           23m

SSLIP.IO and a Spring Boot 3 native application

# Install default domain
kubectl apply -f serving-default-domain.yaml
# Deploy a Spring Boot 3 `native` application
kubectl apply -f spring-boot-native-pi-service.yaml
# Get the address
kubectl get ksvc spring-boot-native-pi --output=custom-columns=NAME:.metadata.name,URL:.status.url
NAME                    URL
spring-boot-native-pi   http://spring-boot-native-pi.default.10.0.0.10.sslip.io
# Curl the address provided by knative with `/actuator/health` at the end
curl http://spring-boot-native-pi.default.default.10.0.0.10.sslip.io/actuator/health

Expected output:

{"status":"UP"}

Summary

With the recent release of Spring Boot 3.0.0, my Raspberry Pi collection has become significantly more interesting. Knative Serving allows me to deploy dozens of Spring Boot / Spring Cloud workloads to a tiny, low power device, with very exciting capabilities.

Keep Learning