Cheatsheet im Volltext
Derselbe Inhalt wie im PDF, zum Mitlesen, Durchsuchen und direkten Kopieren der YAML-Snippets. Stand: RKE2 v1.37 (Edition 2026.11).
Architektur
Ein Binary, zwei Rollen
rke2-server / rke2-agent: je
eine systemd-Unit, ein statisch gelinktes Binary. Der
Supervisor startet und überwacht die eigene
containerd-Instanz, das kubelet und,
auf Servern, die Control-Plane als
statische Pods.
Kein Docker: eigenes containerd unter
/run/k3s/containerd, Socket containerd.sock.
Server-Node
embedded etcd: Default-Datastore (Raft), Quorum über ungerade Server-Zahl.
Control-Plane als static Pods: apiserver,
controller-manager, scheduler, etcd, cloud-controller, Manifeste in /var/lib/rancher/rke2/agent/pod-manifests,
vom kubelet gestartet (nicht in-process wie k3s). kube-proxy
läuft als static Pod auf allen Nodes.
Externer CCM (Hetzner, AWS, OpenStack …):
cloud-provider-name: external plus
disable-cloud-controller: true auf allen Servern. v1.36.0
bis v1.36.5, v1.37.0 und v1.37.1 starten sonst trotz
external den eingebauten CCM.
CNI & Netzwerk
Default Canal (Calico-Policy + Flannel-VXLAN).
Alternativen per cni:: Cilium,
Calico, Flannel (ohne
NetworkPolicy). Multus ist nur Meta-Plugin für
Multi-NIC, immer an erster Stelle neben einem primären CNI:
cni: [multus, canal].
Ingress per ingress-controller:
(traefik | none), Traefik ist seit 1.36
Default für neue Cluster. Ab 1.37 bricht ein explizites
ingress-controller: ingress-nginx allein den Start ab,
nginx ist nur noch im Dual-Betrieb mit Traefik wählbar
(Migration). Upgegradete Cluster ohne gesetzten Wert erkennen nginx
am vorhandenen Chart und behalten es (Community-Image
v1.14.5-hardened2; laut ADR-Entwurf ohne weitere
Updates, Chart entfällt in 1.38). Vor dem 1.37-Upgrade trotzdem
explizit [ingress-nginx, traefik] setzen, Traefik dabei
auf Ausweich-Ports (Migrationsdoku, Phase 1). traefik
allein entfernt nginx.
Dazu CoreDNS, metrics-server, snapshot-controller, ab 1.37
rke2-gateway-api-crd (Gateway API v1.6) und
rke2-security-responder, alle als HelmChart-CRs.
export KUBECONFIG=/etc/rancher/rke2/rke2.yaml export PATH=$PATH:/var/lib/rancher/rke2/bin kubectl get nodes -o wide systemctl status rke2-server
Installation
Server aufsetzen
Installer zieht Binary + systemd-Unit, startet aber nicht selbst:
curl -sfL https://get.rke2.io | sh -, dann
systemctl enable --now rke2-server.
Agent: INSTALL_RKE2_TYPE=agent vor dem Installer,
dann rke2-agent aktivieren.
Wichtige Pfade
Config: /etc/rancher/rke2/config.yaml.
kubeconfig: /etc/rancher/rke2/rke2.yaml.
Binaries (kubectl, crictl, ctr):
/var/lib/rancher/rke2/bin.
Node-Token: /var/lib/rancher/rke2/server/node-token.
Server-Token (ins Backup): /var/lib/rancher/rke2/server/token.
Host vorbereiten
firewalld aus. Mit NetworkManager die CNI-Interfaces
(flannel*, cali* …) per
/etc/NetworkManager/conf.d/rke2-canal.conf als
unmanaged-devices eintragen, nm-cloud-setup
aus.
# /etc/rancher/rke2/config.yaml (erster Server) token: <shared-secret> tls-san: - rke2.example.com # LB / VIP-Hostname - 10.0.0.10 write-kubeconfig-mode: "0640" cni: canal ingress-controller: traefik # oder none node-taint: - "CriticalAddonsOnly=true:NoExecute" disable: - rke2-security-responder
HA Control-Plane
Quorum & Registration
Ungerade Server-Zahl (3 oder 5) für
etcd-Quorum. Feste Registration-Address (LB/VIP)
vor allen Servern, muss in tls-san stehen,
sonst x509-Fehler über den LB.
Der erste Server bootstrappt (kein
server:-Feld), weitere joinen über
server: + gleichen token.
Der LB leitet 9345 und 6443 (TCP) weiter. Kritische
Werte (cluster-cidr, service-cidr,
agent-token, disable-cloud-controller
…) auf allen Servern gleich.
Ports
9345: RKE2 Supervisor/Registration (nicht
6443!), darauf zeigt server:.
6443: kube-apiserver.
2379/2380/2381: etcd client/peer/metrics (nur
Server). 10250: kubelet (alle Nodes).
8472/UDP: VXLAN (Canal, Cilium), Canal-Health
9099.
# config.yaml (zweiter/dritter Server) server: https://rke2.example.com:9345 token: <shared-secret> tls-san: - rke2.example.com # Taint greift nur beim Join, disable je Server: node-taint: - "CriticalAddonsOnly=true:NoExecute" disable: - rke2-security-responder
Bundled Components
Auto-Deploy aus manifests/
Alles in
/var/lib/rancher/rke2/server/manifests/ wird vom
Deploy-Controller angewandt (HelmChart-CRs: rke2-canal,
rke2-coredns, rke2-traefik, rke2-metrics-server).
Nicht direkt editieren, beim Restart
überschrieben.
Anpassen & Abschalten
Customizing über HelmChartConfig-CR
(gleicher Name/Namespace, valuesContent wird gemergt).
Abschalten über disable: in der config.yaml,
gültig u.a. rke2-coredns,
rke2-metrics-server, rke2-security-responder,
rke2-gateway-api-crd. Ingress nicht per
disable:, sondern ingress-controller: none.
Das Gateway-API-CRD-Chart bringt die VAP
safe-upgrades.gateway.networking.k8s.io
(Deny) mit. Sie lehnt Gateway-API-CRDs ohne
bundle-version-Annotation oder älter als v1.6 ab,
ebenso Experimental- über Standard-CRDs: ältere oder
Experimental-Manifeste aus Istio- oder Cilium-Anleitungen scheitern.
experimental: {enabled: true} per HelmChartConfig
ergänzt nur die x-k8s.io-CRDs (XBackend,
XBackendTrafficPolicy, XMesh).
apiVersion: helm.cattle.io/v1
kind: HelmChartConfig
metadata:
name: rke2-traefik
namespace: kube-system
spec:
valuesContent: |-
ports:
web:
forwardedHeaders:
trustedIPs: ["10.0.0.0/8"]
websecure:
forwardedHeaders:
trustedIPs: ["10.0.0.0/8"]
accessLog: {enabled: true} # bis 1.36: logs.access
Security & Hardening
CIS-Profil
profile: cis in der config.yaml aktiviert die
CIS-Benchmark-Härtung: PSA restricted als Default
(außer kube-system,
compliance-operator-system, tigera-operator),
strenge Datei-Rechte, NetworkPolicies nur in kube-system,
kube-public, default. Für eigene
Namespaces Policies selbst anlegen und darin den Ingress-Controller
zulassen.
Self-Assessment: CIS 2.0 für 1.35 bis 1.37, CIS 1.12 für
1.34.
Host-Prereqs: etcd-User
(useradd -r -M -U -s /sbin/nologin etcd) und
rke2-cis-sysctl.conf (/usr/share/rke2/ bei
RPM, /usr/local/share/rke2/ bei Tarball) nach
/etc/sysctl.d/60-rke2-cis.conf kopieren: RKE2 legt die
Datei ab, aktiviert sie aber nicht. profile setzt
protect-kernel-defaults: true: fehlen die Sysctls,
beendet sich RKE2 beim Start mit Fehler. systemd-sysctl
nur auf frischen Nodes neu starten (CNIs setzen eigene Sysctls).
Weitere Defaults
Secrets-Encryption at rest: standardmäßig
an (AES-CBC, alternativ
secrets-encryption-provider: secretbox), verwaltet via
rke2 secrets-encrypt.
SELinux: unterstützt
(selinux: true + rke2-selinux Policy).
Security Responder (ab 1.37, Default
an): CronJob rke2-security-responder in
kube-system, alle 8h. Sendet Cluster-Metadaten
(K8s-Version, kube-system-UID, OS/Kernel, CNI, Ingress,
Node-Zahlen) an SUSE (security-responder.version.rke2.io,
HTTPS), meldet CVEs der laufenden Version. Ohne Egress scheitert der
Lauf folgenlos für den Cluster, nichts wird gepuffert.
Reduzieren: mode: minimal per HelmChartConfig. Kein
Datenabfluss: disable: [rke2-security-responder].
rke2 secrets-encrypt status rke2 secrets-encrypt rotate-keys # Key-Rotation # HA: reencrypt_finished abwarten, dann Neustarts kubectl get --raw='/readyz?verbose'
Zertifikate & Tokens
Node-Zertifikate gelten 365 Tage und werden nur
beim Start erneuert, wenn sie unter 120 Tage
Restlaufzeit haben (Event CertificateExpirationWarning).
Ein Node ohne Neustart über ein Jahr läuft in abgelaufene
Zertifikate. CAs gelten 10 Jahre, ohne Auto-Renew
(rke2 certificate rotate-ca).
Agents per eigenem agent-token joinen lassen. Nach
token rotate alle Nodes mit dem neuen Token neu
starten.
rke2 certificate check --output table systemctl stop rke2-server rke2 certificate rotate systemctl start rke2-server rke2 token rotate --token <alt> --new-token <neu>
etcd Snapshot / Restore
Snapshots
Automatisch an by default:
etcd-snapshot-schedule-cron (Default alle 12h),
etcd-snapshot-retention (Default 5, je Server-Node).
Ablage: /var/lib/rancher/rke2/server/db/snapshots.
Off-node nach S3 sichern, sonst ist der Snapshot
mit dem Node verloren. etcd-s3-retention (Default 5)
zählt clusterweit je Bucket/Ordner. Alle Snapshots im Cluster:
kubectl get etcdsnapshotfile.
# config.yaml (alle Server): Snapshots nach S3 etcd-s3: true etcd-s3-endpoint: s3.example.com etcd-s3-bucket: rke2-snapshots etcd-s3-access-key: <key> etcd-s3-secret-key: <secret>
rke2 etcd-snapshot save --name pre-upgrade rke2 etcd-snapshot ls # Restore (auf EINEM Server, andere vorher stoppen): systemctl stop rke2-server rke2 server \ --cluster-reset \ --cluster-reset-restore-path=/var/lib/rancher/rke2/server/db/snapshots/pre-upgrade-<node>-<ts> systemctl start rke2-server
Restore-Ablauf
Restore läuft auf einem Server, alle anderen
Server werden gestoppt und ihr db/-Verzeichnis
geleert; danach re-joinen sie den zurückgesetzten Cluster
über server: + token.
Mit etcd-s3 in der Config nur den Dateinamen angeben,
für lokale Snapshots --etcd-s3=false setzen. Ohne
den ursprünglichen token kein Restore:
server/token sichern, auf neuem Host mit
--token=<Wert> starten.
Quorum verloren (2 von 3 Servern weg):
--cluster-reset ohne Restore-Pfad auf dem
verbliebenen Server setzt etcd auf dieses Mitglied zurück, ohne
Snapshot. Übrige Server danach leeren und neu joinen.
Upgrades
Zwei Wege
system-upgrade-controller (SUSE-Pattern):
deklarative Plan-CRs, node-selektiert, Server zuerst,
dann Agents.
Manuell: INSTALL_RKE2_VERSION
setzen, Installer erneut laufen lassen, rke2-server
neustarten.
Channels: INSTALL_RKE2_CHANNEL
(stable | latest | v1.37). Default stable
ist ein manuell gesetzter Pin und hängt hinter
latest zurück (bei Redaktionsschluss v1.36.5, nicht
1.37).
Keine Minor überspringen: Ein Plan mit
channel: springt direkt auf den Channel-Stand, auch
über mehrere Minors, der Controller prüft das nicht.
Rollback auf die alte Minor geht nur per Restore eines Snapshots, der
auf dieser Minor erstellt wurde.
Agents: zweiter Plan mit prepare: {image:
rancher/rke2-upgrade, args: [prepare, server-plan]}.
RPM-Installation per Paketmanager aktualisieren, Rancher-verwaltete
Cluster über Rancher.
apiVersion: upgrade.cattle.io/v1
kind: Plan
metadata: {name: server-plan, namespace: system-upgrade}
spec:
concurrency: 1
nodeSelector:
matchExpressions:
- {key: node-role.kubernetes.io/control-plane, operator: Exists}
tolerations: # sonst nie auf getainteten Servern
- {key: CriticalAddonsOnly, operator: Exists}
serviceAccountName: system-upgrade
cordon: true
upgrade: {image: rancher/rke2-upgrade}
version: v1.37.1+rke2r1
Air-Gap
Images & Binary
Images-Tarball
(rke2-images.linux-amd64.tar.zst = Core + Canal) nach
/var/lib/rancher/rke2/agent/images/ legen, RKE2
importiert ihn beim Start in containerd. Andere CNIs:
rke2-images-core plus CNI-Bundle
(rke2-images-cilium, -calico,
-flannel), Multus zusätzlich
-multus.
Binary + install.sh offline via
INSTALL_RKE2_ARTIFACT_PATH.
Seit 1.36 enthält rke2-images-core Traefik statt
nginx. Wer nginx weiter betreibt, spiegelt zusätzlich
rke2-images-ingress-nginx.
touch agent/images/.cache.json: Re-Import nur noch bei
geänderter Datei. Für Upgrades per Plan zusätzlich
rancher/rke2-upgrade,
rancher/system-upgrade-controller und
rancher/kubectl spiegeln.
Private Registry
/etc/rancher/rke2/registries.yaml: Mirror-Endpunkte
+ Auth + TLS, auf jedem Node, wirksam nach Neustart, für
System-Images und Workloads. Kein Rückfall auf den
Upstream bei gespiegelten Registries (je Node):
disable-default-registry-endpoint: true.
# /etc/rancher/rke2/registries.yaml
mirrors:
docker.io:
endpoint:
- "https://registry.internal:5000"
configs:
registry.internal:5000:
auth: {username: robot, password: <token>}
tls: {ca_file: /etc/ssl/registry-ca.pem}
Diagnose
Werkzeuge
journalctl -u rke2-server -f (bzw.
rke2-agent). crictl unter
/var/lib/rancher/rke2/bin, Container/Images
direkt am Node (containerd, nicht Docker). Static-Pod-Logs:
crictl logs oder /var/log/pods.
kubelet und containerd loggen nicht ins Journal:
agent/logs/kubelet.log,
agent/containerd/containerd.log unter
/var/lib/rancher/rke2/.
export CRI_CONFIG_FILE=/var/lib/rancher/rke2/agent/etc/crictl.yaml /var/lib/rancher/rke2/bin/crictl ps /var/lib/rancher/rke2/bin/crictl logs <container-id> journalctl -u rke2-server --no-pager | tail -50
Reset & Removal
rke2-killall.sh: stoppt alle rke2-Prozesse +
Container, lässt Daten liegen.
rke2-uninstall.sh: vollständige Entfernung
(Binaries, Daten, Unit).
Gleichnamigen Node neu aufsetzen: erst kubectl delete
node, sonst scheitert der Join am alten Node-Passwort.
Anti-Patterns
Was du nicht tun solltest
Gerade Server-Zahl (2/4): 4 Server verkraften wie 3 nur einen Ausfall, bieten aber mehr Ausfallpunkte. Bei einer 2/2-Partition hat keine Seite Quorum. Immer 3 oder 5.
Snapshots nur on-node: Node-Verlust = etcd-Verlust. S3 konfigurieren.
Docker erwarten: RKE2 hat ein eigenes
containerd; kein Docker-Socket, kein docker ps. Nutze
crictl.
tls-san vergessen: API-Zertifikat kennt den LB/VIP-Namen nicht, x509-Fehler, sobald kubectl über den LB geht.
Server als Worker ohne Taint in Prod:
Workloads konkurrieren mit etcd/Control-Plane,
CriticalAddonsOnly-Taint setzen.
Alle Nodes getaintet: Ingress, metrics-server bleiben Pending.
manifests/ direkt editieren: beim Restart
überschrieben, HelmChartConfig statt
Datei-Patch.
Projekt und Quellen
Upstream
SUSE entwickelt RKE2 im Rancher-Projekt auf GitHub, Lizenz Apache 2.0.
Code: github.com/rancher/rke2 · Releases · Advisories. Doku: docs.rke2.io · Release Notes: docs.rke2.io/release-notes/v1.37.X. Release- und EOL-Daten: rke2-cheatsheet.de/lifecycle.