Skip to content

Ahoi – Kubernetes Cluster im Homelab aufbauen (1/2)

Kubernetes im Homelab zu betreiben, kann eine ziemliche Herausforderung sein. Daher gibt es auch Kubernetes Produkte wie Minikube oder K3s die einem einige Aufgaben abnehmen und vereinfachen. An vielen Stellen reicht im Homelab auch ein einfacher(er) Docker Host um in die Welt der Container zu schnuppern. Wer einen “vollwertigen” Kubernetes (K8s) Cluster in seinem Homelab aufbauen möchte, erfährt hier wie es geht.

Arbeitet man sich durch die Dokumentationen für Kubernetes, wird man sehr schnell feststellen, dass man so gut wie alles auf mindestens drei Arten machen kann in der Kubernetes Welt. Der hier beschriebene Weg muss nicht der beste für eure Anforderung sein, er erschien nur mir als der einleuchtendste. Ich folge im ersten Teil weitestgehend der offiziellen Dokumentation für die Installation eines Kubernetes Clusters mit kubeadm. Diese könnt ihr hier finden. Für diesen Beitrag setze ich ein paar Dinge voraus, die vor dem Weiterlesen erledigt sein müssen:

  • Min. drei Linux Hosts mit Ubuntu 20.04 installiert (min. 2 CPUs und 2GB RAM; besser 4GB RAM). Davon ist ein Host als Control Plane und zwei als Worker Nodes gedacht.
  • Netzwerkkonnektivität zwischen den Hosts
  • Eindeutige Hostnamen, MAC Adressen und product_uuid je Host (mehr Infos findet ihr hier)
  • Die hier beschriebenen Ports dürfen nicht in Verwendung / belegt sein. Weiterhin müssen die Ports erreichbar sein untereinander. Ich empfehle euch eine eventuell zusätzlich konfigurierte Firewall zu deaktivieren (bspw. ufw)
  • Swap muss deaktiviert sein
  • Ich empfehle euch, einen NTP Dienst auf den Hosts aktiviert zu haben

Ich empfehle euch auch weiterhin, dass die Linux Hosts als virtuelle Maschine (VM) bereitgestellt werden und ihr einen Hypervisor / Storage einsetzt, der es euch ermöglicht Snapshots zu erstellen. Ich werde entsprechende Hinweise in dem Beitrag hinterlassen, wenn ich empfehle einen Snapshot zu erstellen. Sollte ab dort etwas schiefgehen, müsst ihr nicht zuviel Zeit mit dem Lösen von Problemen verbringen, sondern könnt den Snapshot zurückspielen.

Container Runtime installieren

Als erstes stellen wir sicher, dass iptables sogenannten Bridged Traffic erkennen kann. Dazu führen wir auf allen Nodes folgende Befehlsfolge aus.

sudo modprobe br_netfilter

cat <<EOF | sudo tee /etc/modules-load.d/k8s.conf
br_netfilter
EOF

cat <<EOF | sudo tee /etc/sysctl.d/k8s.conf
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
EOF
sudo sysctl --system

Nun kommen wir zur ersten grundlegenden Entscheidung, nämlich welche Container Runtime wir installieren möchten. Ich habe mir für Docker entschieden. Eine detailierte Anleitung zur Installation einer Container Runtime könnt ihr hier und hier finden.

Um Docker zu installieren, führt ihr folgende Befehlsfolge auf allen Hosts durch.

sudo apt-get update

sudo apt-get install \
    ca-certificates \
    curl \
    gnupg \
    lsb-release

# Docker Key und Repo hinzufügen
curl -fsSL https://download.docker.com/linux/ubuntu/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/ubuntu \
  $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

# Docker installieren
sudo apt-get update
sudo apt-get install docker-ce docker-ce-cli containerd.io

Im Anschluss sollte eine Abfrage der Version mit docker version ungefähr diese Ausgabe hervorbringen.

Client: Docker Engine - Community
 Version:           20.10.10
 API version:       1.41
 Go version:        go1.16.9
 Git commit:        b485636
 Built:             Mon Oct 25 07:42:59 2021
 OS/Arch:           linux/amd64
 Context:           default
 Experimental:      true

Server: Docker Engine - Community
 Engine:
  Version:          20.10.10
  API version:      1.41 (minimum version 1.12)
  Go version:       go1.16.9
  Git commit:       e2f740d
  Built:            Mon Oct 25 07:41:08 2021
  OS/Arch:          linux/amd64
  Experimental:     false
 containerd:
  Version:          1.4.11
  GitCommit:        5b46e404f6b9f661a205e28d59c982d3634148f8
 runc:
  Version:          1.0.2
  GitCommit:        v1.0.2-0-g52b36a2
 docker-init:
  Version:          0.19.0
  GitCommit:        de40ad0

Nun konfigurieren wir noch, dass in Docker systemd als cgroup Manager verwendet wird.

sudo mkdir /etc/docker
cat <<EOF | sudo tee /etc/docker/daemon.json
{
  "exec-opts": ["native.cgroupdriver=systemd"],
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "100m"
  },
  "storage-driver": "overlay2"
}
EOF

Und zum Schluss, aktivieren wir noch den automatischen Start der Docker Engine bei einem Systemneustart.

sudo systemctl enable docker
sudo systemctl daemon-reload
sudo systemctl restart docker

Kubeadm installieren

Damit kommen wir zur nächsten grundlegenden Entscheidung, mit welchem Tool wollen wir unseren Cluster erzeugen. Ich habe mich hier für kubeadm entschieden. Auch hier gibt es mehrere Alternativen (z.B. Kubespray siehe hier).

Bitte beachtet, dass bei der hier beschriebenen Vorgehensweise keine automatischen Updates von kubeadm, kubelet und kubectl durchgeführt werden. Die installierten Versionen werden “gesperrt”. Die Installation führen wir erneut auf allen unseren Kubernetes Hosts durch.

sudo apt-get update
sudo apt-get install -y apt-transport-https ca-certificates curl

# GPG Key und Repository hinzufügen
sudo curl -fsSLo /usr/share/keyrings/kubernetes-archive-keyring.gpg https://packages.cloud.google.com/apt/doc/apt-key.gpg
echo "deb [signed-by=/usr/share/keyrings/kubernetes-archive-keyring.gpg] https://apt.kubernetes.io/ kubernetes-xenial main" | sudo tee /etc/apt/sources.list.d/kubernetes.list

# kubelet, kubeadm und kubectl installieren und fixieren
sudo apt-get update
sudo apt-get install -y kubelet kubeadm kubectl
sudo apt-mark hold kubelet kubeadm kubectl

Snapshot: Nun ist ein guter Zeitpunkt um einen Snapshot zu erstellen.

Cluster mit Kubeadm erstellen

Die nächste Entscheidung steht an. Um den Cluster auf dem Control Node zu initialisieren, müssen wir uns für ein Network Plugin entscheiden. Über dieses Plugin läuft die Pod zu Pod Kommunikation von Kubernetes. Ich habe mich hier für Flannel entschieden. Eine detailierte Anleitung zur Initialisierung der Control Plane findet ihr hier. Für die Initialisierung des Clusters hat die Entscheidung für Flannel eine wichtige Auswirkung. Wir müssen bei dem Befehl kubeadm init den Parameter --pod-network-cidr=10.244.0.0/16 mit angeben. Dieser gibt den IP Adressbereich vor, der für unser Pod Netzwerk verwendet wird. Die Initialisierung führen wir nur auf unserem Control Host durch. Der Vorgang kann einige Minuten in Anspruch nehmen, da hier die benötigten Images aus dem Internet geladen werden.

kubeadm init --pod-network-cidr=10.244.0.0/16

Die Ausgabe sollte dann so aussehen:

Your Kubernetes control-plane has initialized successfully!

To start using your cluster, you need to run the following as a regular user:

  mkdir -p $HOME/.kube
  sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
  sudo chown $(id -u):$(id -g) $HOME/.kube/config

Alternatively, if you are the root user, you can run:

  export KUBECONFIG=/etc/kubernetes/admin.conf

You should now deploy a pod network to the cluster.
Run "kubectl apply -f [podnetwork].yaml" with one of the options listed at:
  https://kubernetes.io/docs/concepts/cluster-administration/addons/

Then you can join any number of worker nodes by running the following on each as root:

kubeadm join 192.168.2.115:6443 --token gc5iuc.g1rw2lcvcmhrkp2n \
        --discovery-token-ca-cert-hash sha256:9a5ed52e0427af8a300f33f68342852b68a6bf7a6d55f18a4b43ca069343cf2d

Unsere Control Plane ist jetzt fast fertig. Um mit kubectl unseren Control Node verwalten zu können, legen wir nun noch die kubeconfig in einen passenden Ordner für unseren Benutzer ab und verweisen darauf.

mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config

export KUBECONFIG=$HOME/.kube/config

Nun installieren wir noch das Pod Netzwerk Plugin Flannel.

kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml

Warning: policy/v1beta1 PodSecurityPolicy is deprecated in v1.21+, unavailable in v1.25+
podsecuritypolicy.policy/psp.flannel.unprivileged created
clusterrole.rbac.authorization.k8s.io/flannel created
clusterrolebinding.rbac.authorization.k8s.io/flannel created
serviceaccount/flannel created
configmap/kube-flannel-cfg created
daemonset.apps/kube-flannel-ds created

Nun wechseln wir (als root Benutzer) auf unsere Worker Nodes und führen das den Oben angegebenen Join Befehl aus. In meinem Beispiel also:

kubeadm join 192.168.2.115:6443 --token gc5iuc.g1rw2lcvcmhrkp2n \
        --discovery-token-ca-cert-hash sha256:9a5ed52e0427af8a300f33f68342852b68a6bf7a6d55f18a4b43ca069343cf2d

...
This node has joined the cluster:
* Certificate signing request was sent to apiserver and a response was received.
* The Kubelet was informed of the new secure connection details.

Run 'kubectl get nodes' on the control-plane to see this node join the cluster.

Hat alles geklappt, können wir nun unseren Cluster in voller Ausbaustufe betrachten und z.B. alle registrierten Nodes im Cluster abfragen.

kubectl get nodes

NAME          STATUS   ROLES                  AGE     VERSION
vmkubetst1m   Ready    control-plane,master   10m     v1.22.3
vmkubetst1w   Ready    <none>                 2m48s   v1.22.3
vmkubetst2w   Ready    <none>                 76s     v1.22.3

Wenn es bei euch genauso aussieht, wäre wieder ein guter Zeitpunkt für einen Snapshot aller eurer Cluster Knoten. In einem weiteren Beitrag sehen wir uns dann an, wie wir unseren eigenen “Cloud Loadbalancer” im Homelab bereitstellen, wie Storageklassen bereitgestellt werden, wie wir einen Ingress Controller installieren und über Let’s Encrypt mit einem gültigen Zertifikat versehen.

Philip

1 thought on “Ahoi – Kubernetes Cluster im Homelab aufbauen (1/2)”

  1. Pingback: Ahoi – Kubernetes Cluster im Homelab aufbauen (2/2) – The Database Me

Leave a Reply

Your email address will not be published. Required fields are marked *