Infrastructure as a Service

 View Only

MicroShift – Part 4: Raspberry Pi 4 with Raspberry Pi OS

By Alexei Karve posted Sun December 05, 2021 05:58 AM

  

Microshift on Raspberry Pi 4 with Raspberry Pi OS (64 bit)

Introduction

MicroShift is a research project that is exploring how OpenShift OKD Kubernetes distribution can be optimized for small form factor devices and edge computing. In the previous Parts (Part 1, Part 2 and Part 3) of this series, we looked at multiple ways to run MicroShift on a MacBook Pro and the Jetson Nano. In this Part 4, we will set up and deploy MicroShift on Raspberry Pi OS (64 bit). In Part 5 and Part 6 we will continue working with the Raspberry Pi 4. In Part 5, we will install Microshift on CentOS Stream 8 (64 bit) and in Part 6 on Ubuntu 20.04 (64 bit).

Raspbian is a 32-bit fork of Debian Linux that's optimized for the Pi. The official operating system for the Raspberry Pi changed its name from Raspbian to Raspberry Pi OS. The new 64-bit operating system doesn't use software from the Raspbian project. It now offers 64-bit support to go together with the new SBCs shipping with 8GB RAM.

Setting up the Raspberry Pi 4 with Raspberry Pi OS (64 bit)

Raspberry Pi 4 with SenseHat


We download the Raspberry Pi OS image zip and write to Microsdxc card, setup the sshd and hostname.

  1. Download the image from https://downloads.raspberrypi.org/raspios_arm64/images/raspios_arm64-2021-11-08/2021-10-30-raspios-bullseye-arm64.zip
  2. Write to Microsdxc card
  3. Have a Keyboard and Monitor connected to the Raspberry Pi
  4. Insert Microsdxc into Raspberry Pi4 and poweron, it will reboot after the file system is resized
  5. After first boot, you can change the pi password
  6. Enable ssh using sudo raspi-config -> “3 Interface Options” -> “P2 SSH”
  7. Set the hostname raspberrypi.example.com in “1 System Options” -> “S4 Hostname”

We login to the Raspberry Pi 4

ssh pi@$ipaddress
sudo su –

Check the release and check that the SELinux status is disabled

cat /etc/os-release
sestatus
root@raspberrypi:~# cat /etc/os-release
PRETTY_NAME="Debian GNU/Linux 11 (bullseye)"
NAME="Debian GNU/Linux"
VERSION_ID="11"
VERSION="11 (bullseye)"
VERSION_CODENAME=bullseye
ID=debian
HOME_URL="https://www.debian.org/"
SUPPORT_URL="https://www.debian.org/support"
BUG_REPORT_URL="https://bugs.debian.org/"
root@raspberrypi:/etc# sestatus
SELinux status:                 disabled


Control groups allow for allocating resources among user-defined processes on a system.  Control groups is a Linux kernel feature that enables organization of processes into hierarchically ordered groups - cgroups. The hierarchy (control groups tree) is defined by providing structure to cgroups virtual file system, mounted by default on the /sys/fs/cgroup/ directory by creating and removing sub-directories.

Update cgroup kernel parameters: concatenate onto the end of the existing line (do not add a new line) in /boot/cmdline.txt and reboot

 cgroup_enable=cpuset cgroup_memory=1 cgroup_enable=memory

The Sense HAT “Hardware attached on top” is an add-on board for the Raspberry Pi. The Sense HAT has an 8 × 8 RGB LED matrix, a five – button joystick and includes the following sensors: Inertial Measurement Unit (Accelerometer, Gyroscope, Magnetometer), Temperature, Barometric pressure, Humidity. If you have the Sense HAT attached, test it with i2cdetect. The 46 output for the LED matrix shows UU, that is fine.

root@raspberrypi:~# i2cdetect -y 1
     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
00:                         -- -- -- -- -- -- -- --
10: -- -- -- -- -- -- -- -- -- -- -- -- 1c -- -- --
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
40: -- -- -- -- -- -- UU -- -- -- -- -- -- -- -- --
50: -- -- -- -- -- -- -- -- -- -- -- -- 5c -- -- 5f
60: -- -- -- -- -- -- -- -- -- -- 6a -- -- -- -- --
70: -- -- -- -- -- -- -- --

0x5c: LPS25H Pressure
0x1c: LSM9DS1 9-axis iNEMO inertial module (IMU): 3D magnetometer, 3D accelerometer, 3D gyroscope
0x5f: HTS221 Humidity and Temperature
0x46: LED2472G 24-Channels LED driver with LED error detection and gain control
0x6a: LSM9DS1 Accelerometer Gyro Magnetometer

Test the Sense Hat's LED matrix - Run the sparkles.py and check the pixels changing color

cat << EOF > sparkles.py
from sense_hat import SenseHat
from random import randint
from time import sleep
sense = SenseHat()
while True:
    x = randint(0, 7)
    y = randint(0, 7)
    r = randint(0, 255)
    g = randint(0, 255)
    b = randint(0, 255)
    sense.set_pixel(x, y, r, g, b)
    sleep(0.1)
EOF

python3 sparkles.py # Ctrl-C to interrupt


Test the temperature sensor
-  Create the temperature.py and check the temperature reading

cat << EOF > temperature.py
from sense_hat import SenseHat

sense = SenseHat()

temp = sense.get_temperature_from_pressure()
#temp = sense.get_temperature_from_humidity()
print("Temperature: %s C" % temp)
sense.show_message("{:.1f} C".format(temp))
EOF

python3 temperature.py


Test the USB camera

Create the testcam.py and test the USB camera - Install the latest pygame. Note that pygame 1.9.6 will throw “SystemError: set_controls() method: bad call flags”. So, we need to upgrade pygame to 2.1.0.

pip3 install pygame --upgrade

cat << EOF > testcam.py
import pygame, sys
from pygame.locals import *
import pygame.camera
pygame.init()
pygame.camera.init()
cam = pygame.camera.Camera("/dev/video0",(352,288))
cam.start()
image= cam.get_image()
pygame.image.save(image,'101.bmp')
cam.stop()
EOF

python3 testcam.py # It will create a file 101.bmp

Install MicroShift

Clone the microshift repo so we can run the install.sh script

sudo su –
git clone https://github.com/thinkahead/microshift.git

Hardcode the DISTRO=ubuntu and OS_VERSION=20.04

root@raspberrypi:~/microshift# git diff install.sh 
diff --git a/install.sh b/install.sh
index 9e21c619..a0721e94 100755
--- a/install.sh
+++ b/install.sh
@@ -17,7 +17,8 @@ CONFIG_ENV_ONLY=${CONFIG_ENV_ONLY:=false}
 # Function to get Linux distribution
 get_distro() {
     DISTRO=$(egrep '^(ID)=' /etc/os-release| sed 's/"//g' | cut -f2 -d"=")
-    if [[ $DISTRO != @(rhel|fedora|centos|ubuntu) ]]
+    DISTRO=ubuntu
+    if [[ $DISTRO != @(rhel|fedora|centos|ubuntu|debian) ]]
     then
       echo "This Linux distro is not supported by the install script"
       exit 1
@@ -37,6 +38,7 @@ get_arch() {
 # Function to get OS version
 get_os_version() {
     OS_VERSION=$(egrep '^(VERSION_ID)=' /etc/os-release | sed 's/"//g' | cut -f2 -d"=")
+    OS_VERSION=20.04
 }

You could use the https://github.com/thinkahead/microshift/blob/main/install-raspberry-pi-os.sh where the changes are already made. You will need another change as mentioned in the Errors section below if it does not find crio 1.21.

Set the hostname with domain (if not already set)

hostnamectl set-hostname raspberrypi.example.com
# the host needs a fqdn domain for MicroShift to work well

Run the install script

./install.sh

We can get more details about the microshift service with

systemctl show microshift.service

To check the microshift systemd service, check the file /lib/systemd/system/microshift.service. It shows that the microshift binary is in /usr/local/bin/ directory.

root@raspberrypi:# cat /lib/systemd/system/microshift.service 
[Unit]
Description=MicroShift
After=crio.service

[Service]
WorkingDirectory=/usr/local/bin/
ExecStart=microshift run
Restart=always
User=root

[Install]
WantedBy=multi-user.target

To start microshift and check the status and logs, we can run

systemctl start microshift
systemctl status microshift
journalctl -u microshift -f

Install the oc client

wget https://mirror.openshift.com/pub/openshift-v4/arm64/clients/ocp/candidate/openshift-client-linux.tar.gz
mkdir tmp;cd tmp
tar -zxvf ../openshift-client-linux.tar.gz
mv -f oc /usr/local/bin
cd ..;rm -rf tmp

It will take around 3 minutes for all pods to start. Check the status of node and pods using kubectl or oc client.

export KUBECONFIG=/var/lib/microshift/resources/kubeadmin/kubeconfig
watch "kubectl get nodes;kubectl get pods -A;crictl pods;crictl images"
#watch "oc get nodes;oc get pods -A;crictl pods;crictl images"

Output when microshift is started

Every 2.0s: kubectl get nodes;kubectl get pods -A;crictl pods;crictl images                           raspberrypi.example.com: Fri Dec  3 07:53:09 2021

NAME                      STATUS   ROLES    AGE    VERSION
raspberrypi.example.com   Ready    <none>   3m2s   v1.21.0
NAMESPACE                       NAME                                  READY   STATUS    RESTARTS   AGE
kube-system                     kube-flannel-ds-5mbjn                 1/1     Running   0          2m59s
kubevirt-hostpath-provisioner   kubevirt-hostpath-provisioner-prk4t   1/1     Running   0          3m1s
openshift-dns                   dns-default-rhrt6                     2/2     Running   0          3m
openshift-dns                   node-resolver-h5dvr                   1/1     Running   0          3m
openshift-ingress               router-default-85bcfdd948-6v4g8       1/1     Running   0          3m1s
openshift-service-ca            service-ca-76674bfb58-f2rmd           1/1     Running   0          3m3s
POD ID              CREATED             STATE               NAME                                  NAMESPACE                       ATTEMPT             R
UNTIME
798d692c1c73f       40 seconds ago      Ready               dns-default-rhrt6                     openshift-dns                   0                   (
default)
325066912f355       41 seconds ago      Ready               router-default-85bcfdd948-6v4g8       openshift-ingress               0                   (
default)
e854d516b8ec9       2 minutes ago       Ready               service-ca-76674bfb58-f2rmd           openshift-service-ca            0                   (
default)
b22a6d7c46d80       2 minutes ago       Ready               kubevirt-hostpath-provisioner-prk4t   kubevirt-hostpath-provisioner   0                   (
default)
bde7383c29095       2 minutes ago       Ready               kube-flannel-ds-5mbjn                 kube-system                     0                   (
default)
93228e1009894       2 minutes ago       Ready               node-resolver-h5dvr                   openshift-dns                   0                   (
default)
IMAGE                                     TAG                             IMAGE ID            SIZE
k8s.gcr.io/pause                          3.2                             2a060e2e7101d       489kB
quay.io/microshift/cli                    4.8.0-0.okd-2021-10-10-030117   33a276ba2a973       205MB
quay.io/microshift/coredns                4.8.0-0.okd-2021-10-10-030117   67a95c8f15902       265MB
quay.io/microshift/flannel-cni            4.8.0-0.okd-2021-10-10-030117   0e66d6f50c694       8.78MB
quay.io/microshift/flannel                4.8.0-0.okd-2021-10-10-030117   85fc911ceba5a       68.1MB
quay.io/microshift/haproxy-router         4.8.0-0.okd-2021-10-10-030117   37292c44812e7       225MB
quay.io/microshift/hostpath-provisioner   4.8.0-0.okd-2021-10-10-030117   fdef3dc1264ad       39.3MB
quay.io/microshift/kube-rbac-proxy        4.8.0-0.okd-2021-10-10-030117   7f149e453e908       41.5MB
quay.io/microshift/service-ca-operator    4.8.0-0.okd-2021-10-10-030117   0d3ab44356260       276MB

Build the MicroShift binary for arm64 on Raspberry Pi OS (64 bit)

We can replace the microshift binary that was download from the install.sh script with our own. Let’s build the microshift binary from scratch. Clone the microshift repository from github, install golang, run make and finally move the microshift binary to /usr/local/bin.

sudo su -

apt -y install build-essential curl libgpgme-dev pkg-config libseccomp-dev

# Install golang
wget https://golang.org/dl/go1.17.2.linux-arm64.tar.gz
rm -rf /usr/local/go && tar -C /usr/local -xzf go1.17.2.linux-arm64.tar.gz
rm -f go1.17.2.linux-arm64.tar.gz
export PATH=$PATH:/usr/local/go/bin
export GOPATH=/root/go
cat << EOF >> /root/.bashrc
export PATH=$PATH:/usr/local/go/bin
export GOPATH=/root/go
EOF
mkdir $GOPATH

git clone https://github.com/thinkahead/microshift.git
cd microshift
make
./microshift version
ls -las microshift # binary in current directory /root/microshift
mv microshift /usr/local/bin/microshift
systemctl restart microshift

Output:

root@raspberrypi:~# git clone https://github.com/thinkahead/microshift.git
root@raspberrypi:~# cd microshift
root@raspberrypi:~/microshift# make
go build -mod=vendor -tags 'include_gcs include_oss containers_image_openpgp gssapi providerless netgo osusergo' -ldflags "-X k8s.io/component-base/version.gitMajor=1 -X k8s.io/component-base/version.gitMajor=1 -X k8s.io/component-base/version.gitMinor=21 -X k8s.io/component-base/version.gitVersion=v1.21.0 -X k8s.io/component-base/version.gitCommit=c3b9e07a -X k8s.io/component-base/version.gitTreeState=clean -X k8s.io/component-base/version.buildDate=2021-12-03T11:20:58Z -X k8s.io/client-go/pkg/version.gitMajor=1 -X k8s.io/client-go/pkg/version.gitMinor=21 -X k8s.io/client-go/pkg/version.gitVersion=v1.21.1 -X k8s.io/client-go/pkg/version.gitCommit=b09a9ce3 -X k8s.io/client-go/pkg/version.gitTreeState=clean -X k8s.io/client-go/pkg/version.buildDate=2021-12-03T11:20:58Z -X github.com/openshift/microshift/pkg/version.versionFromGit=4.8.0-0.microshift-unknown -X github.com/openshift/microshift/pkg/version.commitFromGit=63e378fb -X github.com/openshift/microshift/pkg/version.gitTreeState=dirty -X github.com/openshift/microshift/pkg/version.buildDate=2021-12-03T11:20:58Z -s -w" github.com/openshift/microshift/cmd/microshift
root@raspberrypi:~/microshift# ./microshift version
MicroShift Version: 4.8.0-0.microshift-unknown
Base OKD Version: 4.8.0-0.okd-2021-10-10-030117
root@raspberrypi:~/microshift# ls -las microshift
147672 -rwxr-xr-x 1 root root 151211021 Dec  3 06:30 microshift
root@raspberrypi:~/microshift# mv microshift /usr/local/bin/microshift

We may also download the latest microshift binary from github as follows:

ARCH=arm64
export VERSION=$(curl -s https://api.github.com/repos/redhat-et/microshift/releases | grep tag_name | head -n 1 | cut -d '"' -f 4) && \
curl -LO https://github.com/redhat-et/microshift/releases/download/$VERSION/microshift-linux-${ARCH}
chmod +x microshift-linux-${ARCH}
mv microshift-linux-${ARCH} /usr/local/bin/microshift
systemctl restart microshift

Install Docker on Raspberry Pi OS

Although we do not need docker for microshift, we will build images using docker and test some containers. So, let’s install docker.

apt-get install -y ca-certificates curl gnupg lsb-release
curl -fsSL https://download.docker.com/linux/debian/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/debian \
  $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
apt-get update
apt-get install docker-ce docker-ce-cli containerd.io

Samples to run on MicroShift

We will run a few samples that will show the use of helm, persistent volume, SenseHat and the USB camera. The first two samples are the same as in Part 3 that we ran on the Jetson Nano.

1. Mysql database server

Download helm and run the mysql server in a container with hostpath persistent volume and a mysql client container

# Install helm
curl -o helm-v3.5.2-linux-arm64.tar.gz  https://get.helm.sh/helm-v3.5.2-linux-arm64.tar.gz
tar -zxvf helm-v3.5.2-linux-arm64.tar.gz
cp linux-arm64/helm /usr/local/bin
rm -rf linux-arm64
rm -f helm-v3.5.2-linux-arm64.tar.gz
chmod 600 /var/lib/microshift/resources/kubeadmin/kubeconfig

# Add the repo for mysql helm chart
helm repo add stable https://charts.helm.sh/stable

oc project default
# Install mysql with provided image tag (hacky way to use the sha256 tag for the arm64 image) and my-user as the userid with custom passwords for root and my-user
helm install mysql stable/mysql --set mysqlRootPassword=secretpassword,mysqlUser=my-user,mysqlPassword=my-password,mysqlDatabase=my-database --set persistence.enabled=true --set storageClass=kubevirt-hostpath-provisioner --set image=mysql/mysql-server@sha256 --set imageTag=5e373bcea878b3657937c68cdefa8a1504f53e356ac19a3e51bf515e41e0c48c
helm list

# Remember to delete the /var/hpvolumes/mysql if it already exists (otherwise it will use old password from previous run)
rm -rf /var/hpvolumes/mysql

cat << EOF > hostpathpv.yaml
---
apiVersion: v1
kind: PersistentVolume
metadata:
  name: hostpath-provisioner
spec:
  #storageClassName: "kubevirt-hostpath-provisioner"
  capacity:
    storage: 8Gi
  accessModes:
    - ReadWriteOnce
  hostPath:
    path: "/var/hpvolumes/mysql"
...
EOF

# Create the persistent volume
kubectl apply -f hostpathpv.yaml

# Wait for the pod to be Running
kubectl get pods -n default -w

kubectl get svc mysql # Note down the CLUSTER-IP
export ipofmysqlserver=

2. Nginx web server

Create the file nginx.yaml

cat << EOF > nginx.yaml
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
spec:
  selector:
    matchLabels:
      app: nginx
  replicas: 2 # tells deployment to run 2 pods matching the template
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginxinc/nginx-unprivileged:alpine # arm64 image
        ports:
        - containerPort: 8080
        # resource required for hpa
        resources:
          requests:
            memory: 128M
            cpu: 125m
          limits:
            memory: 1024M
            cpu: 1000m
---
apiVersion: v1
kind: Service
metadata:
 name: nginx-svc
 labels:
   app: nginx
spec:
 type: NodePort
 ports:
 - port: 8080
   nodePort: 30080
 selector:
   app: nginx
...
EOF

# Create the deployment and service. Test it.
kubectl apply -f nginx.yaml
kubectl get svc nginx-svc # see the port 8080:30080

Now we can access nginx on the NodePort 30080

curl localhost:30080

If we add following the line to /etc/hosts on the Raspberry Pi 4

127.0.0.1       localhost nginx-svc-default.cluster.local

and run

oc expose svc nginx-svc

We can access nginx on port 80 using the route on the Raspberry Pi 4

curl localhost

Finally on your Laptop/MacBook Pro, you can add the line with ipaddress of the Raspberry Pi 4 with nginx-svc-default.cluster.local to /etc/hosts. Then access nginx at http://nginx-svc-default.cluster.local/

We can delete nginx with:

oc delete -f nginx.yaml
oc delete route nginx-svc

3. Sample with Sense Hat and USB camera

Let’s install Node Red on IBM Cloud. We will use Node Red to show pictures and chat messages sent from the Raspberry Pi 4. Alternatively, we can use the Node Red that we deployed as an application in MicroShift on the MacBook Pro in VirtualBox in Part 1.

  1. Create an IBM Cloud free tier account at https://www.ibm.com/cloud/free and login to Console (top right).
  2. Create an API Key and save it, Manage->Access->IAM->API Key->Create an IBM Cloud API Key
  3. Click on Catalog and Search for "Node-Red App", select it and click on "Get Started"
  4. Give a unique App name, for example xxxxx-node-red and select the region nearest to you
  5. Select the Pricing Plan Lite, if you already have an existing instance of Cloudant, you may select it in Pricing Plan
  6. Click Create
  7. Under Deployment Automation -> Configure Continuous Delivery, click on "Deploy your app"
  8. Select the deployment target Cloud Foundry that provides a Free-Tier of 256 MB cost-free or Code Engine. The latter has monthly limits and takes more time to deploy. [ Note: Cloud Foundry is deprecated, use the IBM Cloud Code Engine. Any IBM Cloud Foundry application runtime instances running IBM Cloud Foundry applications will be permanently disabled and deprovisioned ]
  9. Enter the IBM Cloud API Key from Step 2, or click on "New" to create one
  10. The rest of the fields Region, Organization, Space will automatically get filled up. Use the default 256MB Memory and click "Next"
  11. In "Configure the DevOps toolchain", click Create
  12. Wait for 10 minutes for the Node Red instance to start
  13. Click on the "Visit App URL"
  14. On the Node Red page, create a new userid and password
  15. In Manage Palette, install the node-red-contrib-image-tools, node-red-contrib-image-output, and node-red-node-base64
  16. Import the Chat flow and the Picture (Image) display flow. On the Chat flow, you will need to edit the template node line 35 to use wss:// (on IBM Cloud) instead of ws:// (on your Laptop)
  17. On another browser tab, start the https://mynodered.mybluemix.net/chat (Replace mynodered with your IBM Cloud Node Red URL)
  18. On the Image flow, click on the square box to the right of image preview or viewer to Deactivate and Activate the Node. You will be able to see the picture when you Activate the Node and run samples below
cd ~
git clone https://github.com/thinkahead/microshift.git
cd microshift/raspberry-pi/sensehat

3a. Test directly on the Raspberry Pi 4

pip3 install websocket-client

Update the URL to your node red instance and run the python code to send to Node Red

sed -i "s|mynodered.mybluemix.net|yournodered.mybluemix.net|" *.py
python3 sendtonodered.py

Output

root@raspberrypi:~/microshift/raspberry-pi/sensehat# python3 sendtonodered.py
pygame 2.1.0 (SDL 2.0.16, Python 3.9.2)
Hello from the pygame community. https://www.pygame.org/contribute.html
File 101.jpg uploaded
{"user":"raspberrypi4","message":"1638560972: Temperature: 28.572917938232422 C"}
waiting 5 seconds...
File 101.jpg uploaded
{"user":"raspberrypi4","message":"1638560982: Temperature: 28.625 C"}
waiting 5 seconds...

3b. Use a docker container

Check that we can access the Sense Hat and the camera from a container in docker

docker build -t karve/sensehat .
docker push karve/sensehat
docker run --privileged --name sensehat -ti karve/sensehat bash

# Inside the docker container
python sparkles.py # Tests the Sense Hat's LED matrix
python temperature.py # Get the temperature from Sense Hat’s sensor
python testcam.py # Creates 101.bmp

# Update the URL to your node red instance
sed -i "s|mynodered.mybluemix.net|yournodered.mybluemix.net|" *.py
python sendimages1.py # Ctrl-C to stop
python sendtonodered.py # Ctrl-C to stop
exit

docker rm -f sensehat

3c. Run in MicroShift

We will use the above docker image to send pictures and web socket chat messages to Node Red using a pod in MicroShift.

oc apply -f sensehat.yaml

When we are done, we can delete the deployment

oc delete -f sensehat.yaml

Cleanup MicroShift

We can use the script available on github to cleanup the pods and images. If you already cloned the microshift repo from github, you have the script in the ~/microshift/hack directory.

wget https://raw.githubusercontent.com/thinkahead/microshift/main/hack/cleanup.sh
bash ./cleanup.sh

Containerized MicroShift

We can run MicroShift within containers in two ways:

  1. MicroShift Containerized – The MicroShift binary runs in a Podman container, CRI-O Systemd service runs directly on the host and data is stored at /var/lib/microshift and /var/lib/kubelet on the host VM.
  1. MicroShift Containerized All-In-One – The MicroShift binary and CRI-O service run within a Podman container and data is stored in a podman volume, microshift-data. This should be used for “Testing and Development” only.

Microshift Containerized

We can either use the prebuilt image or build the image using docker.

To use the prebuilt image, set

IMAGE=quay.io/microshift/microshift:4.8.0-0.microshift-2021-11-19-115908-linux-arm64
docker pull $IMAGE

To build the image, clone the microshift repository from github and build

git clone https://github.com/thinkahead/microshift.git
cd microshift 

# Edit the packaging/images/microshift/Dockerfile. Replace the go-toolset with go-toolset:1.16.7-5
-FROM registry.access.redhat.com/ubi8/go-toolset as builder
+FROM registry.access.redhat.com/ubi8/go-toolset:1.16.7-5 as builder
# This will create the image quay.io/microshift/microshift:4.8.0-0.microshift-unknown-linux-arm64
make build-containerized-cross-build-linux-arm64 -e FROM_SOURCE=true

The Dockerfile uses the registry.access.redhat.com/ubi8/go-toolset:1.16.7-5 as builder to build the microshift binary. Then, it copies the binary to the registry.access.redhat.com/ubi8/ubi-minimal:8.4 that is used for the run stage. Output from the build:

root@raspberrypi:~/microshift# make build-containerized-cross-build-linux-arm64 -e FROM_SOURCE=true
make _build_containerized ARCH=arm64
make[1]: Entering directory '/root/microshift'
echo BIN_TIMESTAMP==2021-12-03T21:32:40Z
BIN_TIMESTAMP==2021-12-03T21:32:40Z
/usr/bin/docker build -t quay.io/microshift/microshift:4.8.0-0.microshift-unknown-linux-arm64 \
	-f "/root/microshift"/packaging/images/microshift/Dockerfile \
	--build-arg SOURCE_GIT_TAG=4.8.0-0.microshift-unknown \
	--build-arg BIN_TIMESTAMP=2021-12-03T21:32:40Z \
	--build-arg ARCH=arm64 \
	--build-arg MAKE_TARGET="cross-build-linux-arm64" \
	--build-arg FROM_SOURCE=true \
	--platform="linux/arm64" \
	.
Sending build context to Docker daemon  563.2MB
Step 1/17 : FROM registry.access.redhat.com/ubi8/go-toolset:1.16.7-5 as builder
1.16.7-5: Pulling from ubi8/go-toolset
…

go build -mod=vendor -tags 'include_gcs include_oss containers_image_openpgp gssapi providerless netgo osusergo' -ldflags "-X k8s.io/component-base/version.gitMajor=1 -X k8s.io/component-base/version.gitMajor=1 -X k8s.io/component-base/version.gitMinor=21 -X k8s.io/component-base/version.gitVersion=v1.21.0 -X k8s.io/component-base/version.gitCommit=c3b9e07a -X k8s.io/component-base/version.gitTreeState=clean -X k8s.io/component-base/version.buildDate=2021-12-03T21:32:40Z -X k8s.io/client-go/pkg/version.gitMajor=1 -X k8s.io/client-go/pkg/version.gitMinor=21 -X k8s.io/client-go/pkg/version.gitVersion=v1.21.1 -X k8s.io/client-go/pkg/version.gitCommit=b09a9ce3 -X k8s.io/client-go/pkg/version.gitTreeState=clean -X k8s.io/client-go/pkg/version.buildDate=2021-12-03T21:32:40Z -X github.com/openshift/microshift/pkg/version.versionFromGit=4.8.0-0.microshift-unknown -X github.com/openshift/microshift/pkg/version.commitFromGit=c5ad62e0 -X github.com/openshift/microshift/pkg/version.gitTreeState=dirty -X github.com/openshift/microshift/pkg/version.buildDate=2021-12-03T21:32:40Z -s -w" -o '_output/bin/linux_arm64/microshift' github.com/openshift/microshift/cmd/microshift
make[1]: Leaving directory '/opt/app-root/src/github.com/redhat-et/microshift'
Removing intermediate container 93ff567ab4e7
 ---> 2b2897b0aa96
Step 12/17 : FROM registry.access.redhat.com/ubi8/ubi-minimal:8.4
8.4: Pulling from ubi8/ubi-minimal
…
Step 15/17 : COPY --from=builder /opt/app-root/src/github.com/redhat-et/microshift/_output/bin/linux_$ARCH/microshift /usr/bin/microshift
…
Successfully built 6dafad18ab8e
Successfully tagged quay.io/microshift/microshift:4.8.0-0.microshift-unknown-linux-arm64
make[1]: Leaving directory '/root/microshift'
Set the IMAGE to the one we just built above
IMAGE=quay.io/microshift/microshift:4.8.0-0.microshift-unknown-linux-arm64

Run the microshift container

docker run --rm --ipc=host --network=host --privileged -d --name microshift -v /var/run:/var/run -v /sys:/sys:ro -v /var/lib:/var/lib:rw,rshared -v /lib/modules:/lib/modules -v /etc:/etc -v /run/containers:/run/containers -v /var/log:/var/log -e KUBECONFIG=/var/lib/microshift/resources/kubeadmin/kubeconfig $IMAGE
export KUBECONFIG=/var/lib/microshift/resources/kubeadmin/kubeconfig
watch "docker ps;kubectl get nodes;kubectl get pods -A;crictl images"

The output shows the microshift container running within docker and the rest of the pods in crio on the host

docker ps

CONTAINER ID   IMAGE                                                                  COMMAND                  CREATED         STATUS         PORTS
 NAMES
a0a2b53e07ae   quay.io/microshift/microshift:4.8.0-0.microshift-unknown-linux-arm64   "/usr/bin/microshift…"   5 minutes ago   Up 5 minutes
 microshift

kubectl get nodes

NAME STATUS ROLES AGE VERSION
raspberrypi.example.com   Ready    <none>   3m43s   v1.21.0

kubectl get pods -A

NAMESPACE                     NAME                                READY STATUS    RESTARTS AGE
kube-system                   kube-flannel-ds-bq98q               1/1   Running   0        3m40s
kubevirt-hostpath-provisioner kubevirt-hostpath-provisioner-frq2q 1/1   Running   0        3m43s
openshift-dns                 dns-default-sg7m2                   2/2   Running   0        3m41s
openshift-dns                 node-resolver-h6lqj                 1/1   Running   0        3m41s
openshift-ingress             router-default-85bcfdd948-c96f9     1/1   Running   0        3m42s
openshift-service-ca          service-ca-76674bfb58-bqwrz         1/1   Running   0        3m44s

crictl images

IMAGE                                   TAG                           IMAGE ID       SIZE
k8s.gcr.io/pause                        3.2                           2a060e2e7101d  489kB
quay.io/microshift/cli                  4.8.0-0.okd-2021-10-10-030117 33a276ba2a973  205MB
quay.io/microshift/coredns              4.8.0-0.okd-2021-10-10-030117 67a95c8f15902  265MB
quay.io/microshift/flannel-cni          4.8.0-0.okd-2021-10-10-030117 0e66d6f50c694 8.78MB
quay.io/microshift/flannel              4.8.0-0.okd-2021-10-10-030117 85fc911ceba5a  68.1MB
quay.io/microshift/haproxy-router       4.8.0-0.okd-2021-10-10-030117 37292c44812e7  225MB
quay.io/microshift/hostpath-provisioner 4.8.0-0.okd-2021-10-10-030117 fdef3dc1264ad  39.3MB
quay.io/microshift/kube-rbac-proxy      4.8.0-0.okd-2021-10-10-030117 7f149e453e908  41.5MB
quay.io/microshift/service-ca-operator  4.8.0-0.okd-2021-10-10-030117 0d3ab44356260  276MB

The microshift process is running within the microshift container

root@raspberrypi:~/microshift# docker top microshift -o pid,cmd
PID                 CMD
74205               /usr/bin/microshift run

The rest of the containers run within cri-o on the host:

root@raspberrypi:~/microshift# crictl pods
POD ID        CREATED         STATE   NAME                                  NAMESPACE
f12e4a9d51083 3 minutes ago   Ready   dns-default-sg7m2                     openshift-dns
4b02b06f2e870 3 minutes ago   Ready   router-default-85bcfdd948-c96f9       openshift-ingress
c9555515314ef 4 minutes ago   Ready   kube-flannel-ds-bq98q                 kube-system
f6146be11026f 4 minutes ago   Ready   node-resolver-h6lqj                   openshift-dns
381a7c185ccd4 4 minutes ago   Ready   kubevirt-hostpath-provisioner-frq2q   kubevirt-hostpath-provisioner
b6cc1733c42d8 4 minutes ago   Ready   service-ca-76674bfb58-bqwrz           openshift-service-ca

Now, we can run the samples shown in previous section.

After we are done, we can delete the microshift container. The --rm we used in the docker run will delete the container when we stop it.

docker stop microshift

After it is stopped, we can run the cleanup.sh to delete the pods and images from crio.

MicroShift Containerized All-In-One

Let’s stop the crio on the host, we will be creating an all-in-one container in docker that will have crio within the container.

systemctl stop crio

To build the all-in-one image, clone the microshift repository from github and run make

git clone https://github.com/thinkahead/microshift.git
cd microshift 

# Edit the packaging/images/microshift-aio/Dockerfile. Replace the go-toolset with go-toolset:1.16.7-5
-FROM registry.access.redhat.com/ubi8/go-toolset as builder
+FROM registry.access.redhat.com/ubi8/go-toolset:1.16.7-5 as builder

# This will create the image quay.io/microshift/microshift-aio:4.8.0-0.microshift-unknown-linux-nft-arm64
make build-containerized-all-in-one-arm64

The Dockerfile uses the registry.access.redhat.com/ubi8/go-toolset:1.16.7-5 as builder to get the microshift binary. Then, it copies the microshift binary, packaging files and downloads kubectl to the registry.access.redhat.com/ubi8/ubi-init:8.4 that is used for the run stage. It finally installs the cri-o and dependencies within the image. Output from the build:

root@raspberrypi:~/microshift# make build-containerized-all-in-one-arm64
make _build_containerized_aio ARCH=arm64
make[1]: Entering directory '/root/microshift'
echo BIN_TIMESTAMP==2021-12-04T13:18:37Z
BIN_TIMESTAMP==2021-12-04T13:18:37Z
/usr/bin/docker build -t quay.io/microshift/microshift-aio:4.8.0-0.microshift-unknown-linux-nft-arm64 \
	-f "/root/microshift"/packaging/images/microshift-aio/Dockerfile \
	--build-arg SOURCE_GIT_TAG=4.8.0-0.microshift-unknown \
	--build-arg BIN_TIMESTAMP=2021-12-04T13:18:37Z \
	--build-arg ARCH=arm64 \
	--build-arg MAKE_TARGET="cross-build-linux-arm64" \
	--build-arg FROM_SOURCE=false \
	--build-arg IPTABLES=nft \
	--platform="linux/arm64" \
	.
Sending build context to Docker daemon  563.3MB
Step 1/29 : ARG IMAGE_NAME=registry.access.redhat.com/ubi8/ubi-init:8.4
Step 2/29 : FROM registry.access.redhat.com/ubi8/go-toolset:1.16.7-5 as builder
…
Step 13/29 : RUN if [ "$FROM_SOURCE" == "true" ]; then       make clean $MAKE_TARGET SOURCE_GIT_TAG=$SOURCE_GIT_TAG BIN_TIMESTAMP=$BIN_TIMESTAMP &&       mv _output/bin/linux_$ARCH/microshift microshift;     else       export VERSION=$(curl -s https://api.github.com/repos/redhat-et/microshift/releases | grep tag_name | head -n 1 | cut -d '"' -f 4) &&       curl -LO https://github.com/redhat-et/microshift/releases/download/$VERSION/microshift-linux-$ARCH &&       mv microshift-linux-$ARCH microshift;     fi
…
Step 14/29 : FROM ${IMAGE_NAME}
8.4: Pulling from ubi8/ubi-init
…
Step 17/29 : ENV BUILD_PATH=packaging/images/microshift-aio
 ---> Running in fa3f914645a6
Removing intermediate container fa3f914645a6
 ---> 66724c255163
Step 18/29 : COPY --from=builder /opt/app-root/src/github.com/redhat-et/microshift/microshift /usr/local/bin/microshift
 ---> 865afaa572e7
Step 19/29 : COPY $BUILD_PATH/unit /usr/lib/systemd/system/microshift.service
 ---> 3e78aa44b735
Step 20/29 : COPY $BUILD_PATH/kubelet-cgroups.conf /etc/systemd/system.conf.d/kubelet-cgroups.conf
 ---> 3622d488a598
Step 21/29 : COPY $BUILD_PATH/crio-bridge.conf /etc/cni/net.d/100-crio-bridge.conf
 ---> 33e9a5457057
Step 22/29 : RUN curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/$ARCH/kubectl" &&     chmod +x ./kubectl &&     mv ./kubectl /usr/local/bin/kubectl
 ---> Running in e0eb7c669c2e
…
Step 25/29 : RUN dnf install -y cri-o         cri-tools         iproute         procps-ng &&     dnf clean all
 ---> Running in 5598191b9295
…
Successfully built c0850658b7b9
Successfully tagged quay.io/microshift/microshift-aio:4.8.0-0.microshift-unknown-linux-nft-arm64
make[1]: Leaving directory '/root/microshift'

Create a new docker volume microshift-data and run the microshift container

docker volume rm microshift-data;docker volume create microshift-data
docker run -d --rm --name microshift -h microshift.example.com --privileged -v /lib/modules:/lib/modules -v microshift-data:/var/lib -p 6443:6443 quay.io/microshift/microshift-aio:4.8.0-0.microshift-unknown-linux-nft-arm64 # You may also want to mount the -v /var/hpvolumes:/var/hpvolumes

Now login to the microshift container and see the pods created using crio within the container, not directly on the host. It may take upto 6 minutes for all pods to be started.

root@raspberrypi:~/microshift# docker exec -it microshift bash
[root@microshift /]# export KUBECONFIG=/var/lib/microshift/resources/kubeadmin/kubeconfig
[root@microshift /]# watch "kubectl get nodes;kubectl get pods -A;crictl images;crictl pods"

NAME                     STATUS   ROLES    AGE   VERSION
microshift.example.com   Ready    

We exit back to the host and check that the microshift container is still running within docker

root@raspberrypi:~/microshift# docker ps  -a
CONTAINER ID   IMAGE                                                                          COMMAND                  CREATED          STATUS          PORTS                                       NAMES
ac6cc94bc6d5   quay.io/microshift/microshift-aio:4.8.0-0.microshift-unknown-linux-nft-arm64   "/sbin/init"             38 minutes ago   Up 37 minutes   0.0.0.0:6443->6443/tcp, :::6443->6443/tcp   microshift

We can inspect the microshift-data volume to find the path

root@raspberrypi:~/microshift# docker volume inspect microshift-data
[
    {
        "CreatedAt": "2021-12-04T08:29:59-05:00",
        "Driver": "local",
        "Labels": {},
        "Mountpoint": "/var/lib/docker/volumes/microshift-data/_data",
        "Name": "microshift-data",
        "Options": {},
        "Scope": "local"
    }
]

On the host, we set KUBECONFIG to point to the kubeconfig on the data volume export KUBECONFIG=/var/lib/docker/volumes/microshift-data/_data/microshift/resources/kubeadmin/kubeconfig

# crio on host is stopped, so we do not run crictl commands on host
watch "kubectl get nodes;kubectl get pods -A"

Output

NAME                     STATUS   ROLES    AGE   VERSION
microshift.example.com   Ready    <none>   42m   v1.21.0

NAMESPACE NAME READY STATUS RESTARTS AGE kube-system kube-flannel-ds-g65bp 1/1 Running 0 42m kubevirt-hostpath-provisioner kubevirt-hostpath-provisioner-9nlh8 1/1 Running 0 41m openshift-dns dns-default-s6tzp 2/2 Running 0 31m openshift-dns node-resolver-7lkb7 1/1 Running 0 42m openshift-ingress router-default-85bcfdd948-bzfkj 1/1 Running 0 42m openshift-service-ca service-ca-57cbc45559-6vjm9 1/1 Running 0 31m

The following patch may be required if the dns-default pod in the openshift-dns namespace keeps restarting.

oc patch daemonset/dns-default -n openshift-dns -p '{"spec": {"template": {"spec": {"containers": [{"name": "dns","resources": {"requests": {"cpu": "80m","memory": "90Mi"}}}]}}}}'

You may also need to patch the service-ca deployment if it keeps restarting

oc patch deployments/service-ca -n openshift-service-ca -p '{"spec": {"template": {"spec": {"containers": [{"name": "service-ca-controller","args": ["-v=4"]}]}}}}'

Now, we can run the samples shown previously. Note that the /var/hpvolumes is within the microshift container. You will either need to mount it to the host or create any directories required by the samples within the container. For example, in case of the mysql sample, run “mkdir /var/hpvolumes/mysql” within the container.

After we are done, we can delete the microshift container. The --rm we used in the docker run will delete the container when we stop it.

docker stop microshift

After it is stopped, we can run the cleanup.sh to delete the pods and images from crio.

Errors

E: Unable to locate package cri-o

There is a problem that http://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable:/cri-o:/1.21/xUbuntu_20.04/arm64/ does not have the crio but http://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable:/cri-o:/1.21:/1.21.6/xUbuntu_20.04/arm64/ does, so you could replace the contents of /etc/apt/sources.list.d/devel:kubic:libcontainers:stable:cri-o:1.21.list with 1.21:/1.21.6/xUbuntu_20.04 after the crio:/

Another way is to update the CRIOVERSION=1.22 in the install.sh

Conclusion

In this Part 4, we saw multiple options to build and run MicroShift on the Raspberry Pi 4 with the Raspberry Pi OS (64 bit). We ran samples that used helm, persistent volume for mysql, Sense Hat, and USB camera. We saw a sample that sent the pictures and web socket messages to Node Red on IBM Cloud. In Part 5, we will deploy MicroShift on the Raspberry Pi 4 with CentOS 8 Stream. In Part 6, we will deploy MicroShift on the Raspberry Pi 4 with Ubuntu 20.04. We will look at Virtualization with MicroShift using KubeVirt on the Raspberry Pi 4 in Part 9.

Hope you have enjoyed the article. Share your thoughts in the comments or engage in the conversation with me on Twitter @aakarve. I look forward to hearing about your use of MicroShift on ARM devices and if you would like to see something covered in more detail.

References


​​​​


0 comments
69 views

Permalink