Notes from setting up a three node Raspberry Pi 3 Model B Kubernetes cluster using HypriotOS 64-bit.
Originally from Setup Kubernetes on a Raspberry Pi Cluster easily the official way! with some additions to fix things I ran into when following the guide. This guide uses a 64-bit version of HypriotOS and only armv8 64-bit Docker images will work.
Flash HypriotOS 64-bit to SD card. By using HypriotOS we can avoid a lot of the issues that comes with installing Docker on ARM.
You can skip the following steps for updating, setting up the k8s repo, and installing the k8s package using
--userdata
with the flash tool. See this example.
To begin, boot the Raspberry Pi to Hypriot, login and update system,
sudo apt update
sudo apt upgrade -y
Install Kubernetes from official package repositories on each node,
sudo su -
curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | apt-key add -
echo "deb http://apt.kubernetes.io/ kubernetes-xenial main" > /etc/apt/sources.list.d/kubernetes.list
apt update
apt install -y kubeadm kubelet
As root, init the cluster with the network CIDR for Flannel,
As of this writing this will install and configure Kubernetes 1.8
kubeadm init --pod-network-cidr 10.244.0.0/16
As the pirate
user setup kube config to run kubectl commands as non-root,
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
echo "export KUBECONFIG=${HOME}/.kube/config" >> ~/.bashrc
source ~/.bashrc
By default Kubernetes does not configure a Container Network Interface and needs to have one installed. Flannel has an arm64 version available and works reasonably well on the Raspberry Pi 3 and HypriotOS.
Install flannel using arm64 images,
With older versions of flannel, additinoal iptables rules were required, this was fixed in v0.9.1 (thanks for the tip Frank!)
curl -sSL https://raw.githubusercontent.com/coreos/flannel/v0.9.1/Documentation/kube-flannel.yml | sed "s/amd64/arm64/g" | kubectl create -f -
On each worker node run the kubeadm join
command that was output after successfully running kubeadm init
on the master node.
Join the node to the cluster,
sudo kubeadm join --token=$TOKEN
Show Node Status,
$ kubectl get nodes -o wide
NAME STATUS ROLES AGE VERSION EXTERNAL-IP OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME
navi Ready master 13m v1.8.4 <none> Debian GNU/Linux 9 (stretch) 4.9.65-hypriotos-v8 docker://17.10.0-ce
tael Ready <none> 4m v1.8.4 <none> Debian GNU/Linux 9 (stretch) 4.9.65-hypriotos-v8 docker://17.10.0-ce
tatl Ready <none> 4m v1.8.4 <none> Debian GNU/Linux 9 (stretch) 4.9.65-hypriotos-v8 docker://17.10.0-ce
Show Pod Status,
$ kubectl get pods --all-namespaces
NAMESPACE NAME READY STATUS RESTARTS AGE
kube-system etcd-navi 1/1 Running 0 15m
kube-system kube-apiserver-navi 1/1 Running 0 15m
kube-system kube-controller-manager-navi 1/1 Running 1 15m
kube-system kube-dns-596cf7c484-qrqsx 3/3 Running 0 14m
kube-system kube-flannel-ds-2rzg7 1/1 Running 0 8m
kube-system kube-flannel-ds-852gj 1/1 Running 0 13m
kube-system kube-flannel-ds-qxmws 1/1 Running 0 10m
kube-system kube-proxy-92762 1/1 Running 0 10m
kube-system kube-proxy-r78jd 1/1 Running 0 14m
kube-system kube-proxy-tfdjr 1/1 Running 0 8m
kube-system kube-scheduler-navi 1/1 Running 0 15
Using Docker Hub Official Multi-Platform Images makes running official Docker hub images on arm64 hardware much easier. Since Docker Hub now understands architecture manifest, no specific architecture tags are required and any official images will work on a Raspberry Pi k8s cluster without a specific tag.
Official images based off Alpine Linux currently do not work - see Issue #304 for more information.
In this example, we’ll run the official nginx image and have it listen on port 80.
First, deploy a nginx service with 3 replicas,
$ kubectl run nginx --image=nginx --replicas=3 --port=80
deployment "nginx" created
Expose pods in nginx service on port 80,
$ kubectl expose deployment nginx --port 80
service "nginx" exposed
Get endpoints for nginx service,
$ kubectl get endpoints
NAME ENDPOINTS AGE
kubernetes 192.168.7.220:6443 37m
nginx 10.244.1.2:80,10.244.1.3:80,10.244.2.2:80 23s
Run curl against an endpoint IP to test,
curl
should work against all endpoint IPs on all nodes
$ curl 10.244.2.2 | head -n 5
<DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>