Qake: Hur jag byggde ett Raspberry Pi3-kluster med Kubernetes och Docker hemma - Cygate
Cystore

Qake: Hur jag byggde ett Raspberry Pi3-kluster med Kubernetes och Docker hemma

Kubernetes är ett open source-system skapat av Google för att hantera container-miljöer vad gäller skalning, deployment, operations samt uppgradering. När Apcera presenterade sina avsikter att inkludera stöd för Kubernetes så uppkom tanken hos Magnus Persson om att skapa ett litet Kubernetes-kluster hemmavid — allt för att kunna köra multiplayer-spelservrar för Qake, ett spel som utvecklas av skribenten.

Syftet med det här projektet var att skapa ett strömsnålt litet Docker-kluster som hanteras med Kubernetes. Ett kluster baserat på 4 stycken Raspberry Pi3 (Rpi3).

Klustret visade sig endast använda mellan 6-12W (c:a 0.1A) vid normal last. Lagom nivå när man vill ha ett eget kluster hemma!

Användningsområdet för klustret är att köra multiplayer-spelservrar för ett spel som är under utveckling av skribenten (http://qake.se). Spelservern är skriven i Javascript för både backend (NodeJS) och frontend (WebGL).
(En mycket tidigt demo utan multiplayerstöd finns att spela på: http://qake.se/demo/.)

Kubernetes går att köra på både publika och privata moln samt skapa hybridmiljöer. De containers som används i det här projektet är Docker-containers.

Mitt hemmaprojekt består av två delar:

  1. Första delen är bygget av plattformen rent hårdvarumässigt.
  2. Den andra delen är där mjukvaran i klustret sätts upp. (Läs gärna mer om Apceras tankar kring Kubernetes integrationen här: https://www.apcera.com/apcera-integrate-kubernetes-its-trusted-cloud-platform.)

 

Let’s get started!

Totalt ger de 4 RPi3 korten 4GB RAM samt 16 kärnor med 1.2GHz/kärna.

Mellan klient (webbläsare) och server används websockets. Spelservern emulerar hela spelvärlden på serversidan (”headlesss”) för att förhindra fusk med samma tekniker som används av stora spel som Half-Life och Quake.

All data som skickas mellan client/server är komprimerad och alla modeller läses in av servern som skickas i komprimerad binärdata till klienten. Alla rörelser som en klient gör emuleras även det på servern. Det innebär att spelservern har ett ganska krävande jobb och ju fler spelare desto fler serverinstanser krävs för att hålla upp i takt med antal spelare. Då passar ett autoskalande Kubernetes-kluster in riktigt bra.


Raspberry Pi bygger på en processorarkitektur som heter ARM:

Den skiljer sig åt från exempelvis x86 plattformen vilket de flesta datorerna har idag. Det medför att program kompilerade för x86 inte går att köra på ARM och då heller inte Raspberry Pi3.

För att underlätta installation av Kubernetes och Docker så användes en del förkompilerade versioner av både Kubernetes samt Docker. För Kubernetes användes kube-config (https://github.com/luxas/kubernetes-on-arm) och för Docker användes en förbyggd Docker deb-paket från Hypriot.

Mycket av konfigurationen för Kubernetes får man på köpet via kube-config där man kan installera diverse delar. Flannel installeras till exempel automatiskt, vilket hanterar det overlay-nätverk som används av kubernetes. Så i det här projektet blev det lite av en genväg för att snabbt komma igång och slippa kompilera hela Kubernetes för ARM.

Hypriot tillhandahåller även förbyggda image-filer med Docker på. Men vid tillfället för projektet så fanns det ingen förbyggd image med stöd för WiFi på Raspberry Pi3 korten och där av valdes att köra en ren Raspbian image (Debian byggt för Arm riktat mot Raspberrykorten). (I skrivande stund har det släppts en uppdaterad image från Hypriot-teamet där det ska funka bra att boota från WiFi på Rpi3.)

För att övervaka klustret så användes ett verktyg som heter Netdata. Det är ett open source verktyg som presenterar data på realtidsuppdaterade sidor. För projektet byggdes en egen sida där alla noders data presenterades i realtid. Även temperaturen för alla korten presenteras på sidan. Den så kallade ”kube.html” sidan finns att ladda ner under kapitlet ”Projektfiler”.


Hårdvara

Nedan är merparten av de delar som användes för bygget av klustret:

  • 4 x Raspberry Pi3 (1.2GHz Quad Core, 1GB RAM)
  • 4 x 8 GB mSDHC
  • 50W 10A USB nätaggregat
  • mUSB-kablar
  • Taisol 80mm 12V fläkt
  • Gröna lysdioder (18000 mcd)
  • 350 Ohms motstånd
  • Resetknappar
  • Stiftlist för kretskort
  • Låda från Ikea (DRAGAN)
  • 8 x aluminiumkylflänsar
  • Röda kabel-sleeves
  • En bunt kablar för finelektronik

(Röda kabel-sleeves samt kylflänsar beställdes från Kina. Övriga delar köptes från diverse svenska företag.)


Bygge

bild1_bloggpostTanken med klusterlådan var att få den så liten som möjlig samtidigt att få till ett utseende som smälter in i hemmet. Ett första bygge skapades där en Nexus 7 surfplatta skulle användas för övervakning:

När bygget var näst intill färdigt så vägrade plattan att fungera och bygget byttes ut mot ett mindre bygge.

Här bredvid en bild på hur det första bygget blev. Bilden visar hur plattan visar status för alla noder via en realtidsuppdaterad netdata sida. (Det blev en bygglogg för projektet som ni kan se här: http://www.sweclockers.com/galleri/13818-raspberry-pi-cluster.)


Det andra bygget började med att göra iordning lådan som klustret skulle husera i.

Undersidan gjordes iordning för att ha strömförsörjning samt sladdar i. Ovansidan borrades hål i för att få upp sladdarna från undersidan. Locket på lådan fick två stora hål där metallnät sattes in för att filtrera damm då fläkten drar luften genom lådan.
Det som skett efter bilderna togs var att sätta på kylflänsar på korten för att sänka temperaturen. Rpi3 är kända för att bli ganska varma. Därför sattes även en fläkt in i lådan som blåser igenom alla korten.
(Bilderna nedan visar bygget. En mer detaljerad bygglogg hittar ni här: http://www.sweclockers.com/galleri/13821-rpi3-cluster-2.)

bild_2_bloggpost bild_3_bloggpost
bild_4_bloggpost bild5_bloggpost
bild6_bloggpost

På lådan sitter det fyra lysdioder som visar om en nod är igång eller inte. Varje nod har även en knapp som kan resetta ett kort ifall man behöver göra det.
För att kunna resetta ett Raspberry-kort behöver du löda på stift på resetbryggan och sedan koppla en brytarswitch till den. Du behöver även vara aktsam när du löder på stift då det är väldigt lite utrymme för misstag på undersidan av kortet.
Dioderna sattes på +5V och ground på GPIO bryggan och varje diod har ett motstånd på 350 Ohm fastlött. Alla kablar är sleevade med röda sleeves för att få mer ordning och bättre luftflöde i lådan.


Router-konfiguration

RPi3 kort har inbyggt WiFi och det används för klustret. Detta är kanske inte något du normalt väljer för ett kluster som ska ha en hög tillgänglighet, men eftersom det är ett hemmakluster så är routern lika stor SPOF som korten i det här fallet.

Routern konfigurerades med static DHCP lease för de 4 korten, baserat på MAC filtrering. Varje nod döptes med prefix ”kube-”. En kontroller samt 3st worker-noder.

kube-controller: 192.168.1.150

kube-node1: 192.168.1.151

kube-node2: 192.168.1.152

kube-node3: 192.168.1.153


Manuellt installationssteg

Det första manuella steget är att skriva in en OS image på SD-korten. Det är ett svårt steg att automatisera ifall man inte har kortläsare med 4 portar för mSDHC (eftersom man behöver byta kort mellan skrivningarna).

Det operativsystem som användes var senaste Raspbian Lite (baserat på Debian Jessie) med kernel 4.4 (2016-05-10). OS-imagen skrevs in på varje kort med dd.


sudo dd bs=1m if=<image_namn>.img| pv |sudo dd of=/dev/disk6

Att pipe:a via kommandot ’pv’ ger status på hur mycket som skrivits till kortet så att man får en uppfattning på hur lång tid det tar.
Notera att det är viktigt att of är korrekt disk så att man inte skriver över fel disk!, i det här fallet var /dev/disk6 SD-kortet.
Efter SD-korten var på plats så bootades klustret upp med trådbundet ethernet för att se så att allt fungerade samt att WiFi gick att aktivera.


 Automatisk installation med Ansible

Eftersom installationsflödet består av ganska många steg samt på 4 kort så användes Ansible för att automatisera hela installationsflödet så långt det gick. Varje del beskrivs nedan följt av det Ansible script som användes.
Det gör det även enkelt att nollställa systemet ifall något gått fel och se till att allt är konsistent på korten.
(Vill man även flasha om korten så blir det enkelt att installera om allt, bara genom att köra playbooken nedan.)
Vissa script som används av systemet behövde modifieras en aning för att kunna köras automatiskt och ersätts därför av den så kallade Playbook som skapades.


Playbooken har följande flöde:

  1. Lägg in en modifierad raspi-config fil som inte är interaktiv.
  2. Kolla om docker är installerat.
  3. Om docker inte är installerat så kopiera över hypriot docker paketet.
  4. Om docker inte är installerat så installera deb paketet från (3).
  5. Kontrollera ifall filsystemet är expanderat (så att hela mSDHC kortet används)
  6. Om inte så kör raspi-config som är modifierad att enkelt expandera filsystemet åt oss.
  7. Starta om alla noder ifall filsystemet blev expanderat.
  8. Vänta på att servrarna är startade igen.
  9. Installera paketen som behövs för att bygga netdata (git, automake, gcc, autoconf, make, zlib1g-dev)
  10. Sätt korrekt hostnamn på noden
  11. Kolla om swap är skapad
  12. Om swap inte finns så skapa swapfil samt initiera swap av filen
  13. Aktivera swap
  14. Konfigurera swapiness till 1, vilket medför att den inte swappar förrän 99% av RAM-minnet används. Man vill helst undvika att swappa på SD-kortet då det är dålig prestanda samt har en tendens att skrivas sönder.
  15. Lägg in swap i fstab så att det används vid start.
  16. Kolla om kube-systemd är nerladdat. Annars ladda ner det.
  17. Installera kube-systemd
  18. Kopiera över en modifierad kube-systemd konfigurationsfil som går att köra utan interaktivitet.
  19. Installera kubernetes via kube-config install.
  20. Kolla om netdata är clonad från github. Annars clona ut det.
  21. Kontrollera om netdata är installerat redan. Annars bygg och installera netdata.
  22. Kopiera kube.html som används för att visa status på alla noder via netdata.
  23. Uppdatera rc.local så att netdata startas vid boot.
  24. Kopiera över WiFi konfigurationsfilen (wpa_supplicant.conf)
  25. Byt default lösenord till ett nytt.
  26. Starta om alla noder.


Nedan är hela ansible playbooken som gör det som beskrivs ovan:

#!/usr/bin/env ansible-playbook

– hosts: rpi

gather_facts: yes

vars:

wifi:

ssid: ”mywifisid”

password: ”mywifipassword”

packages_to_install: [ git, automake, gcc, autoconf, make, zlib1g-dev ]

update_cache: yes

sudo: yes

tasks:

– name: Add modified raspi-config

template: src=raspi-config dest=/usr/bin/raspi-config

 

– name: Check if docker pkg is installed

shell: dpkg -l |grep -i docker

ignore_errors: True

register: docker_exists

 

– name: Copy docker package

copy: src=docker-hypriot_1.10.3-1_armhf.deb dest=/home/pi/docker-hypriot_1.10.3-1_armhf.deb

when: docker_exists.rc != 0

 

– name: Install docker pkg

command: dpkg -i /home/pi/docker-hypriot_1.10.3-1_armhf.deb

when: docker_exists.rc != 0

 

– name: Check if fs is expanded

shell: df -h | grep ”/dev/root       7”

ignore_errors: True

register: expanded_res

 

– name: Expand root fs

command: raspi-config

when: expanded_res.rc != 0

 

– name: restart machine

shell: sleep 2 && shutdown -r now

async: 1

poll: 0

sudo: true

ignore_errors: true

when: expanded_res.rc != 0

 

– name: waiting for server to come back

local_action: wait_for host={{ inventory_hostname }} state=started delay=10 timeout=60

sudo: false

when: expanded_res.rc != 0

 

– name: install ubuntu packages

apt: pkg={{ item }} state=installed update_cache={{ update_cache }}

with_items: packages_to_install

 

– name: Assign hostname

raw:  ”echo {{hostname|quote}} > /etc/hostname”

 

– name: Update hosts file

template: src=hostsfile dest=/etc/hosts

 

– name: Check if swap exists and is not zero size

command: /usr/bin/test -s /swap/swapfile

ignore_errors: True

register: swap_res

 

– name: Create swapdir

file: path=/swap state=directory mode=0755

when: swap_res.rc != 0

 

– name: Create swapfile

file: path=/swap/swapfile state=touch mode=0600

when: swap_res.rc != 0

 

– name: Create swap

command: dd if=/dev/zero of=/swap/swapfile bs=1M count=512

when: swap_res.rc != 0

 

– name: Make swap

command: mkswap /swap/swapfile

when: swap_res.rc != 0

 

– name: Swap on

command: swapon /swap/swapfile

when: swap_res.rc != 0

 

– name: Swappiness

lineinfile: dest=/etc/sysctl.conf line=”vm.swappiness=1″

 

– name: fstab update

lineinfile: dest=/etc/fstab line=”/swap/swapfile none swap sw 0 0″

 

– name: Check if kube-systemd is downloaded already

command: /usr/bin/test -s /root/kube-systemd.deb

ignore_errors: True

register: kube_res

 

– name: download kube-config

get_url: url=https://github.com/luxas/kubernetes-on-arm/releases/download/v0.7.0/kube-systemd.deb dest=/root/kube-systemd.deb mode=0755

when: kube_res.rc != 0

 

– name: Install kube-config

apt: deb=/root/kube-systemd.deb

 

– name: Copy modified kube-config

copy: src=kube-config dest=/usr/bin/kube-config mode=0755

 

– name: Install with modified kube-config

shell: /usr/bin/kube-config install

 

– name: Check if netdata is cloned already

command: /usr/bin/test -d /home/pi/netdata

ignore_errors: True

register: netdata_res

 

– name: Checkout netdata

git: repo=https://github.com/firehol/netdata.git dest=/home/pi/netdata

when: netdata_res.rc != 0

 

– name: check if netdata is installed

command: /usr/bin/test -e /usr/sbin/netdata

register: netdata_exists

ignore_errors: True

 

– name: Build netdata

shell: cd /home/pi/netdata; echo | /home/pi/netdata/netdata-installer.sh

when: netdata_exists.rc != 0

 

– name: Copy kube.html page

template: src=kube.html dest=/usr/share/netdata/web/kube.html mode=0755

 

– name: Update rc.local with autostart of netdata.

lineinfile: dest=/etc/rc.local line=”/usr/sbin/netdata” insertbefore=”exit 0″

when: netdata_exists.rc != 0

 

– name: put wifi config in place

template: src=wpa_supplicant.conf.j2 dest=/etc/wpa_supplicant/wpa_supplicant.conf

 

– name: Change pi password

user: name=pi update_password=always password=<mysecret>

 

– name: restart machines

shell: sleep 2 && shutdown -r now

async: 1

poll: 0

sudo: true

ignore_errors: true

when: expanded_res.rc != 0


För att ansible ska veta vad alla hostar har för IP samt login så skapades filen hosts med följande innehåll:

[rpi]

kube-controller ansible_ssh_host=192.168.1.150 ansible_ssh_user=pi ansible_ssh_pass=mypass host_key_checking=false hostname=kube-controller

kube-node1 ansible_ssh_host=192.168.1.151 ansible_ssh_user=pi ansible_ssh_pass=mypass host_key_checking=false hostname=kube-node1

kube-node2 ansible_ssh_host=192.168.1.152 ansible_ssh_user=pi ansible_ssh_pass=mypass host_key_checking=false hostname=kube-node2

kube-node3 ansible_ssh_host=192.168.1.153 ansible_ssh_user=pi ansible_ssh_pass=mypass host_key_checking=false hostname=kube-node3

 

Ansibles konfigurationsfil fick följande innehåll för att bland annat peka ut hosts filen:

[defaults]

hostfile = ./hosts

host_key_checking = False

deprecation_warnings = False


Ansibles konfigurationsfil fick följande innehåll för att bland annat peka ut hosts filen:

[defaults]

hostfile = ./hosts

host_key_checking = False

deprecation_warnings = False


När allt var på sin plats kördes playbooken med följande kommando:

ansible-playbook playbook.yml
En fördel med att köra Ansible är att det går att köra samma kommando åter igen och status på alla noder kommer då vara samma efter varje körning. Om t.ex. Kubernetes är avinstallerat på en nod så kommer det vara installerat igen efter nästa körning.


Några manuella steg återstod efter ansible-installation och det var att aktivera klustret. På kube-controller (kontrollernoden) körs kommandot:

kube-config enable-master
Det körs för att säga till kubernetes vilken nod som är kontrollern. På de resterande noderna körs stället:
kube-config enable-worker 192.168.1.150
Det IP som angavs efter kommandot är kontrollernodens IP. Om vi inte anger det så hittar den inte vilken nod som är kontrollernoden.
Med kommandot ”kube-config info” kan man sedan se info om klustret. ”kubectl get no” ger status på alla noder.

 

Bild_kod

 

För att även få en dashboard till Kubernetes så installerades den via kube-config enable-addon dashboard som då deployas på klustret och går att nå via webbläsaren på url http://192.168.1.150:8080/ui/.

 

Bild_kubernetes
Kube-config kan även användas för att installera en färdig lastbalanserare samt DNS server. Kubectl är det cli-gränssnitt som finns mot kubernetes och används för att skapa podar, services, replication controllers samt se status på diverse komponenter.


Netdata installation

Netdata installerades även det via Ansible; en installation per nod + kontroller.
Kube.html anropar via Javascript varje nods netdata URL och presenterar returnerad data på sidan. Där av får man ett gränssnitt för alla noder i klustret som går att nå via nätet. Nedan är ett screenshot på hur det ser ut.

Sidan visar i realtid nätverk RX/TX, RAM, swap, CPU, temperatur, disk r/w. Det går även att lägga in grafer för IO-wait vilket kan vara nyttigt att se var flaskhalsen i systemet är. I det här fallet är det mSDHC korten (se kapitel ”Nästa steg” för hur en HDD kan användas istället).

Bild_kubernetes_2


 Docker på ARM

Ett litet ”problem”, om man kan kalla det så, är att processor-arkitekturen på Raspberry Pi är ARM.
De flesta docker images som finns att tillgå på t.ex. Docker Hub är kompilerade för x86 arkitekturen. Det medför att man exempelvis inte kan skapa en docker-fil med ”FROM: ubuntu” eftersom den kommer basera docker-containern på Ubuntu x86 från Docker Hub.

I det här fallet fanns en skapad image på Docker Hub som teamet bakom Hypriot släppt som även var byggt med NodeJS (hypriot/rpi-node) support.

Om man försöker exekvera en container som är byggd på fel arkitektur får man felet som nedan eftersom det inte går att exekvera binärerna:

Bild_kubernetes_3


 Docker image med NodeJS server

För att hantera docker med annan användare än root, i det här fallet användaren ”pi” så måste man lägga in pi till gruppen ”docker”.
sudo usermod -aG docker pi

Där efter kan man använda docker-kommandot för att skapa containers, images etc.
Att bygga en docker-image från ett existerande projekt är ganska enkelt. Det enda man behöver skapa är en Dockerfile i katalogen för projektet. I filen specificerar man vilken bas man vill utgå ifrån (i det här fallet hypriot/rpi-node som baseras på raspbian och node för ARM).

Man specificerar vilken port man vill öppna upp, vilka filer/kataloger som skall ingå samt hur applikationen skall exekveras.


Filen Dockerfile för spelet blev följande:

FROM hypriot/rpi-node

EXPOSE 8081

ADD *.* /qake/

ADD server/ /qake/server/

ADD bootstrap /qake/bootstrap/

ADD images/ /qake/images/

ADD js/ /qake/js/

ADD libs/ /qake/libs/

ADD maps/ /qake/maps/

ADD models/ /qake/models/

ADD sound/ /qake/sound/

WORKDIR ”/qake/server/”

CMD node server.js
I Dockerfile specificeras även WORKDIR vilket medför att CMD exekveras i den sökvägen (utan WORKDIR hade det blivit ”node /qake/server/server.js), vilket kan vara bra beroende på hur applikationen är uppbyggd. Porten 8081 är vad spelet lyssnar på i nodejs servern.


När filen är skapad är det dags att bygga docker-imagen med följande kommando:

docker build –t lallassu/qake.
Det kan ta ett tag första gången då den behöver hämta ner de images som behövs för att bygga.

Bild_kubernetes_4


För att vara säker på att en docker-image fungerar innan man deployar den så är det enkelt att starta igång en container med ett skal:

docker run -it qake /bin/bash
Då får man upp ett bash-skal där man kan testa att exekvera så som ”CMD” anger i Dockerfile. I det här fallet: node server.js


Docker registry (docker.io)

För att enkelt kunna komma åt sina docker-images så kan man använda sig av de tjänster som finns. Gcr.io är en tjänst från Google (Google Cloud Registry).

En annan är Docker Hub (docker.io). På docker.io får man ett privat-repo vilket används i det här fallet. Man kan också skapa ett eget registry lokalt ifall man föredrar det.

För att komma åt ett privat docker.io repository behöver man skapa en så kallad secret i kubernetes. Det gör man på följande vis:

  1. Logga in via docker: docker login
  2. Då skapas filen ~/.docker/config.json
  3. Skapa en base64 kodning av filen: cat ~/.docker/config.json |base64
  4. Skapa sedan en fil med valfritt namn (secret.yml) med följande innehåll:
    apiVersion: v1

kind: Secret

metadata:

name: registrypullsecret

data:

.dockerconfigjson: <base64_string>

type: kubernetes.io/dockerconfigjson

  1. Skapa sedan med följande kommando: kubectl create –f ./secret.yml
  2. Sedan kan man lista alla secrets: kubectl get secrets

Den skapade ”secreten” kommer användas i konfigurationen för pod:ar för att få access till docker-registry då en image ska hämtas.


Det är enkelt att ladda upp sin image till docker.io via kommandot:

docker push lallassu/qake

Kubernetes pod

En pod i kubernetes är en eller flera containers som delar storage och körs på samma underliggande hårdvara. För att skapa en pod med en container av spelet så skapades följande konfigurationsfil. Här används YAML format men även JSON går att använda (qake.yml):

apiVersion: v1

kind: Pod

metadata:

name: qake

spec:

containers:

– name: private

image: lallassu/qake:latest

imagePullSecrets:

– name: registrypullsecret

Det man specificerar i den här filen är namnet på pod:en. Vilka containers som ska vara med samt vilken image som ska användas. Även vilken secret som ska användas anges så att det går att hämta den image man vill ha från docker-registry (docker.io).


Podden kan sedan skapas med kommandot:

kubectl create –f qake.yml


Det kommandot går fort men pod:en är inte nödvändigtvis uppe för det. För att se status på poden kan man använda kommandot:

kubectl get pods


Vill man ha mer information om vilka events som sker kan man kolla med describe på följande vis:

kubectl describe qake

Bild_kubernetes_5


 Kubernetes replication controller konfiguration

För att enklare skapa skalning av pod:ar så kan man skapa en replication-controller. Det sker på liknande vis som för en pod. Följande fil skapades (även den i YAML format):

apiVersion: v1

kind: ReplicationController

metadata:

name: qakerc

spec:

replicas: 2

selector:

app: qake

template:

metadata:

name: qake

labels:

app: qake

spec:

containers:

– name: qake

image: docker.io/lallassu/qake:latest

ports:

– containerPort: 8081

imagePullSecrets:

– name: registrypullsecret


En av de stora ändringarna här mot i pod-filen är att vi specificerar ”replicas”. Det vill säga att vi vill köra två uppsättningar av poden (det går självklart att specificera fler). Det medför att vi får två IP:n att gå mot för båda replikor:

pi@kube-controller:~ $ kubectl describe svc

Name:                                         qakerc

Namespace:                             default

Labels:                                        app=qake

Selector:                                   app=qake

Type:                                           ClusterIP

IP:                                                 10.0.0.102

Port:                                             <unset>  8081/TCP

Endpoints:                                 10.1.64.2:8081,10.1.71.4:8081

Session Affinity:    None

No events.

I det här fallet tilldelades det följande IPn med portar: 10.1.64.2:8081,10.1.71.4:8081. Varje pod får ett helt nät tilldelat sig och därav blir det olika nät som pod:arna ligger på.

Kubernetes kommer inte med någon lastbalanserare utan det förväntas man tillhandahålla själv. Det finns flera alternativ, t.ex. Calico som har stöd för GBP, HA-Proxy etc. Molnleverantörer brukar leverera lastbalanserare som man kan använda sig av.


I det här fallet skapades endast enkla iptables-regler för att komma åt noderna externt för att se att det fungerade som det skulle:

iptables -A PREROUTING -t nat -i wlan0 -p tcp –dport 8085 -j DNAT –to 10.1.64.2:8081

iptables -A FORWARD -p tcp -d 10.1.64.2 –dport 8085 -j ACCEPT


Resultat: Hur gick det med spelservrarna?

Efter mycket jobb med att hitta rätt byggstenar som är kompilerade för ARM så gick till slut spelservrarna igång. Nedan är två screenshots som visar dels klienten (webläsaren)
där spelet körs samt servern som hanterar spelarna.

Bild_kubernetes_6

Bild_kubernetes_7


 Kubernetes kontrollpanel

Kubernetes kommer även med en dashboard som det går att deploya applikationer via. Den är inte lika kraftfull som kubectl men ger en bra överblick på vad som körs etc. Nedan är några screenshots från panelen:

 

Bild_kubernetes_8

Bild_kubernetes_9


Nästa steg

Kubernetes plattformen är en stor och avancerad produkt som har stöd för autoskalning. Nästa steg är att autoskala spelservrarna. Helst behöver man även autoskala underliggande hårdvara vilket skulle gå bra via API på Cygate Hosted VMware eller Elastic Cloud Server.

Att använda mSDHC kort, som i det här fallet inte var så snabba, är lätt att byta ut till en hårddisk. Man kan då ”jump-boota” från SD-kortet till disken genom att ändra i /boot/cmdline.txt från följande:

dwc_otg.lpm_enable=0 console=ttyAMA0,115200 console=tty1 root=/dev/sda1 rootfstype=ext4 elevator=deadline rootwait


Till att istället ange disken som root:

dwc_otg.lpm_enable=0 console=ttyAMA0,115200 console=tty1 root=/dev/mmcblk0p2 rootfstype=ext4 elevator=deadline rootwait

Förutom risken för hög IO-wait mot disk då man kör mSDHC så riskerar man att de skrivs sönder över tid. Av egen erfarenhet skrivs ett kort sönder efter c:a 1år även om man kör utan swap samt lägger flyktiga kataloger i ramFS (/tmp/, /var/ etc).

Att lägga in en lastbalanserare framför klustret är även ett steg att göra, så att man enkelt kan lastbalansera mellan sina podar.

Det finns fortfarande en uppsjö av kunskap att fördjupa sig i när det kommer till Kubernetes, så som autoskalning av sina pod:ar. Det här projektet har bara skrapat lite på ytan.


Slutsats: Ett projekt som gav mersmak!

Detta var ett roligt projekt som ger mersmak på att fortsätta undersöka diverse plattformar för att managera docker-containers.

Nästa del skulle kunna bli att se över Docker Swarm som är Docker-projektets egna typ av manageringsverktyg för containers?

Raspberry Pi är trevliga små enkortsdatorer med bra prestanda för att vara så billiga. De kan användas till mycket, kolla gärna in mina andra projekt där jag använt Raspberry Pi:

 

sweclockers_logoSom en extra bonus kammade projektet hem en tredje plats i Corsairs ”Månadens galleri
i juli 2016” på Sweclockers!
Läs mer på Sweclockers hemsida:
http://www.sweclockers.com/forum/post/16195920


Projektfiler

Alla filer för projektet går att ladda ner här:

http://qake.se/project_files.tar.gz


Länkar

Spelets hemsida: http://qake.se

Netdata: https://github.com/firehol/netdata

Kubernetes: http://kubernetes.io/

Hypriot: http://blog.hypriot.com/

Docker: https://www.docker.com/

Docker.io: https://hub.docker.com/

Bygglogg 2:a bygget: http://www.sweclockers.com/galleri/13821-rpi3-cluster-2

Bygglogg 1:a bygget: http://www.sweclockers.com/galleri/13818-raspberry-pi-cluster

Raspbian Lite: https://downloads.raspberrypi.org/raspbian_lite_latest

Kubernetes on ARM: https://github.com/luxas/kubernetes-on-arm

Kube-systemd: https://github.com/luxas/kubernetes-on-arm/releases/download/v0.7.0/kube-systemd.deb

 

/Magnus Persson, Cygate Cloud