Wer schon immer einen eigenen Docker Cluster betreiben möchte, kann dies einfach über z.B. drei Raspberry Pis oder natürlich auch auf einer anderen Hardware oder Virtuellen Umgebungen bereitstellen.
Warum Docker und nicht gleich eine Virtuelle Maschine die dasselbe kann?
Vielfach handelt es sich um einen kleinen Service, bei dem es übertrieben ist eine komplette Virtuelle Maschine bereitzustellen. Weiter hat man mit einem Container die Möglichkeit den selben Service innert Kürze x-fach bereitzustellen, da jeder Container bis auf die «veränderbaren» Daten immer aus dem selben Docker Image bereitgestellt wird. Klar könnte man das auch mit VM-Templates bauen benötigt aber in den meisten fällen viel zu viele Ressourcen da jedes Mal das komplette Betriebssystem mitkommt.
Warum gleich ein Cluster und was sind da die Vorteile?
In gewissen Umgebungen ist es wichtig das ein Dienst immer oder so gut wie immer verfügbar ist, auch wenn man Wartungen durchführt oder natürlich, auch wenn ein Hardware defekt auftreten sollte. Der Swarm Manager überwacht alles und falls nötig wird der Container einfach auf einem anderen Node neu gestartet.
Hardware
Für unseren Aufbau verwenden wir drei Raspberry Pis, da die Hardware bereits vorhanden war und Ressourcen schonend sind.
Wichtig nicht alle Docker Container laufen auf ARM-Hardware!
- 3x Raspberry PI
- 3x Argon One M.2 Case
- 3x 512 GB M.2 SATA SSD inkl. Argon One erweiterung
Netzwerk
Hostname | IP-Adresse | Type |
---|---|---|
Docker1 | 10.40.10.211 | Manager |
Docker2 | 10.40.10.212 | Worker |
Docker3 | 10.40.10.213 | Worker |
Installation
Die Installation ist überschaubar sofern das Raspberry Pi OS Lite (64-bit) bereits auf den Raspberry Pis installiert ist.
Vorbereitungen
Hostname ändern
hostnamectl set-hostname dockerX.onesystems.ch
Statische IP-Adresse konfigurieren
/etc/dhcpcd.conf
interface eth0 static ip_address=10.40.10.211/24 static routers=10.40.10.1 static domain_name_servers=10.40.10.2 10.40.10.3
SSH Keys
- Erstellen (falls mann noch keinen eigenen besitzt)
ssh-keygen -t rsa
- Public Key auf alle Nodes verteilen
SERVER="10.40.10.211, 10.40.10.212, 10.40.10.213" for s in $SERVER do ssh-copy-id -i ~/.ssh/id_rsa.pub pi@$s done
Konfiguration
sudo raspi-config
Updaten
# Kernel Updates sudo rpi-update # Pakete Updaten sudo apt update sudo apt upgrade -y sudo reboot
SSD migration starten
SD-Karte auf das USB-Laufwerk klonen
- USB-Stick oder USB-Festplatte einstecken
- Überprüfen, ob das USB-Laufwerk ersichtlich ist (mmcblk0 ist die SD-Karte)
sudo fdisk -l sudo lsblk
- rpi-clone installieren
git clone https://github.com/billw2/rpi-clone.git cd rpi-clone sudo cp rpi-clone rpi-clone-setup /usr/local/sbin sudo rpi-clone-setup -t $(hostname -s) sudo rpi-clone -s
- SD-Karte auf das USB-Laufwerk klonen
sudo rpi-clone sdX
sdX durch die richtige Festplatte ersetzen, in der Regel sollte es sda sein.
Raspberry Pi für das Booten von einem USB-Laufwerk aktivieren
Der betreffende Raspberry Pi muss einmalig mit Raspbian von einer SD-Karte gebootet werden. Den USB-Boot-Modus aktiviert man mit einem Parameter in der Konfigurationsdatei „/boot/config.txt“.
echo program_usb_boot_mode=1 | sudo tee -a /boot/config.txt
Wichtig ist jetzt das Raspberry Pi neu zu starten und das ohne SD-Karte, wenn jetzt alles wieder startet läuft das Betriebssystem über die USB-Festplatte.
sudo halt
Dateisystem vergrössern
Da in den meisten fällen die USB-Festplatte grösser ist wie die SD-Karte kann mit dem folgenden Befehl die Partition angepasst werden:
sudo raspi-config --expand-rootfs
GlusterFS
Damit ein Docker Container auch auf einem anderen Docker Node gestartet werden kann sollten alle Nodes Zugriff auf dieselben Daten haben, im HomeLab könnte man da ein Zentrales NAS-System verwenden, was auf jedem Node per NFS zu Verfügung gestellt wird. Damit die Docker Nodes aber etwas unabhängiger vom Rest der Infrastruktur werden, kann man auch ein verteiltes Dateisystem mit GlusterFS oder Ceph aufbauen.
Installation
apt install -y xfsprogs attr ntp ntpdate glusterfs-server glusterfs-common glusterfs-client systemctl start glusterd.service systemctl enable glusterd.service
Cluster erstellen
gluster peer probe docker2.onesystems.ch gluster peer probe docker3.onesystems.ch
Überprüfen ob der Cluster aufgebaut wurde:
gluster peer status
Konfiguration
Lokale Ordner anlegen
mkdir -p /gluster/bricks/1/data
Volumen erstellen und berechtigungen setzen (Nur auf dem Node 1)
gluster volume create docker \ replica 3 \ docker1.onesystems.ch:/gluster/bricks/1/data \ docker2.onesystems.ch:/gluster/bricks/1/data \ docker3.onesystems.ch:/gluster/bricks/1/data \ force
Da wir das Volumen direkt auf dem «Root» Dateisystem anlegen, muss der Befehl mit «force» erweitert werden, dort wo eine separate Partition vorhanden ist kann der «force» Schalter weggelassen werden.
Volumen starten
gluster volume start docker
Mit einer «Allow» Liste kann eingeschränkt werden, dass nur die drei Raspberry Pis zugriff auf das Volumen erhalten:
gluster volume set docker auth.allow 10.40.10.211,10.40.10.212,10.40.10.213
Mounten (auf allen Nodes)
Damit alle drei Docker Server denselben Pfad für die Docker Konfigurationen verwenden kann nun das Volumen permanent verfügbar gemacht werden:
mkdir -p /docker echo 'localhost:/docker /docker glusterfs defaults,_netdev,backupvolfile-server=localhost 0 0' >> /etc/fstab mount.glusterfs localhost:/docker /docker
Damit der Mount auch nach einem neustart fehlerfrei geladen wird sollte noch die startreienfolge angepasst werden:
mkdir -p /etc/systemd/system/srv.mount.d/ cat << OV-EOF > /etc/systemd/system/srv.mount.d/override.conf [Unit] After=glusterfs-server.service Wants=glusterfs-server.service OV-EOF
Docker installieren
Mit dem folgenden Skript wird die «Standard» Docker Installation inkl. Docker-Compose installiert:
SERVER="10.40.10.211, 10.40.10.212, 10.40.10.213" for s in $SERVER do ssh root@$s 'apt update' ssh root@$s 'apt install -y ca-certificates curl gnupg' ssh root@$s 'sudo install -m 0755 -d /etc/apt/keyrings' ssh root@$s 'curl -fsSL https://download.docker.com/linux/debian/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg' ssh root@$s 'sudo chmod a+r /etc/apt/keyrings/docker.gpg' ssh root@$s 'echo "deb [arch="$(dpkg --print-architecture)" signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/debian "$(. /etc/os-release && echo "$VERSION_CODENAME")" stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null' ssh root@$s 'apt update' ssh root@$s 'apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin' done
Cluster erstellen
Als nächstes wird der Docker Swarm Cluster aufgebaut, auch dies funktioniert mit wenigen befehlen fast automatisch.
Initialisieren
docker swarm init --advertise-addr 10.40.10.211
Token abrufen
docker swarm join-token manager docker swarm join-token worker
Mit den Befehlen können nun die Nodes einfach zum Cluster hinzugefügt werden.
Prüfen ob alle Nodes verbunden sind
docker node ls
Portainer installieren
Damit man einzelne Docker Nodes oder in unserem falle einen Swarm einfach und unkompliziert verwalten kann empfiehlt sich z.B. den «Portainer», mit dem es dann möglich wird über eine Management Webseite die komplette Farm zu verwalten.
mkdir -p /docker/portainer cd /docker/portainer curl -L https://downloads.portainer.io/portainer-agent-stack.yml -o portainer-agent-stack.yml docker stack deploy -c portainer-agent-stack.yml portainer