Vanilla K8S mit Cilium auf Ubuntu 22.04 in Virtualbox

Moin. Heute bauen wir uns einen Kubernetes Cluster

Kubernetes Cluster in Virtualbox, ohne Scripte, und ohne Vagrant. Von Hand halt eben ;)

  • Level: Anfänger

  • Reqs: 8GB+ RAM, 100GB+ Disk

Ich entwickle auf Ubuntu 22.10, das ist jedoch weitestgehend irrelevant, es sei denn du benutzt Mac oder Windows. Dann musst du entsprechend PuTTY benutzen oder Binaries mit choco/brew installieren. Dieses Walkthrough ist nur für Ubuntu geschrieben. BTW: Ich habe mein Ubuntu auf Englisch eingestellt, daher sind Labels auch auf Englisch, das sollte dich aber nicht davon abhalten mir zu folgen.

Auf gehts! Vorbereitung und Virtualbox

Was du brauchst:

Nun erstellen wir unsere erste VM. Klicke in Virtualbox auf "New".

  • Name "K8S01" (oder dein eigenes Namensschema)

  • ISO Image: Die heruntergeladene Ubuntu Server ISO

  • Checkbox bei "Skip Unattended Installation" (hat bei mir schlichtweg nicht funktioniert und wir wollen es ja von Hand machen)

Auf Next klicken.

  • Base memory: Mein Rechner hat nur 16 GB, daher belasse ich es bei 2GB. Wir werden später diese VM 2x klonen und damit 6GB verbrauchen. Bleiben 10GB für Host OS, Browser, Spotify, etc...

  • Processors: Mit dem 2. rechnet man schneller

  • Enable EFI: Check. Warum nicht.

Next. Die Settings für die Platte belasse ich bei dynamischen 25GB. Wenn wir später persistente Volumes brauchen werden wir das anders lösen. (Weitere Volumes einhängen und mit hostPath volumes oder Rook benutzen)

Finish.

Nachdem die VM erstellt wurde editiere ich sie vor dem Start und mache noch ein paar Anpassungen:

  • System -> Motherboard -> Boot Order -> "Floppy" entfernen

  • System -> Processor -> Extended Features -> Alle aktivieren

  • Storage -> K8S01.vdi -> "Solid-state Drive" aktivieren

  • Audio -> Audio deaktivieren

  • Network -> Adapter 1 -> Enable + Bridged Adapter

Starten wir die VM. Das Setup ist recht straightforward. Ich installiere:

  • Step 1: Sprache: English

  • Step 2: Mit aktualisiertem Installer

  • Step 3: Kezboard Lazout: German / German (no dead keys)

  • Type: Ubuntu Server (minimized)

  • Network Connection: Keine Änderung (Notiere dir die IP Adresse!)

  • Proxy: Nö

  • Mirror: Nö

  • Storage Config: Passt so!

  • Storage Config: Ja, es passt wirklich!

  • Profile Setup: Selbstständig ausfüllen.

  • SSH Setup: OpenSSH Server installieren und PubKeys von GitHub importieren

  • Bloß keine Snaps installieren.

Dann startet die Installation. Wenn diese fertig ist starten wir die VM neu und schalten sie dann per ACPI aus, nur um sie danach im Headless Mode neu zu starten.

Den Headless Mode findest du in Virtualbox neben dem Start-Pfeil im Dropdown.

Warum Headless? Es ist natürlich einfacher alles per Copy-Paste in das eigene Terminal einzugeben als in ein VM-Fenster abzutippen ;)

Jetzt installieren wir mal die restlichen Updates und ein paar Basics (und ja, ich nutze nano!)

sudo apt update

sudo apt upgrade -y

sudo apt install -y nano less sed bash-completion

echo "export EDITOR=nano" >> $HOME/.bashrc

Da wir später enorm viel per sudo ausführen müssen stell ich auch gleich mal auf passwordless sudo um. Natürlich auf eigene Gefahr.

sudo sed -i $'s/%sudo\tALL=(ALL:ALL) ALL/%sudo\tALL=(ALL:ALL) NOPASSWD: ALL/' /etc/sudoers

Jetzt brauchen wir eine Container-Runtime. Ich habe mich für containerd entschieden. Ein gute Zusammenfassung für die notwendigen Schritte zur installation habe ich hier gefunden: https://www.nocentino.com/posts/2021-12-27-installing-and-configuring-containerd-as-a-kubernetes-container-runtime/

Ich fasse sie nochmal hier schnell zusammen:

sudo modprobe overlay

sudo modprobe br_netfilter

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

overlay

br_netfilter

EOF

cat <<EOF | sudo tee /etc/sysctl.d/99-kubernetes-cri.conf

net.bridge.bridge-nf-call-iptables = 1

net.ipv4.ip_forward = 1

net.bridge.bridge-nf-call-ip6tables = 1

EOF

sudo sysctl --system

sudo apt update

sudo apt install -y containerd

sudo mkdir -p /etc/containerd

sudo containerd config default | sudo tee /etc/containerd/config.toml

sudo sed -i 's/ SystemdCgroup = false/ SystemdCgroup = true/' /etc/containerd/config.toml

sudo systemctl restart containerd

Unsere Container Runtime ist bereit. Jetzt brauchen wir noch die Kubernetes Tools. Die Anleitung gibts von k8s frei Haus: https://kubernetes.io/docs/setup/production-environment/tools/kubeadm/install-kubeadm/#installing-kubeadm-kubelet-and-kubectl

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

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

sudo apt update

sudo apt install -y kubelet kubeadm kubectl

sudo apt-mark hold kubelet kubeadm kubectl

Kubernetes unterstützt seit 1.22 swap als alpha-feature, aber ich möchte es nicht drauf ankommen lassen. Daher deaktiviere ich Swap für jetzt und immer.

sudo swapoff -a

sudo sed -e '/\/swap/ s/^#*/#/' -i /etc/fstab

Alles klar. Jetzt müssen wir nur noch Kubernetes per kubeadm installieren, oder?

Ich habe Cilium genannt. Nach den Kubernetes Community Days 2022 war ich so davon begeistert, dass ich es einfach einsetzen musste. Grüße gehen raus :D

Ich installiere noch die Cilium und Hubble binaries, bevor wir die Maschinen klonen und K8S fertig aufsetzen. Die Befehle sind aus der offiziellen Doku.

CILIUM_CLI_VERSION=$(curl -s https://raw.githubusercontent.com/cilium/cilium-cli/master/stable.txt)

CLI_ARCH=amd64

if [ "$(uname -m)" = "aarch64" ]; then CLI_ARCH=arm64; fi

curl -L --fail --remote-name-all https://github.com/cilium/cilium-cli/releases/download/${CILIUM_CLI_VERSION}/cilium-linux-${CLI_ARCH}.tar.gz{,.sha256sum}

sha256sum --check cilium-linux-${CLI_ARCH}.tar.gz.sha256sum

sudo tar xzvfC cilium-linux-${CLI_ARCH}.tar.gz /usr/local/bin

rm cilium-linux-${CLI_ARCH}.tar.gz{,.sha256sum}

export HUBBLE_VERSION=$(curl -s https://raw.githubusercontent.com/cilium/hubble/master/stable.txt)

HUBBLE_ARCH=amd64

if [ "$(uname -m)" = "aarch64" ]; then HUBBLE_ARCH=arm64; fi

curl -L --fail --remote-name-all https://github.com/cilium/hubble/releases/download/$HUBBLE_VERSION/hubble-linux-${HUBBLE_ARCH}.tar.gz{,.sha256sum}

sha256sum --check hubble-linux-${HUBBLE_ARCH}.tar.gz.sha256sum

sudo tar xzvfC hubble-linux-${HUBBLE_ARCH}.tar.gz /usr/local/bin

rm hubble-linux-${HUBBLE_ARCH}.tar.gz{,.sha256sum}

Jetzt fahren wir die VM herunter (per sudo shutdown now oder ACPI shutdown) und erstellen einen Snapshot. (Wir können auch einen Live-Snapshot machen).

Dann klonen wir den Snapshot zwei mal und erstellen damit die Maschinen K8S02 und K8S03. Dabei weisen wir allen NICs neue MAC Adressen zu.

Die neuen Maschinen brauchen auch noch neue Hostnames. Dafür starten wir beide normal, loggen uns ein und führen auf der ersten aus:

sudo hostnamectl set-hostname k8s02

sudo sed -i 's/127.0.1.1 k8s01/127.0.1.1 k8s02/' /etc/hosts

Und auf der zweiten:

sudo hostnamectl set-hostname k8s03

sudo sed -i 's/127.0.1.1 k8s01/127.0.1.1 k8s03/' /etc/hosts

In meinem Fall hat meine Fritz!Box der geklonten Maschine die gleiche IP vergeben (muss wohl am hostname liegen). Leider reicht es nicht den Hostname zu ändern. Wenn die IP Adressen der geklonten bei dir auch gleich sind musst du nach dem Ändern des hostname beide Maschinen herunterfahren und dem Bridged Adapter eine neue Mac-Adresse zuweisen.

Fahre beide Klone danach wieder hoch und prüfe, dass die IPs nun unterschiedlich sind. Notiere sie, fahre die VMs herunter und starte alle wieder headless.

Auf der ersten Node K8S01 werde ich nun Kubernetes installieren, allerdings ohne kube-proxy, da wir diesen durch Cilium ersetzen.

sudo kubeadm init --skip-phases=addon/kube-proxy

Nach einiger Zeit bekommen wir den Output:

Ich kopiere mir wie angegeben die Kubeconfig in mein HOME-Verzeichnis.

mkdir -p $HOME/.kube

sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config

sudo chown $(id -u):$(id -g) $HOME/.kube/config

Nun kann ich mit dem kubectl auf der Node mit dem Cluster interagieren. Natürlich kann ich mir die config auch auf meinen Rechner kopieren und von dort aus mit kubectl agieren. Auf meinem Host erstelle ich das gleiche .kube Verzeichnis und lade die config herunter. Glücklicherweise heißt mein Benutzer auf der Node genauso wie auf dem Host. Wenn das bei dir anders ist musst du den Befehl anpassen.

mkdir -p $HOME/.kube

scp 192.168.188.88:/home/oeglseder/.kube/config $HOME/.kube/config

kubectl get nodes

Der letzte Befehl gibt nun aus, dass sich in meinem Cluster eine Node befindet und sie NotReady ist. Das liegt daran, dass wir noch kein Container Network haben.

Nun installieren wir Cilium. Die binary dafür haben wir schon heruntergeladen. BTW mit watch kubectl get pods -A -o wide können wir recht einfach verfolgen was passiert, während wir auch cilium warten. Hubble aktivieren wir noch nicht (aus Gründen).

cilium install

Jetzt joine ich mit den beiden anderen Nodes den Cluster. Dafür benutze ich den Befehl, den mir kubeadm init ausgespuckt hat.

kubeadm join 192.168.188.88:6443 --token birfuv.lxr89c04t2nf5dj1 --discovery-token-ca-cert-hash sha256:b0aca90ac92f5ebd8e0cde9f50cdda75daf81d20a09ac1825e29993a8d24668e

Danach können wir auch Hubble aktivieren

cilium hubble enable

Fertig. Viel Spaß mit deinem 3-Node Vanilla K8S Cluster mit Cilium und Hubble auf Ubuntu 22.04, in einer Virtualbox.