k0s #
Was ist k0s?
k0s ist eine leichtgewichtige, CNCF-zertifizierte Kubernetes-Distribution. k0s ist vollständig konform zur Kubernetes-API – alles, was Sie aus Standard-Kubernetes kennen, funktioniert auch hier.
Abweichungen zu kubeadm-basiertem Kubernetes
Der wichtigste Unterschied: k0s verwendet einen abweichenden kubelet-Pfad. Statt des üblichen /var/lib/kubelet nutzt k0s:
/var/lib/k0s/kubeletDas bedeutet: Wenn Sie DaemonSets, HostPath-Volumes oder andere Ressourcen einsetzen, die auf den kubelet-Pfad verweisen, müssen Sie diesen Pfad berücksichtigen.
Beispiel für ein HostPath-Volume:
volumes:
- name: kubelet-data hostPath: path: /var/lib/k0s/kubelet type: DirectoryCilium (CNI) #
Warum Cilium?
Cilium ist ein eBPF-basiertes Container Network Interface und ersetzt herkömmliche iptables-basierte Netzwerkstacks. Vorteile:
- Performant: eBPF arbeitet direkt im Linux-Kernel – schneller als iptables-basierte Lösungen
- Kein kube-proxy: Cilium übernimmt die Service-Proxy-Funktion nativ über eBPF
Was bedeutet „kein kube-proxy“?
In einigen Kubernetes-Clustern übernimmt kube-proxy die Weiterleitung von Service-Traffic. In Ihrem Cluster erledigt Cilium diese Aufgabe über eBPF – effizienter und mit geringerer Latenz.
Für Sie ändert sich nichts bei der Nutzung von Services – alle Kubernetes-Service-Typen (ClusterIP, NodePort, LoadBalancer) funktionieren wie gewohnt.
Cluster-Autoscaler #
Voraussetzungen für effektives Autoscaling
Der Cluster-Autoscaler skaliert auf Basis von nicht-schedulbaren Pods – er reagiert also auf Ressourcenengpässe, nicht auf Auslastung. Damit Autoscaling zuverlässig funktioniert, sollten folgende Voraussetzungen erfüllt sein:
- Horizontal Pod Autoscaler (HPA) nutzen: HPAs skalieren zuerst die Anzahl der Pods innerhalb der bestehenden Nodes. Erst wenn keine weiteren Pods geplant werden können, greift der Cluster-Autoscaler und fügt neue Nodes hinzu. HPAs sollten daher die erste Skalierungsebene sein.
- Ressourcen korrekt setzen: Jedes Pod benötigt definierte requests und limits für CPU und Memory. Ohne requests kann der Autoscaler nicht einschätzen, ob eine Node ausgelastet ist oder neue Nodes benötigt werden.
- TopologySpreadConstraints verwenden: Um Pods gleichmäßig auf Nodes zu verteilen, sollten topologySpreadConstraints gesetzt werden. Ohne diese Constraints kann es vorkommen, dass Pods auf einzelnen Nodes konzentriert werden, was Autoscaling-Entscheidungen verzerrt und die Ausfallsicherheit reduziert.
Verhalten bei Min/Max Scaling
Der Cluster-Autoscaler überwacht die Ressourcenauslastung Ihres Clusters und passt die Anzahl der Worker Nodes automatisch an:
| Situation | Verhalten |
|---|---|
| Pods pending wegen Ressourcenmangel | Neue Worker Nodes werden hinzugefügt (bis max erreicht ist) |
| Nodes werden nicht ausgelastet | Überflüssige Nodes werden entfernt (bis min erreicht ist) |
Wie schnell skaliert der Cluster?
Das Hochskalieren (neue Worker Nodes hinzufügen) dauert in der Regel wenige Minuten, bis die neuen Nodes bereit sind. Das Herunterskalieren erfolgt bewusst verzögert und träger als das Hochskalieren, um zu vermeiden, dass Nodes zu früh entfernt werden und Pods neu platziert werden müssen.
Version Upgrades #
Version-Upgrades werden automatisch durch uns durchgeführt. Sie müssen nicht eingreifen – weder manuell upgraden noch Cluster-Konfigurationen anpassen.
Empfohlene Einstellungen für Hochverfügbarkeit #
Stateless Multi-Replica oder Application-Level HA
Für hochverfügbare Anwendungen empfehlen wir:
- Stateless Workloads: Mindestens 2 Replicas deployen – so bleibt die Anwendung verfügbar, wenn ein Pod oder eine Node ausfällt
- Stateful Workloads: Application-Level HA einsetzen (z.B. Datenbank-Replikation) – ein einzelner Pod auf einer Node bietet keinen Ausfallschutz
PodDisruptionBudget (PDB)
Ein PDB stellt sicher, dass bei geplanten Wartungsarbeiten (z.B. Node-Drain) immer eine Mindestanzahl an Pods verfügbar bleibt:
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata: name: example-app-pdb namespace: example-namespace
spec: minAvailable: 1 selector: matchLabels: app: example-app
TopologySpreadConstraints oder Node Anti-Affinity
Um Pods auf verschiedene Nodes zu verteilen, stehen zwei Mechanismen zur Verfügung:
Pod Anti-Affinity:
spec: affinity: podAntiAffinity: preferredDuringSchedulingIgnoredDuringExecution: - weight: 100 podAffinityTerm: labelSelector: matchLabels: app: example-app topologyKey: kubernetes.io/hostnameTopologySpreadConstraints – präzisere Kontrolle über die Verteilung:
spec: topologySpreadConstraints: - maxSkew: 1 topologyKey: kubernetes.io/hostname whenUnsatisfiable: DoNotSchedule labelSelector: matchLabels: app: example-appWorker Gruppen mit Labels #
Jede Worker Gruppe erhält automatisch ein Label basierend auf ihrem Namen:
k8s.at/node-group: <worker-gruppen-name>Mit diesem Label können Sie Workloads gezielt auf bestimmten Worker Gruppen platzieren:
spec: nodeSelector: k8s.at/node-group: memory-optimizedNode Failure #
Automatische Node-Ersetzung (Node Reconciliation)
Wenn eine Worker Node ausfällt, wird diese automatisch erkannt und durch eine neue Node ersetzt. Sie müssen nicht manuell eingreifen.
Ephemeral Storage geht verloren
Wichtig: Bei einem Node-Ausfall geht aller lokaler Speicher (ephemeral storage) auf dieser Node unwiderruflich verloren. Das betrifft:
- EmptyDir-Volumes
- HostPath-Volumes
- Container-Dateisystem (nicht in Persistent Volumes gespeicherte Daten)
Für persistente Daten verwenden Sie bitte Persistent Volume Claims (siehe Storage).
Long-lived Kubeconfig #
Wir empfehlen kurzlebige Tokens zu verwenden, welche über das Control Center erstellt werden können. Diese laufen automatisch ab und reduzieren das Risiko.
Sollte dennoch eine langlebige Kubeconfig notwendig sein, kann ein ServiceAccount mit dauerhaftem Token manuell erstellt werden:
# ServiceAccount erstellen
kubectl create serviceaccount long-lived-admin -n kube-system
# ClusterRoleBinding mit cluster-admin erstellen
kubectl create clusterrolebinding long-lived-admin \ --clusterrole=cluster-admin \ --serviceaccount=kube-system:long-lived-admin
# Secret für den ServiceAccount erstellen
kubectl apply -f - <<EOF
apiVersion: v1
kind: Secret
metadata: name: long-lived-admin-token namespace: kube-system annotations: kubernetes.io/service-account.name: long-lived-admin
type: kubernetes.io/service-account-token
EOF
# Token auslesen
kubectl get secret long-lived-admin-token -n kube-system -o jsonpath='{.data.token}' | base64 -dDieser Token kann anschließend den kurzlebigen Token der aus dem Control Center heruntergeladenen Kubeconfig ersetzen.
Hinweis: Dieser Token verfällt nicht automatisch. Stellen Sie sicher, dass er sicher aufbewahrt und bei Bedarf (z.B. Mitarbeiterwechsel) manuell widerrufen wird:
kubectl delete secret long-lived-admin-token -n kube-system
kubectl delete clusterrolebinding long-lived-admin
kubectl delete serviceaccount long-lived-admin -n kube-system