K3s im Produktiveinsatz: Erfahrungsbericht nach zwei Jahren
Zurück zum Blog

K3s im Produktiveinsatz: Erfahrungsbericht nach zwei Jahren

6 Min. Lesezeit
Lesen auf English

Von der Evaluation zum Produktiveinsatz

Im April 2019 haben wir K3s zum ersten Mal installiert und waren beeindruckt davon, wie schnell man ein funktionierendes Kubernetes-Cluster auf die Beine stellen konnte. Wie wir in unserem K3s-Einführungsartikel beschrieben haben, war die Distribution damals noch jung, die Dokumentation dünn und Hochverfügbarkeit offiziell nicht unterstützt. Unsere Einschätzung damals: hervorragend für Entwicklung und CI, für Produktion noch zu früh.

Zwei Jahre später sieht die Lage anders aus. K3s ist in Version 1.21 angekommen, wurde von SUSE übernommen (die Rancher Labs Anfang 2020 akquiriert haben), ist ein CNCF-Sandbox-Projekt und hat sich als zertifizierte Kubernetes-Distribution einen soliden Ruf erarbeitet. Und wir betreiben mittlerweile mehrere produktive Workloads darauf -- auf Nodes, die für ein vollständiges Kubernetes zu klein wären.

Dieser Beitrag beschreibt, was wir in diesen zwei Jahren gelernt haben. Nicht als Wiederholung der offiziellen Dokumentation, sondern als ehrlicher Bericht aus dem Alltag.

Warum nicht einfach vollständiges Kubernetes?

Die kurze Antwort: weil es für bestimmte Workloads schlicht überdimensioniert ist. Nicht jeder Dienst braucht ein HA-Cluster mit drei etcd-Nodes, separatem Control Plane und Worker-Pool. Wir betreiben eine Reihe interner Tools und kleinerer Kundenprojekte, die zuverlässig laufen müssen, aber weder Traffic-Spitzen noch horizontale Skalierung über Dutzende Pods erfordern.

Für diese Workloads haben wir K3s gewählt, und zwar bewusst. Die Argumente, die uns überzeugt haben:

Ressourcenverbrauch. Ein vollständiger K8s-Control-Plane mit etcd belegt auf einem kleinen VPS schon im Leerlauf 1,5 bis 2 GB RAM. K3s kommt mit 400 bis 500 MB aus. Auf Nodes mit 4 GB RAM macht das den Unterschied zwischen "passt nichts mehr drauf" und "drei bis vier Services laufen komfortabel".

Betriebskomplexität. K3s ist eine einzelne Binary unter 70 MB. Kein etcd-Cluster, das man separat pflegen muss. Kein komplexes Zertifikats-Bootstrapping. Kein Zusammenspiel von fünf separaten Systemd-Services. Das reduziert die Angriffsfläche für Fehler erheblich -- besonders wenn man, wie wir, die Infrastruktur mit einem kleinen Team betreut.

Volle Kompatibilität. K3s ist zertifiziertes Kubernetes. Unsere Helm Charts, Manifeste und CI/CD-Pipelines funktionieren identisch. Kein Vendor Lock-in, kein proprietäres API. Wenn ein Workload wächst und ein vollständiges Cluster braucht, migrieren wir -- ohne die Deployments umzuschreiben.

NixOS als Host-Betriebssystem

Eine Entscheidung, die wir nicht bereut haben: Unsere K3s-Nodes laufen auf NixOS. Das klingt nach einer ungewöhnlichen Kombination, passt aber hervorragend zusammen.

NixOS bringt deklarative Systemkonfiguration mit. Der gesamte Zustand eines Nodes -- installierte Pakete, Systemd-Services, Firewall-Regeln, Kernel-Parameter -- ist in einer einzigen Nix-Konfigurationsdatei definiert und versioniert. Wenn wir einen Node neu aufsetzen müssen, deployen wir die Konfiguration und haben nach wenigen Minuten einen identischen Zustand. Kein Ansible, kein manuelles Nachkonfigurieren.

K3s selbst installieren wir nicht über das offizielle Install-Skript, sondern als NixOS-Service. Die Konfiguration ist dadurch reproduzierbar und rollback-fähig -- wenn ein Upgrade Probleme macht, schalten wir auf die vorherige NixOS-Generation zurück. Das gibt uns ein Sicherheitsnetz, das wir bei konventionellen Linux-Distributionen so nicht hätten.

SQLite vs etcd: Die Datenspeicher-Frage

K3s nutzt standardmäßig SQLite als Datastore für den Cluster-Zustand. Das war 2019 einer der Punkte, die uns für den Produktiveinsatz zögern ließen. Zwei Jahre später können wir sagen: Für Single-Server-Setups funktioniert SQLite einwandfrei.

Die Bedenken, die man häufig hört -- SQLite sei nicht für Concurrent Writes ausgelegt, die Performance breche bei größeren Clustern ein -- sind berechtigt, aber treffen auf unsere Szenarien nicht zu. Wir betreiben Single-Server-Nodes mit 15 bis 30 Pods. Die Schreiblast auf den Datastore ist dabei minimal. In über zwei Jahren hatten wir keinen einzigen Ausfall, der auf SQLite zurückzuführen war.

Wo wir etcd empfehlen würden: bei Multi-Server-HA-Setups, die K3s seit Version 1.19 offiziell unterstützt. Oder bei Clustern mit mehr als 50 Nodes, wo die Schreiblast tatsächlich relevant wird. Für alles darunter ist SQLite die einfachere Wahl -- weniger bewegliche Teile, weniger Wartungsaufwand.

Traefik als gebündelter Ingress

K3s bringt Traefik als Ingress Controller mit. In Version 1.21 ist das Traefik v1, was mittlerweile etwas in die Jahre gekommen ist. Für unsere Zwecke funktioniert es aber zuverlässig: TLS-Terminierung mit Let's Encrypt, automatische Zertifikatserneuerung, saubere Ingress-Konfiguration über Standard-Kubernetes-Ressourcen.

Wer Traefik v2 oder einen anderen Ingress Controller wie nginx-ingress bevorzugt, kann den gebündelten Traefik beim Start deaktivieren:

curl -sfL https://get.k3s.io | INSTALL_K3S_EXEC="--disable traefik" sh -

Danach installiert man den gewünschten Controller per Helm wie in jedem anderen Kubernetes-Cluster. Wir haben das auf einem unserer Nodes gemacht und sind mit Traefik v2 zufrieden. Auf den anderen Nodes läuft der mitgelieferte Traefik v1 problemlos weiter. Sobald K3s auf Traefik v2 als Standard umstellt, werden wir die manuell installierten Instanzen wieder durch die gebündelte Version ersetzen.

Upgrades: Pragmatisch statt elegant

Upgrades waren anfangs der Punkt, der uns am meisten Sorgen gemacht hat. Bei einem vollständigen Kubernetes-Cluster mit kubeadm gibt es einen definierten Upgrade-Pfad mit kubeadm upgrade plan und kubeadm upgrade apply. Bei K3s ist der Ansatz deutlich simpler -- und das ist Absicht.

Ein K3s-Upgrade auf einem einzelnen Node sieht so aus:

# Aktuelle Version prüfen
k3s --version

# Upgrade auf eine neue Version via Install-Skript
curl -sfL https://get.k3s.io | INSTALL_K3S_CHANNEL=v1.21 sh -

# Node-Status prüfen
sudo kubectl get nodes

Das Install-Skript erkennt eine bestehende Installation und führt ein In-Place-Upgrade durch. Der K3s-Prozess wird neu gestartet, die laufenden Pods werden kurz unterbrochen und kommen danach wieder hoch. Bei uns dauert das typischerweise 30 bis 60 Sekunden Downtime.

Auf unseren NixOS-Nodes ist der Prozess noch einfacher: Wir aktualisieren die K3s-Version in der Nix-Konfiguration und deployen mit nixos-rebuild switch. Danach prüfen wir den Zustand:

# Kubeconfig setzen
export KUBECONFIG=/etc/rancher/k3s/k3s.yaml

# Cluster-Status verifizieren
sudo kubectl get nodes -o wide

# Alle Pods prüfen
sudo kubectl get pods --all-namespaces

Für Dienste, die keine Downtime vertragen, fahren wir den Workload vorher auf einen zweiten Node um. Aber ehrlich gesagt: Die meisten unserer K3s-Workloads vertragen 60 Sekunden Unterbrechung problemlos. Das klingt nach einem Kompromiss, und das ist es auch. Aber es ist ein bewusster Kompromiss, der den operativen Aufwand drastisch reduziert.

Ressourceneinsparung in der Praxis

Die konkrete Ersparnis hängt vom Szenario ab, aber hier sind die Zahlen von einem unserer Nodes -- ein VPS mit 4 GB RAM und 2 vCPUs:

Mit K3s (aktuell): K3s-Prozess belegt ca. 450 MB RAM. Traefik, CoreDNS und local-path-provisioner zusammen nochmal ca. 100 MB. Bleiben gut 3,4 GB für Workloads. Darauf laufen bei uns vier Services produktiv.

Geschätzt mit vollem K8s: etcd allein hätte 500 bis 800 MB belegt, dazu kube-apiserver, kube-scheduler, kube-controller-manager und kubelet separat. Realistisch wären 1,5 bis 2 GB für die Control Plane weggegangen. Auf einem 4-GB-Node hätte das für maximal einen bis zwei Services gereicht.

Der Unterschied ist nicht akademisch. Er bestimmt, ob man für einen kleinen Dienst einen 4-Euro-VPS nehmen kann oder einen 15-Euro-VPS braucht. Bei zehn solcher Nodes summiert sich das.

Was wir heute anders machen würden

Nicht alles lief von Anfang an rund. Ein paar Lektionen, die wir gerne früher gehabt hätten:

Backup des Datastores. SQLite ist eine einzelne Datei. Wir sichern sie mittlerweile täglich per Cronjob. In den ersten Monaten haben wir das nicht gemacht -- fahrlässig, im Nachhinein betrachtet.

# SQLite-Datastore sichern
sudo cp /var/lib/rancher/k3s/server/db/state.db /backup/k3s-state-$(date +%Y%m%d).db

Kein Mischen von K3s und klassischem K8s in derselben CI/CD-Pipeline ohne Tests. K3s ist kompatibel, aber es gibt Randfälle -- etwa bei bestimmten Admission-Webhook-Konfigurationen oder wenn man Cloud-Provider-spezifische Features nutzt, die K3s bewusst entfernt hat. Wir testen Helm Charts mittlerweile gegen beide Varianten.

Flannel-Netzwerk nicht unterschätzen. K3s nutzt Flannel mit VXLAN als Standard-CNI. Für die meisten Szenarien funktioniert das. Aber wer Network Policies braucht, muss Calico oder ein anderes CNI nachinstallieren. Flannel allein unterstützt keine Network Policies -- ein Punkt, den man bei der Planung berücksichtigen sollte.

Fazit

K3s hat sich in zwei Jahren vom vielversprechenden Experiment zur soliden Produktionslösung entwickelt. Nicht für jedes Szenario -- wer ein großes, hochverfügbares Cluster mit komplexen Netzwerk-Policies und Multi-Tenancy braucht, ist mit einem vollständigen Kubernetes besser bedient. Aber für die vielen Fälle, in denen ein oder zwei Nodes mit einer Handvoll Services ausreichen, ist K3s die pragmatischere Wahl.

Die Kombination mit NixOS als Host-Betriebssystem hat sich für uns als besonders wertvoll erwiesen. Deklarative Konfiguration auf OS-Ebene, darauf ein leichtgewichtiges Kubernetes, darauf Standard-Helm-Charts -- das ergibt einen Stack, der mit wenig Aufwand betrieben werden kann und trotzdem die volle Kubernetes-API bietet.

Wer K3s heute evaluiert, findet eine deutlich reifere Distribution vor als das, was wir 2019 getestet haben. Die HA-Unterstützung ist da, die CNCF-Zertifizierung ist da, die Community ist gewachsen. Der beste Einstieg ist immer noch derselbe: ein Linux-System, ein Befehl, dreißig Sekunden Geduld. Nur dass man das Ergebnis heute auch guten Gewissens produktiv betreiben kann.

Teilen

Patrick Hütter

Geschrieben von

Patrick Hütter

Gründer & Software-Architekt

Softwarearchitekt, Ingenieur und Unternehmer. Patrick baut seit über einem Jahrzehnt Produkte und Plattformen — von Enterprise-Backends über Cloud-Native-Infrastruktur bis hin zu KI-gestützten Anwendungen. Als Gründer von encircle360 verbindet er technische Tiefe mit unternehmerischem Denken und treibt Open-Source-Projekte voran, die echten Impact haben.