← Übersicht  ·  Skripte & Dateien  ·  OpenShift · Betrieb · Backup

Cluster-Innereien: Logging, MachineConfig und etcd

Du verfolgst eine Logzeile durch ihre möglichen Speicherorte, ordnest einem Node seine gerenderte MachineConfig zu und erzeugst ein echtes etcd-Backup. Dabei bleibt klar getrennt, was du selbst anlegst, was der Cluster generiert und was du nur kennen oder sichern musst.

Stand: 5. September 2026OKD / OCP 4.xLogging 6.xAtlas G2, G4, G7ca. 45 Minuten

1 Drei Zustandsketten

Alle drei Themen beantworten dieselbe Betriebsfrage: Wo entsteht Zustand, wer hält ihn und wie kommst du im Fehlerfall wieder daran?

LoggingContainer schreibt nach Standardausgabe. CRI-O hält den lokalen Logstrom. Vector sammelt ihn optional ein. Ein ClusterLogForwarder leitet ihn an Loki oder ein externes Ziel weiter.
MachineConfigMehrere MachineConfig-Objekte beschreiben den Sollzustand. Der MCO erzeugt daraus eine rendered-master-…-Konfiguration. Der Machine Config Daemon wendet sie am Node an.
etcdDer API-Server speichert Kubernetes-Objekte in etcd. Das Skript cluster-backup.sh erzeugt Snapshot und Static-Pod-Ressourcen. Erst die externe Kopie macht daraus ein belastbares Backup.

Begriffe: Ein Daemon ist ein ständig laufender Hintergrundprozess. Ein MachineConfigPool, kurz MCP, fasst Nodes mit derselben Betriebssystem-Konfiguration zusammen. etcd ist die verteilte Schlüssel-Wert-Datenbank für alle API-Objekte des Clusters.

2 Gesundheit vor der Diagnose prüfen

Das Lab benötigt cluster-admin. Alle Befehle in diesem Abschnitt lesen nur.

Laptop · PowerShell oder Bash · nur lesen
oc whoami
oc auth can-i '*' '*' --all-namespaces
oc get nodes
oc get co machine-config etcd
oc get mcp
oc get pods -n openshift-etcd -o wide

Startzustand: Die ClusterOperatoren machine-config und etcd sollten Available=True und Degraded=False melden. Ein MCP ist vollständig abgeglichen, wenn UPDATED=True und UPDATING=False ist.

3 Einen Logpfad untersuchen

OpenShift kann aktuelle Container-Logs ohne zentralen Logging-Stack anzeigen. Diese Logs liegen zunächst am Node und verschwinden mit Rotation, Pod-Löschung oder Node-Verlust.

Container schreiben nach stdout/stderr, der Node sammelt das. OpenShift-Logging bündelt drei Teile: Vector sammelt auf jedem Node, LokiStack speichert (nach Labels indiziert, nicht Volltext), und der ClusterLogForwarder lenkt die Ströme – in die interne LokiStack und/oder an externe Ziele wie Splunk oder ein SIEM.

Sammeln (Vector) → Speichern (Loki) → Weiterleiten (ClusterLogForwarder). Vector – DaemonSet ein Pod je Node, liest: Container stdout/stderr journald (der Node selbst) Audit-Logs (kube-apiserver, OVN) parst, reichert an (Namespace, Pod, Container, Node als Labels) löste Fluentd ab (leichter, schneller) LokiStack verwaltet vom Loki-Operator Backend: Objektspeicher (S3, ODF, MinIO) indiziert nach Labels, nicht Volltext → billiger als Elasticsearch, aber Query anders drei Tenants: application / infrastructure / audit RBAC und Retention je Tenant getrennt sizing: 1x.demo / 1x.small / … Observe → Logs in der Web-Konsole Abfragesprache: LogQL nach Namespace / Pod / Level filtern Live-Tail, Zeitfenster, Kontext der Entwickler sieht nur den application-Tenant seiner Projekte Alternative: Grafana gegen Loki externe Ziele Splunk · Elasticsearch syslog · Kafka Cloudwatch · GCP Logging Azure Monitor · HTTP typisch: Audit-Logs ans SIEM, App-Logs nach Splunk TLS + ein Secret je Ziel der ClusterLogForwarder – das Lenkobjekt ein CR mit inputs (application / infrastructure / audit, oder ein Label-Selektor), outputs (die Ziele) und pipelines (input → filter → output) filters: Felder droppen, PII maskieren, Labels/Struktur umschreiben, Rate-Limit je Pipeline ohne Forwarder-CR: alles geht in die Default-LokiStack. Mit CR: du entscheidest, was wohin geht Falle: ein Output mit falschem Zertifikat/Secret → die ganze Pipeline staut, Logs gehen verloren (kein unendlicher Puffer) oc get clusterlogforwarder,lokistack -n openshift-logging · Status-Conditions am CR Merksatz: Vector sammelt, Loki speichert nach Labels, der ClusterLogForwarder lenkt – ersetzt das alte EFK (Elasticsearch/Fluentd/Kibana) Metriken sind ein anderer Stack (G1) · Storage für die Log-PVCs / das Objektspeicher-Backend: G3 Bibliothek: die 8 Dienste loggen strukturiert (JSON) nach stdout → LokiStack, Audit-Logs an ein SIEM weitergeleitet OCP-Unterschied: identisch (die Operatoren sind in OKD verfügbar) – frisch keine Logging-Komponente, man installiert die Operatoren.
Sammeln, speichern, lenken. Vector läuft als DaemonSet und liest auf jedem Node die Container-Ausgabe, journald und die Audit-Logs. Die LokiStack speichert sie in Objektspeicher, nach Labels indiziert (nicht Volltext), aufgeteilt in die Tenants application / infrastructure / audit. Der ClusterLogForwarder-CR entscheidet mit pipelines, was in die interne Loki und was an externe Ziele (Splunk, SIEM, Kafka) geht. Das löste den alten EFK-Stack ab.
  • drei Teile: Vector sammelt (DaemonSet), LokiStack speichert, der ClusterLogForwarder lenkt
  • Vector liest je Node: Container-stdout/stderr, journald des Nodes, Audit-Logs – und reichert mit Namespace, Pod und Container als Labels an
  • LokiStack indiziert nach Labels, nicht Volltext – billiger als Elasticsearch, Backend ist Objektspeicher (S3, ODF, MinIO)
  • drei Tenants: application, infrastructure, audit – RBAC und Retention je Tenant getrennt
  • der Observe → Logs-View der Konsole mit LogQL – ein Entwickler sieht nur den application-Tenant seiner Projekte
  • der ClusterLogForwarder-CR: inputs, outputs (die Ziele), pipelines (input → filter → output)
  • filters: Felder droppen, PII maskieren, Labels umschreiben, Rate-Limit je Pipeline
  • externe Ziele: Splunk, Elasticsearch, syslog, Kafka, Cloudwatch, GCP Logging, Azure Monitor, HTTP – jeweils mit TLS und einem Secret
  • ohne Forwarder-CR geht alles in die Default-LokiStack. Mit CR entscheidest du, was wohin geht
  • Falle: ein Output mit falschem Zertifikat staut die ganze Pipeline – Logs gehen verloren, der Puffer ist nicht unendlich
  • Bibliothek: die 8 Spring-Dienste loggen strukturiert als JSON nach stdout (Logback-Encoder), Vector labelt mit namespace=library und dem Pod-Namen – alles im application-Tenant
  • ohne die Logging-Operatoren (auf der SNO nicht per Default installiert) ist oc logs -f deploy/catalog-service -n library alles was du hast – nach einem sno.ps1 up fehlen die Logs von vor dem Snapshot
  • Metriken sind ein anderer Stack (G1) – Kafka-Consumer-Lag und langsame DB-Queries stehen nicht in den Logs, das ist Metrik oder der Postgres-Exporter
  • auf SNO ohne HA: Vector und ClusterLogForwarder laufen – die LokiStack braucht Objektspeicher, also ein MinIO daneben
  • OCP-Unterschied: identisch – frisch ist keine Logging-Komponente da, man installiert die Operatoren (auch in OKD verfügbar)
  • von Hand untersuchen: Logpfad und Logging-Stack – Container-, Kubelet- und CRI-O-Logs lesen und Logging 6 von der früheren Architektur unterscheiden
Laptop · PowerShell oder Bash · Anwendung
oc get pods -n library
oc logs -n library deployment/catalog-service --tail=50
oc logs -n library deployment/catalog-service --since=10m --timestamps

# nach einem Container-Neustart den vorherigen Container lesen
oc logs -n library pod/<pod-name> --previous --tail=50

oc logs fragt über den API-Server den Kubelet des Nodes ab. Der Kubelet ist der Node-Prozess, der Pods startet und ihren Zustand meldet. Er ist keine dauerhafte Logdatenbank.

Node- und Plattform-Logs

Laptop · PowerShell · Node
$node = oc get node -l node-role.kubernetes.io/control-plane -o jsonpath='{.items[0].metadata.name}'
oc adm node-logs $node --unit=kubelet --tail=50
oc adm node-logs $node --unit=crio --tail=50
Bash-Variante anzeigen
Laptop · Bash · Node
node=$(oc get node -l node-role.kubernetes.io/control-plane -o jsonpath='{.items[0].metadata.name}')
oc adm node-logs "$node" --unit=kubelet --tail=50
oc adm node-logs "$node" --unit=crio --tail=50
QuellezeigtÜberlebensgrenze
oc logsStandardausgabe eines aktuellen oder vorherigen Containerslokale Rotation und Node-Lebensdauer
kubelet-JournalPod-Start, Mounts, Probes und Node-AusführungJournal-Rotation am Node
crio-JournalImage, Sandbox und Container-RuntimeJournal-Rotation am Node
Loki oder externes Zielzentral gesammelte Anwendungs-, Infrastruktur- und Audit-LogsAufbewahrungsregel des Zielsystems

4 Erkennen, ob zentrales Logging installiert ist

OpenShift Logging ist nicht automatisch Bestandteil jedes Clusters. In Logging 6 verwaltet der Logging Operator Sammlung und Weiterleitung, der Loki Operator den Speicher und der Cluster Observability Operator die Anzeige.

Laptop · PowerShell · nur lesen
oc api-resources | Select-String -Pattern 'ClusterLogForwarder|LokiStack'
oc get csv -A | Select-String -Pattern 'logging|loki|observability'
oc get clusterlogforwarder -A
oc get lokistack -A
oc get pods -n openshift-logging
Bash-Variante anzeigen
Laptop · Bash · nur lesen
oc api-resources | grep -E 'ClusterLogForwarder|LokiStack'
oc get csv -A | grep -Ei 'logging|loki|observability'
oc get clusterlogforwarder -A
oc get lokistack -A
oc get pods -n openshift-logging

Versionsgrenze: Logging 6 verwendet für ClusterLogForwarder die API-Gruppe observability.openshift.io und Vector als Collector. Ältere Beispiele mit logging.openshift.io, ClusterLogging, Fluentd oder Elasticsearch gehören zur früheren Architektur. Prüfe immer zuerst oc api-resources | Select-String ClusterLogForwarder und oc explain clusterlogforwarder.spec.

Auf der kleinen SNO ist kein Logging-Stack die vernünftige Vorgabe. Loki benötigt dauerhaften Objektspeicher und zusätzliche Ressourcen. Für kurze Diagnose reicht oc logs. Für Aufbewahrung oder Audit muss ein zentraler Zielpfad geplant werden.

5 Node-Konfiguration zum Ursprung zurückverfolgen

Der Machine Config Operator, kurz MCO, verwaltet das Betriebssystem der RHCOS- oder SCOS-Nodes. Direkte SSH-Änderungen sind Drift und keine dauerhafte Konfiguration.

RHCOS/SCOS ist ein unveränderliches Betriebssystem – du gehst nicht per SSH rein und editierst Dateien. Jede Änderung am Node ist ein MachineConfig-Objekt (ein Ignition-Schnipsel). Der Machine Config Operator mischt alle MachineConfigs eines Pools zu einer Konfig und rollt sie Node für Node aus: cordon, drain, schreiben, reboot, uncordon.

Kein SSH-Editieren – alles über MachineConfig, ausgerollt Node für Node. MachineConfig (Objekt) ein Ignition-Schnipsel: Dateien (/etc/…), systemd-Units Kernel-Argumente, kernelType Label …/role: worker ordnet es einem Pool zu höhere CRs: KubeletConfig, ContainerRuntimeConfig → MCO macht MachineConfigs draus MachineConfigPool master, worker, oder ein eigener Pool der MCO mischt alle MachineConfigs des Pools zu einer gerenderten Konfig (rendered-worker-<hash>) maxUnavailable: wie viele Nodes gleichzeitig paused: true → Rollout einfrieren (Wartungsfenster) oc get mcp – UPDATED / UPDATING / DEGRADED, Maschinenzahlen DEGRADED = ein Node kam nicht durch (SSH rein, journalctl) der MCO rollt aus – Node für Node 1 cordon – keine neuen Pods auf diesen Node 2 drain – laufende Pods verdrängen (PodDisruptionBudget beachtet) 3 die neue Konfig auf die Platte schreiben (der machine-config-daemon je Node) 4 reboot – der Node startet mit der neuen Konfig 5 uncordon – Node nimmt wieder Pods, dann der nächste auch ein einzelner SNO-Node macht das → kurze Downtime der Control Plane manche Datei-Änderungen ohne Reboot (der Daemon erkennt das) wofür man MachineConfigs nimmt chrony / NTP-Server · Registry-Mirror (registries.conf, ImageDigestMirrorSet) Kernel-Argumente (hugepages, nosmt), Realtime-Kernel zusätzliche CA-Zertifikate ins System-Trust, eine systemd-Unit SSH-Keys für core · crio-Einstellungen (via ContainerRuntimeConfig) eine kaputte MachineConfig kann alle Nodes eines Pools lahmlegen – erst an einem Custom-Pool testen Beziehung zu Upgrades & Nodes ein Cluster-Upgrade (G5) liefert oft eine neue Basis-MachineConfig → der MCO rollt die Nodes darum dauert ein Upgrade so lang – jeder Node cordon/drain/reboot, nacheinander Pool pausieren vor einem EUS-Hop, danach entpausen (G5) oc debug node/<name>chroot /host zum Nachsehen (nicht zum Ändern) oc get machineconfig · oc get mcp -w · oc get nodes (SchedulingDisabled = mitten im Rollout) Merksatz: MachineConfig = eine Node-Änderung als Objekt, MachineConfigPool = die Gruppe, MCO = rollt sie nacheinander mit Reboot aus niemals per SSH Dateien ändern – beim nächsten Reconcile oder Reboot ist es weg, und der Pool wird Degraded baut auf dem unveränderlichen Node-OS aus Diagramm 01 (SCOS/RHCOS) auf · Node-Auswahl für Pods: B6 OCP-Unterschied: identisch – MCO und MachineConfig sind Kern-OpenShift, in OKD und OCP gleich (RHCOS vs SCOS als OS).
Der Node ist unveränderlich – die Konfig ist ein Objekt. Eine MachineConfig trägt einen Ignition-Schnipsel (Dateien, systemd-Units, Kernel-Args). Alle MachineConfigs eines MachineConfigPool (master/worker) werden vom MCO zu einer gerenderten Konfig gemischt und dann Node für Node ausgerollt: cordon → drain → schreiben → reboot → uncordon. Darum dauert ein Upgrade so lang. Per SSH editieren macht den Pool Degraded.
  • RHCOS/SCOS ist unveränderlich – jede Node-Änderung ist ein MachineConfig-Objekt (ein Ignition-Schnipsel: Dateien, systemd-Units, Kernel-Args)
  • ein Label machineconfiguration.openshift.io/role ordnet die MachineConfig einem MachineConfigPool zu – der MCO mischt alle eines Pools zu einer rendered-<pool>-<hash>-Konfig
  • der Rollout geht Node für Node: cordondrain (PodDisruptionBudget beachtet) → schreiben → rebootuncordon
  • maxUnavailable am Pool steuert die Parallelität, paused: true friert den Rollout ein (Wartungsfenster)
  • oc get mcp zeigt UPDATED / UPDATING / DEGRADED und die Maschinenzahlen – DEGRADED = ein Node kam nicht durch
  • höhere CRs: KubeletConfig und ContainerRuntimeConfig – der MCO übersetzt sie in MachineConfigs
  • typische Nutzung: chrony/NTP, Registry-Mirror (registries.conf), Kernel-Args (hugepages), extra CA-Zertifikate, eine systemd-Unit, SSH-Keys für core
  • ein Cluster-Upgrade (G5) liefert oft eine neue Basis-MachineConfig → darum rollt jedes Upgrade alle Nodes mit Reboot
  • niemals per SSH Dateien ändern – beim nächsten Reconcile oder Reboot ist es weg und der Pool wird Degraded. Nur nachsehen: oc debug node/<name> dann chroot /host
  • Falle: eine kaputte MachineConfig kann alle Nodes eines Pools lahmlegen – erst an einem Custom-Pool testen
  • real auf der SNO: tailscaled wurde von Hand per SSH als statisches Binary und systemd-Unit installiert – überlebt einen Reboot, aber ein Cluster-Upgrade (G5) rollt den Node neu aus und es ist weg. Sauber wäre eine MachineConfig mit der Unit
  • der SSH-Key für core kam über install-config.yaml (sshKey:) in die Ignition – das ist schon eine MachineConfig, die einzige, die wir bewusst gesetzt haben
  • auf SNO ohne HA: die Rollout-Mechanik sieht man am einen Node (cordon/drain/reboot, kurze Control-Plane-Downtime) – nur maxUnavailable über einen Pool zeigt sich erst mit Workern
  • OCP-Unterschied: identisch – MCO und MachineConfig sind Kern-OpenShift (RHCOS vs SCOS als OS)
  • sicher von Hand proben: MachineConfig und MCO – gerenderte Konfiguration bis zum Node zurückverfolgen und ein eigenes Manifest nur per serverseitigem Dry-Run prüfen
Laptop · PowerShell · nur lesen
oc get co machine-config
oc get mcp
oc get mc -o 'custom-columns=NAME:.metadata.name,GENERATED-BY:.metadata.ownerReferences[0].kind'

$node = oc get node -l node-role.kubernetes.io/control-plane -o jsonpath='{.items[0].metadata.name}'
oc get node $node -o jsonpath='{.metadata.annotations.machineconfiguration\.openshift\.io/currentConfig}{"\n"}{.metadata.annotations.machineconfiguration\.openshift\.io/desiredConfig}{"\n"}{.metadata.annotations.machineconfiguration\.openshift\.io/state}{"\n"}{.metadata.annotations.machineconfiguration\.openshift\.io/reason}{"\n"}'

$rendered = oc get mcp master -o jsonpath='{.status.configuration.name}'
oc get mc $rendered -o yaml
Bash-Variante anzeigen
Laptop · Bash · nur lesen
oc get co machine-config
oc get mcp
oc get mc -o 'custom-columns=NAME:.metadata.name,GENERATED-BY:.metadata.ownerReferences[0].kind'

node=$(oc get node -l node-role.kubernetes.io/control-plane -o jsonpath='{.items[0].metadata.name}')
oc get node "$node" -o jsonpath='{.metadata.annotations.machineconfiguration\.openshift\.io/currentConfig}{"\n"}{.metadata.annotations.machineconfiguration\.openshift\.io/desiredConfig}{"\n"}{.metadata.annotations.machineconfiguration\.openshift\.io/state}{"\n"}{.metadata.annotations.machineconfiguration\.openshift\.io/reason}{"\n"}'

rendered=$(oc get mcp master -o jsonpath='{.status.configuration.name}')
oc get mc "$rendered" -o yaml
KategorieBeispieldeine Aufgabe
du legst anmachineconfig-mco-lab.yamlgewollte Node-Änderung als deklaratives Manifest beschreiben
wird generiertrendered-master-…nur lesen. Der MCO kombiniert alle zur Rolle passenden MachineConfigs
wichtig/etc/mco-lab-marker am NodeWirkung prüfen, aber nicht per SSH als dauerhafte Konfiguration anlegen

6 Eine MachineConfig sicher proben

Du legst lokal ein Manifest an und lässt nur API-Schema und Admission prüfen. Der Dry-Run erzeugt kein Clusterobjekt und löst keinen Node-Neustart aus.

Laptop · PowerShell · erzeugt lokale Datei
@'
apiVersion: machineconfiguration.openshift.io/v1
kind: MachineConfig
metadata:
  name: 99-master-mco-lab
  labels:
    machineconfiguration.openshift.io/role: master
spec:
  config:
    ignition:
      version: 3.4.0
    storage:
      files:
        - path: /etc/mco-lab-marker
          mode: 420
          overwrite: true
          contents:
            source: data:text/plain;charset=utf-8,mco-lab%0A
'@ | Set-Content -LiteralPath .\machineconfig-mco-lab.yaml -Encoding utf8

oc apply --dry-run=server -f .\machineconfig-mco-lab.yaml
oc diff -f .\machineconfig-mco-lab.yaml
Bash-Variante anzeigen
Laptop · Bash · erzeugt lokale Datei
cat > machineconfig-mco-lab.yaml <<'EOF'
apiVersion: machineconfiguration.openshift.io/v1
kind: MachineConfig
metadata:
  name: 99-master-mco-lab
  labels:
    machineconfiguration.openshift.io/role: master
spec:
  config:
    ignition:
      version: 3.4.0
    storage:
      files:
        - path: /etc/mco-lab-marker
          mode: 420
          overwrite: true
          contents:
            source: data:text/plain;charset=utf-8,mco-lab%0A
EOF

oc apply --dry-run=server -f machineconfig-mco-lab.yaml
oc diff -f machineconfig-mco-lab.yaml

machineconfig-mco-lab.yaml ist eine Datei, die du anlegst. /etc/mco-lab-marker würde erst bei einem echten Apply vom MCO generiert. Der Rückgabecode 1 von oc diff bedeutet normalerweise „Unterschied gefunden“ und ist hier kein Fehler.

Nicht im Lab ausführen: Ein echtes Apply auf die Rolle master erzeugt eine neue gerenderte Konfiguration. Der MCO kann den Node entleeren und neu starten. Auf einer SNO bedeutet das vollständige Unterbrechung. Ein pausierter MCP verhindert den sofortigen Rollout, sammelt aber ausstehende Änderungen, die beim Entpausieren gemeinsam wirksam werden.

Die lokale Übungsdatei kannst du danach mit Remove-Item -LiteralPath .\machineconfig-mco-lab.yaml oder unter Bash mit rm -- machineconfig-mco-lab.yaml entfernen.

7 etcd vor dem Backup untersuchen

Ein etcd-Snapshot schützt Kubernetes- und OpenShift-API-Objekte. Er enthält keine Daten aus Persistent Volumes und ersetzt kein Anwendungsbackup.

etcd ist die Schlüssel-Wert-Datenbank des Clusters – jedes API-Objekt liegt darin. Sie repliziert per Raft und braucht deshalb ein Quorum (3 Member überstehen 1 Ausfall, 5 Member 2). Auf jedem Control-Plane-Node läuft ein etcd-Static-Pod, verwaltet vom etcd-Operator. Ein Snapshot ist die einzige Absicherung – und es gibt zwei Wege dazu (der etcd-Snapshot und der Hetzner-Disk-Snapshot).

Die Datenbank hinter dem API-Server – Raft, Quorum, und ein Snapshot als Notausgang. was etcd ist verteilte Schlüssel-Wert-Datenbank – jedes Objekt (Pod, Secret, CO…) liegt hier, sonst nirgends der kube-apiserver ist der einzige Client ein etcd-Static-Pod je Control-Plane-Node verwaltet vom etcd-Operator (cluster-etcd-operator) gemeldet als ClusterOperator etcd (G6) Namespace openshift-etcd · oc get etcd cluster -o yaml Encryption at rest (B9) verschlüsselt die Werte – auch im Snapshot Raft & Quorum Schreibvorgänge gehen an den Leader, der sie repliziert ein Schreibvorgang gilt erst mit Mehrheit als bestätigt 3 Member → Mehrheit 2 → überstehen 1 Ausfall 5 Member → Mehrheit 3 → überstehen 2 Ausfälle unter der Mehrheit → Quorum verloren → API read-only / tot darum haben Cluster 3 (oder 5) Control-Plane-Nodes, nie 2 oder 4 2 von 3 tot = manueller Restore nötig, kein Selbstheilen der Operator ersetzt einen einzelnen ausgefallenen Member automatisch SNO – ein Member, kein Quorum Single-Node OpenShift hat genau einen etcd-Member kein Quorum, keine HA – Node weg = Cluster weg ein Backup ist der einzige Rettungsweg der Disk-Snapshot von sno.ps1 down/up fängt etcd mit ein zusätzlich cluster-backup.sh laufen lassen (Cron) Restore auf SNO = cluster-restore.sh auf demselben Node unser SNO ist der Alltags-Arbeitsplatz – hier reicht der Disk-Snapshot der 3-Node-Cluster kommt nur für Block G kurz hoch Backup & Restore Backup (auf einem Control-Plane-Node, als root): /usr/local/bin/cluster-backup.sh /home/core/backup snapshot.db + static-pod-resourcesvor jeder riskanten Änderung + per Cron Restore (Quorum verloren): einen Node wählen → cluster-restore.sh mit dem Snapshot → dieser Node wird die einzige Wahrheit → andere treten neu bei & syncen → Control Plane startet neu danach: oc get co (G6) durchsehen, evtl. hängende Operatoren neu starten Pflege & Diagnose Defrag: die DB wächst durch alte Revisionen – der Operator defragmentiert automatisch, sonst oc rsh + etcdctl defrag oc get pods -n openshift-etcd – laufen alle Member? etcdctl endpoint status / member list im Pod Alarme: etcdInsufficientMembers, etcdHighFsyncDurations etcd will schnelle Disks (fsync-Latenz) – SSD/NVMe, nie HDD Merksatz: etcd hält jedes API-Objekt, repliziert per Raft, braucht Mehrheit – 3 Nodes überstehen 1 Ausfall, 5 Nodes 2 verlorenes Quorum heilt nicht von selbst – cluster-restore.sh aus einem snapshot.db ist der Weg zurück SNO: ein Member, kein Quorum – der sno.ps1-Disk-Snapshot ist die Absicherung · Backup vor Upgrade (G5) und MachineConfig (G4) OCP-Unterschied: identisch – etcd-Operator, cluster-backup.sh/cluster-restore.sh und die Quorum-Regeln sind in OKD und OCP gleich.
Die Datenbank des Clusters. etcd speichert jedes API-Objekt und repliziert per Raft – ein Schreibvorgang gilt erst mit Mehrheit als bestätigt, also überstehen 3 Member 1 Ausfall und 5 Member 2. Ein Static-Pod je Control-Plane-Node, verwaltet vom etcd-Operator und als ClusterOperator etcd gemeldet (G6). cluster-backup.sh erzeugt eine snapshot.db – vor jeder riskanten Änderung. Bei verlorenem Quorum ist cluster-restore.sh aus dem Snapshot der einzige Weg zurück. Auf SNO gibt es nur einen Member und kein Quorum – da ist der sno.ps1-Disk-Snapshot die Absicherung.
  • etcd ist die verteilte Schlüssel-Wert-Datenbank des Clusters – jedes API-Objekt (Pod, Secret, ClusterOperator…) liegt darin und sonst nirgends
  • ein etcd-Static-Pod je Control-Plane-Node, verwaltet vom etcd-Operator (cluster-etcd-operator), gemeldet als ClusterOperator etcd (G6) – der kube-apiserver ist der einzige Client
  • Raft: Schreibvorgänge gehen an den Leader und gelten erst mit Mehrheit der Member als bestätigt
  • Quorum: 3 Member überstehen 1 Ausfall, 5 Member 2 – darum 3 oder 5 Control-Plane-Nodes, nie 2 oder 4. Einen einzelnen Ausfall ersetzt der Operator, unter die Mehrheit gefallen heilt nicht von selbst
  • Backup: /usr/local/bin/cluster-backup.sh /home/core/backup auf einem Control-Plane-Node → snapshot.db + static-pod-resources
  • Backup vor jeder riskanten Änderung (Upgrade G5, MachineConfig G4) und regelmäßig per Cron
  • Restore bei verlorenem Quorum: einen Node wählen, cluster-restore.sh mit dem Snapshot → er wird die einzige Wahrheit, die anderen treten neu bei und syncen, die Control Plane startet neu
  • Defrag: die DB wächst durch alte Revisionen – der Operator defragmentiert automatisch, notfalls oc rsh plus etcdctl defrag
  • etcd braucht schnelle Disks (niedrige fsync-Latenz) – SSD/NVMe, nie HDD. Alarme dazu: etcdInsufficientMembers, etcdHighFsyncDurations
  • SNO: genau ein Member, kein Quorum, keine HA – Node weg = Cluster weg, ein Backup ist der einzige Rettungsweg
  • zwei Backup-Wege: der richtige ist cluster-backup.sh (etcd-Snapshot, im echten Cluster Pflicht) – der pragmatische ist der Hetzner-Disk-Snapshot von sno.ps1 down/up, der etcd mit einfängt
  • auf einem Wegwerf-SNO nimmst du den zweiten und sparst dir den etcd-Snapshot – Quorum-Verlust und cluster-restore.sh übst du an einem lokalen kind-Cluster mit drei Control-Plane-Nodes
  • was im Snapshot steckt: sno.ps1 down stoppt kubelet und snapshottet die Nodes-Disk – etcd liegt darauf, also ist der ganze Cluster-Zustand mit drin, auch die veraltete image-registry-Lease und fehlende SA-Tokens. Darum räumt sno-wsl.sh remediate nach dem up auf (G6)
  • Diagnose: oc get pods -n openshift-etcd, oc get etcd cluster -o yaml, etcdctl endpoint status im Pod – Encryption at rest (B9) verschlüsselt die Werte, auch im Snapshot
  • OCP-Unterschied: identisch – etcd-Operator, die Backup- und Restore-Skripte und die Quorum-Regeln sind in OKD und OCP gleich
  • Backup wirklich erzeugen: etcd-Backup auf einem Control-Plane-Node – beide erzeugten Dateien außerhalb des Clusters sichern und von Anwendungs- und Disk-Backups abgrenzen
Laptop · PowerShell oder Bash · nur lesen
oc get co etcd
oc get etcd cluster -o yaml
oc get pods -n openshift-etcd -l app=etcd -o wide
oc get --raw='/readyz?verbose'
oc get clusterversion version -o jsonpath='{.status.desired.version}{"\n"}'

Vorbedingungen für das Backup: Der Cluster muss gesund sein. Die erste Zertifikatsrotation 24 Stunden nach der Installation muss abgeschlossen sein. Das Backup wird nur auf einem Control-Plane-Node und möglichst außerhalb hoher Last erzeugt. Ein Restore benötigt dieselbe z-Stream-Version.

8 Ein echtes etcd-Backup erzeugen

Das offizielle Skript ist Teil des etcd Cluster Operators. Es erzeugt einen Datenbank-Snapshot und ein Archiv mit den Static-Pod-Ressourcen.

Control-Plane-Node ermitteln

Laptop · PowerShell
$node = oc get node -l node-role.kubernetes.io/control-plane -o jsonpath='{.items[0].metadata.name}'
$node
oc debug --as-root node/$node
Bash-Variante anzeigen
Laptop · Bash
node=$(oc get node -l node-role.kubernetes.io/control-plane -o jsonpath='{.items[0].metadata.name}')
printf '%s\n' "$node"
oc debug --as-root "node/$node"

Im Debug-Pod ausführen

Debug-Pod · schreibt auf die Node-Disk
chroot /host
mkdir -p /home/core/assets/etcd-backup
/usr/local/bin/cluster-backup.sh /home/core/assets/etcd-backup
ls -lh /home/core/assets/etcd-backup
exit
exit
DateiHerkunftBedeutung
snapshot_<zeit>.dbwird generiertetcd-Datenbank mit dem Clusterzustand
static_kuberesources_<zeit>.tar.gzwird generiertStatic-Pod-Ressourcen, die der Restore zusätzlich benötigt
/home/core/assets/etcd-backup/wichtigZwischenablage auf der Node-Disk. Noch keine externe Sicherung

9 Backup außerhalb des Clusters sichern

Eine Datei auf derselben SNO hilft nicht bei Node- oder Disk-Verlust. Kopiere beide erzeugten Dateien auf den Laptop und danach in deinen verschlüsselten Backup-Speicher.

Laptop · PowerShell · benötigt Node-SSH
$node = oc get node -l node-role.kubernetes.io/control-plane -o jsonpath='{.items[0].metadata.name}'
$nodeIp = oc get node $node -o jsonpath='{.status.addresses[?(@.type=="InternalIP")].address}'
$destination = ".\backups\etcd-$(Get-Date -Format yyyyMMdd-HHmmss)"
New-Item -ItemType Directory -Path $destination -Force
scp -r "core@${nodeIp}:/home/core/assets/etcd-backup/*" $destination
Get-ChildItem -LiteralPath $destination
Get-FileHash -Algorithm SHA256 -Path "$destination\*"
Bash-Variante anzeigen
Laptop · Bash · benötigt Node-SSH
node=$(oc get node -l node-role.kubernetes.io/control-plane -o jsonpath='{.items[0].metadata.name}')
node_ip=$(oc get node "$node" -o jsonpath='{.status.addresses[?(@.type=="InternalIP")].address}')
destination="./backups/etcd-$(date +%Y%m%d-%H%M%S)"
mkdir -p "$destination"
scp -r "core@${node_ip}:/home/core/assets/etcd-backup/." "$destination/"
find "$destination" -maxdepth 1 -type f -print
sha256sum "$destination"/*

Falls die ermittelte InternalIP vom Laptop nicht erreichbar ist, verwendest du stattdessen die erreichbare Tailscale- oder Host-Adresse desselben Nodes. Der Node-Name und die Zieladresse müssen weiterhin zum gleichen Control-Plane-Node gehören.

Der Ordner backups/etcd-<zeit>/ wird von dir angelegt. Er gehört nicht ins Git-Repository. Der Snapshot enthält Clusterobjekte und damit möglicherweise Secrets. Verschlüssele und schütze ihn wie Zugangsdaten.

Restore hier nicht üben: cluster-restore.sh ersetzt den Zustand der Control Plane und startet Static Pods neu. Das ist ein Disaster-Recovery-Vorgang für ein Wartungsfenster oder einen isolierten Übungscluster, kein Gesundheitstest für die laufende SNO.

10 Die drei Sicherungsarten nicht verwechseln

Sicherungenthältenthält nichttypischer Zweck
etcd-BackupAPI-Objekte und Static-Pod-RessourcenPV-Inhalte, externe Datenbanken und Registry-BlobsControl-Plane-Restore derselben z-Stream-Version
gestoppter Hetzner-Disk-Snapshotgesamte Node-Disk einschließlich etcd und lokaler PVsexterne Systeme und spätere Änderungenpragmatisches Wiederaufwecken der SNO mit sno.ps1
AnwendungsbackupDatenbank-Dumps, Objekte und fachliche DatenClusterkonfigurationeinzelne Anwendung wiederherstellen oder migrieren
  • Logs sind keine Backups. Sie erklären Ereignisse, stellen aber keinen Zustand wieder her.
  • MachineConfig ist gewünschte Node-Konfiguration. Sie sichert keine Daten und gehört als selbst angelegtes Manifest ins Git.
  • etcd-Backup ist versionsgebunden. Dokumentiere die genaue Cluster-Version zusammen mit den Prüfsummen.
  • Ein SNO-Snapshot ersetzt keine externe Kopie. Provider-, Konto- oder Regionsverlust bleibt sonst derselbe Ausfallbereich.

11 Lernkontrolle

  • Du kannst erklären, warum oc logs auch ohne Loki funktioniert und wann die Logzeile verloren geht.
  • Du erkennst Logging-6-Ressourcen und verwechselst sie nicht mit der früheren Fluentd- und Elasticsearch-Architektur.
  • Du kannst currentConfig, desiredConfig und rendered-master-… eines Nodes zusammenführen.
  • Du weißt, warum ein echtes MachineConfig-Apply auf einer SNO einen Wartungsfall auslösen kann.
  • Du kannst die zwei erzeugten etcd-Backup-Dateien benennen und ihren Speicherort außerhalb des Clusters nachweisen.
  • Du kannst etcd-, Disk- und Anwendungsbackup voneinander abgrenzen.