Dies ist das Repo für unseren Blogpost https://bee42.com/de/blog/tutorials/kubernetes-cluster-on-embedded/, schaut mal rein!
Achtung: Mit der Hypriot-Version 1.4.0 gab es einen schwerwiegenden Fehler: Die Machine-ID wurde nicht neu generiert und war deshalb bei allen RPI's identisch. Das führte zu Problemen mit dem Netzwerk-Layer!
Alternative kann man den Cluster auch folgendermassen aufbauen:
Wir bauen einen kompleten Kubernetes-Cluster auf Embedded-Hardware. Dazu benutzen wir einen EdgeRouterX, 2 WLAN-Router, 2 Switches, ein Intel UP-Board und für den eigentlichen K8S-Cluster Raspberry Pi's.
Alle Komponenten die Ihr braucht um einen Docker PI-Cluster aufzubauen können in der Regel preiswert und zuverlässig bestellt werden. Wir haben uns an der Liste von Roland Huss orientiert:
Danke Roland :-)
Wir haben hier den aktuellsten RPI Modell 3B+ genommen, ein RPI 2 funktioniert aber auch, natürlich mit Abstrichen in der Leistung.
Stand 2018-10 ca. 290 Euro
Anzahl | Systemkomponente | Preis |
---|---|---|
3 | Raspberry Pi 3 B+ | 3 * 41 EUR |
3 | Micro SD Card 32 GB | 3 * 8 EUR |
1 | WLAN Router | 1 * 34 EUR |
4 | USB Kabel | 1 * 7 EUR |
1 | USB Stromgerät | 1 * 29 EUR |
1 | Gehäuse | 1 * 10 EUR |
2 | Zwischenplatten | 2 * 7 EUR |
5 | Ethernet Kabel | 1 * 8 EUR |
1 | Ethernet 8 Port Switch | 1 * 32 EUR |
- Kühler für die PI kaufen und installieren
- OnOff Shim von Pimoroni installieren oder selber bauen
- Nicht vergessen es wird ein Ethernet Switch und Ethernetkabel benötigt. Die WLAN Verbindungen sind in der Regel zu störanfällig.
- POE Switch und POE 3+ Hat installieren.
- TP-Link-TL-WR902AC-AC750
- https://www.amazon.de/dp/B01MY5JIJ0
- Konfiguration via ROOT WLAN Access Point spart den Edge Router und die zweiten TP Link Access Point.
Stand: 2018-10-06
Wer die aktuelle Docker 18.06 mit dem aktuellen Kubernetes 1.12.x zum laufen bringen möchte, muss etwas in die Trickkisten greifen und das OS Image für die RPIs selber herstellen.
Installieren von virtualbox und vagrant mit Homebrew
$ brew cask install virtualbox
$ brew cask install virtualbox-extension-pack
$ brew cask install vagrant
$ git clone https://github.com/hypriot/image-builder-rpi
$ cd image-builder-rpi
$ vagrant up
$ export DOCKER_HOST=tcp://127.0.0.1:2375
# check OS version and docker version
$ docker info | grep 'Operating System'
Operating System: Ubuntu 16.04.5 LTS
$ mv versions.config versions-orginal.config
$ cat >versions.config <<EOF
# config vars for the root file system
HYPRIOT_OS_VERSION="v2.0.1"
ROOTFS_TAR_CHECKSUM="d1e7e6d48a25b4a206c5df99ecb8815388ec6945e4f97e78413d5a80778d4137"
# name of the ready made raw image for RPi
RAW_IMAGE="rpi-raw.img"
RAW_IMAGE_VERSION="v0.2.2"
RAW_IMAGE_CHECKSUM="2fbeb13b7b0f2308dbd0d82780b54c33003ad43d145ff08498b25fb8bbe1c2c6"
# specific versions of kernel/firmware and docker tools
export KERNEL_BUILD="20180422-141901"
# For testing a new kernel, use the CircleCI artifacts URL.
# export KERNEL_URL=https://62-32913687-gh.circle-artifacts.com/0/home/circleci/project/output/20180320-092128/raspberrypi-kernel_20180320-092128_armhf.deb
export KERNEL_VERSION="4.14.34"
export DOCKER_CE_VERSION="18.06.1~ce~3-0~raspbian"
export DOCKER_COMPOSE_VERSION="1.22.0"
export DOCKER_MACHINE_VERSION="0.15.0"
EOF
$ make sd-image
$ make test
flash hypriotos-rpi-dirty.img.zip
# put SD card to rpi and switch it on
$ ssh [email protected]
$ docker version
$ sudo apt-get update
$ sudo apt-get install rpi-update
$ sudo rpi-update
$ sudo reboot
Prüfen die vorhandenen Kernels im Hypriot Deb Repo
$ ssh -i ~/.ssh/id_ed25519-rpi [email protected]
$ sudo apt-cache madison raspberrypi-kernel
Tipp: Wenn der Kernel selbst gebaut werden muss, prüfe ob das "privileged: true" Flag im Vagrantfile
gesetzt ist.
- Starte einen lokalen HTTP Server für das image-builder-rpi Projekt.
- Prüfe die Informationen im
build_results
Verzeichnis und addiere den Pfad in der Dateiversions.config
im derKERNEL_URL
Variable.
$ cat >docker-compose.yml <<EOF
version: '3'
services:
nginx:
image: nginx:latest
volumes:
- ./nginx-cache:/var/cache/nginx
- ./nginx-pid:/var/run
- ./build_results:/usr/share/nginx/html:ro
ports:
- 8081:80
read_only: true
EOF
$ docker-compose up -d
Hier zur Ansicht meine `versions.config``
$ cat >versions.config <<EOF
# config vars for the root file system
HYPRIOT_OS_VERSION="v2.0.1"
ROOTFS_TAR_CHECKSUM="d1e7e6d48a25b4a206c5df99ecb8815388ec6945e4f97e78413d5a80778d4137"
# name of the ready made raw image for RPi
RAW_IMAGE="rpi-raw.img"
RAW_IMAGE_VERSION="v0.2.2"
RAW_IMAGE_CHECKSUM="2fbeb13b7b0f2308dbd0d82780b54c33003ad43d145ff08498b25fb8bbe1c2c6"
# specific versions of kernel/firmware and docker tools
# export KERNEL_BUILD="20180422-141901"
export KERNEL_BUILD="20181007-162516"
# For testing a new kernel, use the CircleCI artifacts URL.
# export KERNEL_URL=https://62-32913687-gh.circle-artifacts.com/0/home/circleci/project/output/20180320-092128/raspberrypi-kernel_20180320-092128_armhf.deb
export KERNEL_URL=http://192.168.178.56:8081/20181007-162516/raspberrypi-kernel_20181007-162516_armhf.deb
export KERNEL_VERSION="4.14.70"
export DOCKER_CE_VERSION="18.06.1~ce~3-0~raspbian"
export DOCKER_COMPOSE_VERSION="1.22.0"
export DOCKER_MACHINE_VERSION="0.15.0"
EOF
Wenn die Disk zu klein ist kann das vagrant-disksize Plugin vielleicht helfen:
Vagrant.configure("2") do |config|
required_plugins = %w( vagrant-vbguest vagrant-disksize )
_retry = false
required_plugins.each do |plugin|
unless Vagrant.has_plugin? plugin
system "vagrant plugin install #{plugin}"
_retry=true
end
end
if (_retry)
exec "vagrant " + ARGV.join(' ')
end
config.vm.box = "ubuntu/trusty64"
config.disksize.size = "30GB"
end
Es gibt mehrere Möglichkeiten ein RPi-Image auf eine SD-Karte zu bekommen. Wir nutzen für diesen Anwendungsfall das Flash Tool der Hypriot Priraten. Als Basis der Installation verwenden wir das aktuelle Hypriot OS.
Mit folgendem Befehlen installiert Ihr das Hypriot Flash Tool:
$ curl -O https://raw.githubusercontent.com/hypriot/flash/master/flash
$ chmod +x flash
$ sudo mv flash /usr/local/bin/flash
Da Kubernetes in der Version 1.9.x offziel nur Docker CE bis 17.03 unterstützt, nehmen wir das Image V1.7.1 und (re-)installieren im weiteren Verlauf darauf Docker in der passenden Version:
$ mkdir OS-Images
$ cd OS-Images
$ HOS_VERSION=1.7.1
$ HOS_URL=https://github.com/hypriot/image-builder-rpi/releases/download
$ curl -LO ${HOS_URL}/v${HOS_VERSION}/hypriotos-rpi-v${HOS_VERSION}.img.zip
Entpacken des Images:
$ unzip hypriotos-rpi-v${HOS_VERSION}.img.zip
Alternative kann das selbsterstellte hypriotos images mit docker 18.06.x für Kubernetes 1.12.1 verwendet werden. Dort muss aktuell nur der Kernel immer manuelle auf den aktuellen Stand 4.14.73 oder neuer gebracht werden.
In dieser Datei können diverse Einstellungen vorgenommen werden, z.B. der zu vergebende Hostname, anzulegende User, oder, wie im folgenden Beispiel, SSH-Public-Keys für den passwortlosen Zugriff. Ein Beispiel findet Ihr im Repo.
Nach Erstellung der Datei user-data.yml
könnt Ihr diese direkt mit auf die SD-Karte flashen. Ansonsten könnt ihr auch nach dem flashen die user-data.yml
direkt auf dem PI bearbeiten.
$ flash -n "bee42-crew-01-001" -u "user-data.yml" hypriotos-rpi-v${HOS_VERSION}.img
Nach dem Einsetzen der Karten könnt Ihr den Raspberry-PI starten. Nun könnt Ihr Euch zum Test mit dem PI per SSH verbinden.
$ ssh pirate@<ip>
Frage: Wie bekommt eigentlich heraus welche IP dem PI vom DHCP Server zugeordnet wurde?
# install nmap
$ brew install nmap
$ nmap -sn 192.168.42.0/24 # Durch Euer Netz ersetzen
Das Passwort für den Nutzer pirate lautet: hypriot.
Im Blog der Hypriot Piraten findet Ihr jede Mengen Erklärungen zum Thema Docker on ARM:
- https://blog.hypriot.com/getting-started-with-docker-on-your-arm-device/
- https://hub.docker.com/u/hypriot/
Zur Ausführung unseres Installationsscripts auf den einzelen RPIs benutzen wir Ansible.
$ brew install ansible
Dafür benötigen wir zunächst ein Inhaltsverzeichnis. Wir haben mehrere Cluster, deshalb ist die Konfiguration in der Datei cluster
etwas größer angelegt:
[cluster-1-master]
192.168.42.11
[cluster-1-nodes]
192.168.42.12
192.168.42.13
[cluster-1:children]
cluster-1-master
cluster-1-nodes
[cluster-1:vars]
fqdn_master="bee42-crew-01-001.local"
network_address_master="192.168.42.11"
[master:children]
cluster-1-master
[nodes:children]
cluster-1-nodes
Für eine K8s Cluster sollten die Maschinen eine fixe IP Adresse besitzen. Wir fixieren also die DHCP Records im Edge Max.
Die Maschinen müssen dann alle rebooted werden.
Auf einem MAC kann man den DNS Cache mit folgendem Kommando erneuern:
sudo killall -HUP mDNSResponder
Ansible verbindet sich per SSH auf die zu verwaltenden Rechner, dort muss also öffentlicher SSH-Key hinterlegt sein. Falls Ihr noch keinen habt, hier ein kleines Beispiel:
# Schlüssel erzeugen
$ ssh-keygen -t ed25519 -C "[email protected]"
# Öffentlichen Schlüssel auf alle RPIs kopieren
$ ssh-copy-id [email protected]
$ ssh-copy-id [email protected]
...
# Testen der Maschinenverfügbarkeit :
$ export SSH_KEY=~/.ssh/id_ed25519
$ export K8sCLUSTER=cluster-1
$ ansible -u pirate --key=$SSH_KEY -i cluster -l $K8sCLUSTER -m ping all
192.168.42.11 | success >> {
"changed": false,
"ping": "pong"
}
192.168.2.12 | success >> {
"changed": false,
"ping": "pong"
}
So, wenn alle Vorbereitungen abgeschlossen sind, kann der Kubernetes-Cluster erzeugt werden. Ein RPI wird zum Master und die restlichen werden als Nodes angeschlossen.
$ export K8sCLUSTER=cluster-1
$ export KUBERNETES_VERSION=1.13.2
$ export DOCKER_VERSION=18.09.1
$ ansible-playbook -u pirate --key=$SSH_KEY -i cluster -l $K8sCLUSTER kubernetes.yml
$ ssh 192.168.42.11
$ mkdir -p .kube
$ sudo cp /etc/kubernetes/admin.conf .kube/config
$ sudo chown -R pirate:pirate .kube/
$ kubectl get nodes
NAME STATUS ROLES AGE VERSION
bee42-crew-04-001 Ready master 8m53s v1.12.0
bee42-crew-04-002 Ready <none> 6m32s v1.12.0
bee42-crew-04-003 Ready <none> 6m22s v1.12.0
$ kubectl run my-shell --rm -i --tty --image alpine -- /bin/sh
> ls
ssh <new machine>
sudo useradd -m -p hypriot -s /bin/bash pirate
sudo usermod -aG sudo pirate
exit
ssh-copy-id -i $SSH_KEY [email protected]
I2C:
Todo:
- Kopieren der Images eines Release in eine Registry
- Installation der PI's auf der Basis dieser Registry
- Einrichten eines Mirrors
- Einrichten eines DNS Server für alle Cluster
- Test mit einem Unify Router via Ethernet
- WLAN Router nur für Crew
- Test mit weiteren AccessPoints
- DHCP?
- Loadbalancer
- External DNS
- Noip Dynamic DNS
Manchmal möchte man den Cluster abreissen und vielleicht in einer anderen Version neu bauen, deshalb gibt es auch ein Reset-Playbook:
$ ansible-playbook -u pirate --key=$SSH_KEY -i cluster -l $K8sCLUSTER reset.yml
TIPP: Phönix aus der Asche entstehen lassen
Wer einen wirklich unbelastete Maschine benötigt, sollte allerdings lieber die SD Karte flashen und den RPI neu starten.
--audit-log-maxage=30 \
--audit-log-maxbackup=3 \
--audit-log-maxsize=100 \
--authorization-mode=Node,RBAC \
--enable-swagger-ui=true \
--event-ttl=1h \
--insecure-bind-address=127.0.0.1 \
--runtime-config=rbac.authorization.k8s.io/v1alpha1 \
--v=2
Liebe Grüße
Peter [email protected]