|
|
||
|---|---|---|
| __pycache__ | ||
| docs | ||
| .env.example | ||
| .gitignore | ||
| README.md | ||
| backup.py | ||
| config_parser.py | ||
| discovery.py | ||
| main.py | ||
| migrator.py | ||
| models.py | ||
| planner.py | ||
| requirements.txt | ||
| rescue.py | ||
| ssh_manager.py | ||
| verifier.py | ||
README.md
Proxmox Cluster Network Changer
Migriert ein komplettes Proxmox-Cluster (inkl. Ceph) von einem Netzwerk in ein anderes.
Problem: Wenn man bei einem Proxmox-Cluster die IPs ändert, verliert man das Quorum und /etc/pve wird read-only — dann kann man weder Corosync noch Ceph über das Cluster-Dateisystem konfigurieren. Dieses Tool löst das Problem durch eine koordinierte Migration aller Nodes.
Features
- Auto-Detect aller Nodes, Bridges, IPs und Netzwerke
- Koordinierte Migration aller Nodes in einem Durchgang
- Multi-NIC-Support — erkennt automatisch Management-, Ceph-Public- und Ceph-Cluster-Bridges
- Ceph-Support (Public Network, Cluster Network, MON-Adressen)
- Funktioniert auch bei gebrochenem Quorum (z.B. wenn ein Node bereits manuell geändert wurde)
- Rescue-Netzwerk — temporäres Emergency-Netz wenn sich Nodes nicht mehr erreichen können
- Passwort-Auth via
.env— unabhängig von/etc/pve, funktioniert immer - Automatische Backups aller Konfigurationen vor der Migration
- Dry-Run-Modus zum gefahrlosen Testen
- Verifikation nach der Migration
Voraussetzungen
- Python 3.9+ (auf Proxmox standardmäßig vorhanden)
- Root-Zugriff auf dem Node, auf dem das Tool läuft
sshpass— wird beim ersten Start automatisch installiert falls nicht vorhanden- Root-Passwort der Proxmox-Nodes (alle Nodes müssen das gleiche Passwort haben)
- Keine externen Python-Pakete nötig (nur stdlib)
Installation
# Auf einen Proxmox-Node kopieren
scp -r proxmox-cluster-network-changer/ root@pve1:/root/
# Oder direkt klonen
cd /root
git clone <repo-url> proxmox-cluster-network-changer
# .env erstellen
cd proxmox-cluster-network-changer
cp .env.example .env
nano .env # SSH_PASSWORD=dein-root-passwort eintragen
SSH-Authentifizierung
Das Tool nutzt sshpass mit dem Root-Passwort aus der .env-Datei. Key-basierte Auth funktioniert bei Proxmox nicht zuverlässig, weil /etc/pve/priv/authorized_keys verschwindet wenn pve-cluster gestoppt wird.
# .env-Datei erstellen
echo 'SSH_PASSWORD=dein-root-passwort' > .env
Hinweis: Alle Nodes müssen das gleiche Root-Passwort haben (bei Proxmox-Clustern üblich).
Verwendung
Aktuelle Konfiguration anzeigen (Discovery)
python3 main.py --discover
Zeigt an:
- Alle Cluster-Nodes mit IPs
- Corosync-Konfiguration
- Ceph-Netzwerke und MON-Hosts
- Quorum-Status
- Welche Nodes erreichbar sind
Dry-Run (nichts wird geändert)
python3 main.py --dry-run
Durchläuft den kompletten Prozess, zeigt alle geplanten Änderungen an, schreibt aber nichts.
Migration durchführen
python3 main.py
Das Tool führt interaktiv durch den Prozess:
============================================================
Proxmox Cluster Network Changer
============================================================
[SSH] Passwort-Authentifizierung aktiv (via sshpass)
=== Phase 1: Discovery ===
[Corosync]
Cluster: mycluster
Nodes gefunden: 4
- pve1 (ID: 1) -> 192.168.0.101
- pve2 (ID: 2) -> 192.168.0.102
- pve3 (ID: 3) -> 192.168.0.103
- pve4 (ID: 4) -> 192.168.0.104
[Ceph]
Public Network: 192.168.0.0/24
Cluster Network: 10.0.1.0/24
=== Phase 2: Migration planen ===
[Netzwerk-Erkennung]
vmbr0: Management/Corosync (192.168.0.0/24)
vmbr1: Ceph Cluster (10.0.1.0/24)
[Management-Netzwerk (Corosync)]
Aktuell: 192.168.0.0/24
Neues Management-Netzwerk (z.B. 172.0.2.0/16): 172.0.2.0/16
Neues Gateway [172.0.0.1]: 172.0.2.1
[Management IP-Mapping]
pve1: 192.168.0.101 -> [172.0.2.101]:
pve2: 192.168.0.102 -> [172.0.2.102]:
[Ceph Netzwerke]
Ceph Public: gleich wie Management -> wird automatisch mit umgezogen
Ceph Cluster (10.0.1.0/24) auf separater NIC -> eigenes Mapping
Migration durchführen? [j/N]: j
Das Tool erkennt automatisch welche Bridges welche Netzwerke tragen. Wenn Ceph Public/Cluster auf separaten NICs liegen, werden die IPs einzeln pro Node abgefragt.
Optionen
| Option | Beschreibung |
|---|---|
--dry-run |
Nur anzeigen, nichts ändern |
--discover |
Nur aktuelle Config anzeigen |
--rescue |
Rescue-Modus: Emergency-Netzwerk einrichten |
--rescue-commands SUBNET |
Nur Rescue-Befehle ausgeben (z.B. 10.99.99.0/24) |
--ssh-port PORT |
SSH-Port (Standard: 22) |
--env-file PFAD |
Pfad zur .env-Datei (Standard: .env) |
.env-Datei
| Variable | Beschreibung |
|---|---|
SSH_PASSWORD |
Pflicht. Root-Passwort für SSH (alle Nodes gleich) |
SSH_USER |
SSH-Benutzer (Standard: root) |
Was wird geändert?
| Datei | Wo | Was |
|---|---|---|
/etc/network/interfaces |
Jeder Node | Alle Bridge-IPs (Management, Ceph), Gateway |
/etc/hosts |
Jeder Node | Hostname-zu-IP-Zuordnung |
/etc/corosync/corosync.conf |
Jeder Node | Corosync Ring-Adressen |
/etc/pve/ceph.conf |
Cluster-FS | public_network, cluster_network, MON-Adressen |
/etc/pve/storage.cfg |
Cluster-FS | monhost-IPs für CephFS- und RBD-Storage |
Migrationsablauf (Phase 4)
- Neue Konfigurationen werden auf alle Nodes verteilt (Staging)
- Corosync wird auf allen Nodes gestoppt
- pve-cluster (pmxcfs) wird gestoppt →
/etc/pveunmounted - Corosync-Config wird direkt geschrieben (
/etc/corosync/corosync.conf) /etc/hostswird aktualisiert/etc/network/interfaceswird aktualisiert + Netzwerk-Reload:- Remote-Nodes zuerst (fire-and-forget via
nohup) - Lokaler Node zuletzt
- Verifikation der neuen IPs mit Retry
- Remote-Nodes zuerst (fire-and-forget via
- Services starten (pve-cluster, corosync), Quorum abwarten, Ceph aktualisieren
SSH funktioniert durchgehend via
sshpass— unabhängig von/etc/pve.
Rescue-Netzwerk (Emergency Mode)
Szenario: PVE01 hat bereits eine neue IP, PVE02-04 sind noch im alten Netz. Kein Node kann die anderen erreichen.
Schnell: Nur Befehle anzeigen
python3 main.py --rescue-commands 10.99.99.0/24
Ausgabe:
RESCUE BEFEHLE
Subnetz: 10.99.99.0/24 | Bridge: vmbr0
pve1 (192.168.0.101):
ip addr add 10.99.99.1/24 dev vmbr0
pve2 (192.168.0.102):
ip addr add 10.99.99.2/24 dev vmbr0
pve3 (192.168.0.103):
ip addr add 10.99.99.3/24 dev vmbr0
pve4 (192.168.0.104):
ip addr add 10.99.99.4/24 dev vmbr0
Zum Entfernen:
ip addr del 10.99.99.1/24 dev vmbr0 # pve1
ip addr del 10.99.99.2/24 dev vmbr0 # pve2
ip addr del 10.99.99.3/24 dev vmbr0 # pve3
ip addr del 10.99.99.4/24 dev vmbr0 # pve4
Diese Befehle über IPMI/iLO/iDRAC/KVM-Konsole auf jedem Node ausführen.
Interaktiv: Rescue + Migration
python3 main.py --rescue
oder einfach starten — wenn Nodes nicht erreichbar sind, wird automatisch gefragt:
python3 main.py
3 Node(s) nicht erreichbar.
Rescue-Netzwerk einrichten? [J/n]: j
Ablauf:
- Du gibst ein freies Subnetz an (z.B.
10.99.99.0/24) - Das Tool zeigt für jeden Node den
ip addr addBefehl - Auf dem lokalen Node wird die IP automatisch gesetzt
- Du führst die Befehle auf den anderen Nodes per Konsole aus
- Das Tool testet die Verbindung und liest die Configs
- Danach läuft die normale Migration
- Rescue-IPs werden durch
ifreload -aautomatisch entfernt
Wann brauche ich das?
- Ein oder mehrere Nodes haben bereits manuell eine neue IP bekommen
- Die Nodes liegen in verschiedenen Subnetzen
- SSH zwischen den Nodes funktioniert nicht mehr
- Du hast aber noch Zugriff auf die Konsolen (IPMI/iLO/iDRAC/KVM)
Gebrochenes Quorum
Wenn bereits ein Node manuell geändert wurde und das Quorum verloren ist:
- Das Tool erkennt den Zustand automatisch in der Discovery-Phase
- Nicht erreichbare Nodes werden per Hostname gesucht
- Configs werden direkt geschrieben (nicht über
/etc/pve/) - Nach dem Netzwerk-Reload wird
pvecm expected 1genutzt, um Quorum zu erzwingen - Danach wird Ceph über das Cluster-Dateisystem aktualisiert
Backups
Vor der Migration werden automatisch Backups erstellt:
/root/network-migration-backup-20260304_143022/
├── etc_network_interfaces
├── etc_hosts
├── etc_corosync_corosync.conf
├── etc_ceph_ceph.conf
├── etc_pve_corosync.conf
└── etc_pve_ceph.conf
Restore (manuell)
# Beispiel: Netzwerk-Config wiederherstellen
cp /root/network-migration-backup-*/etc_network_interfaces /etc/network/interfaces
ifreload -a
# Corosync wiederherstellen
cp /root/network-migration-backup-*/etc_corosync_corosync.conf /etc/corosync/corosync.conf
systemctl restart corosync
Empfohlene Reihenfolge bei Problemen
pvecm status— Cluster-Status prüfenpvecm expected 1— Quorum erzwingen (Notfall)ceph -s— Ceph-Status prüfenceph -w— Ceph-Recovery beobachtenjournalctl -u corosync— Corosync-Logs prüfenjournalctl -u pve-cluster— pmxcfs-Logs prüfen
Workaround: Corosync zeigt noch alte IPs in der GUI
Falls nach der Migration in der Proxmox-GUI unter Datacenter → Cluster noch die alten IPs stehen, wurde /etc/pve/corosync.conf nicht aktualisiert. Das passiert weil /etc/pve während der Migration read-only ist und die Config nur direkt nach /etc/corosync/corosync.conf geschrieben wird. Aktuelle Versionen des Tools aktualisieren /etc/pve/corosync.conf automatisch nach dem Quorum.
# 1. Prüfen was wo drin steht:
grep -A1 ring0_addr /etc/corosync/corosync.conf
grep -A1 ring0_addr /etc/pve/corosync.conf
# 2. Wenn /etc/corosync/corosync.conf die neuen IPs hat:
cp /etc/corosync/corosync.conf /etc/pve/corosync.conf
# 3. Falls auch /etc/corosync/corosync.conf die alten IPs hat,
# manuell editieren (IPs anpassen):
nano /etc/pve/corosync.conf
# 4. config_version in /etc/pve/corosync.conf hochzählen
# (Pflicht, damit alle Nodes die Änderung übernehmen)
# Die Zeile steht ganz oben/oder fast unten in der Datei im totem {} Block:
#
# totem {
# ...
# config_version: 4 <-- diese Zahl um 1 erhöhen (z.B. 4 -> 5)
# }
#
# Aktuelle Version anzeigen:
grep config_version /etc/pve/corosync.conf
# 5. Corosync neu starten:
systemctl restart corosync
Workaround: Ceph MON-Map manuell aktualisieren
Falls nach der Migration ceph-mon und ceph-mgr nicht starten (z.B. weil eine ältere Version des Tools die MON-Map nicht aktualisiert hat), muss die Ceph MON-Map manuell korrigiert werden. Die MON-Map ist eine interne Datenbank in der die MON-Adressen gespeichert sind — ein reines Update der ceph.conf reicht nicht.
Wichtig: Die MON-Map muss auf allen Nodes identisch sein (gleiche Epoch), sonst crasht Ceph mit notify_rank_removed. Deshalb: auf einem Node erstellen und auf die anderen kopieren.
Schritt 1: MON auf allen Nodes stoppen
# Auf JEDEM Node:
systemctl stop ceph-mon@$(hostname)
Schritt 2: MON-Map auf dem ersten Node erstellen
# Auf pve1 (oder einem beliebigen Node):
ceph-mon -i $(hostname) --extract-monmap /tmp/monmap
monmaptool --print /tmp/monmap
# Alte Einträge entfernen (für jeden MON-Node)
monmaptool --rm pve1 /tmp/monmap
monmaptool --rm pve2 /tmp/monmap
monmaptool --rm pve3 /tmp/monmap
# Neue Einträge mit neuen IPs hinzufügen
monmaptool --addv pve1 [v2:172.0.2.101:3300/0,v1:172.0.2.101:6789/0] /tmp/monmap
monmaptool --addv pve2 [v2:172.0.2.102:3300/0,v1:172.0.2.102:6789/0] /tmp/monmap
monmaptool --addv pve3 [v2:172.0.2.103:3300/0,v1:172.0.2.103:6789/0] /tmp/monmap
# Ergebnis prüfen
monmaptool --print /tmp/monmap
# Injizieren und MON starten
ceph-mon -i $(hostname) --inject-monmap /tmp/monmap
systemctl start ceph-mon@$(hostname)
Schritt 3: Autoritative Map holen und auf die anderen Nodes kopieren
# Auf pve1 (wo der MON jetzt läuft):
ceph mon getmap -o /tmp/monmap_auth
# Auf die anderen Nodes kopieren:
scp /tmp/monmap_auth root@172.0.2.102:/tmp/monmap
scp /tmp/monmap_auth root@172.0.2.103:/tmp/monmap
Schritt 4: Auf jedem weiteren Node injizieren und starten
# Auf pve2, pve3, etc.:
ceph-mon -i $(hostname) --inject-monmap /tmp/monmap
systemctl start ceph-mon@$(hostname)
systemctl restart ceph-mgr@$(hostname)
systemctl restart ceph-osd.target
systemctl restart ceph-mds@$(hostname) # nur wenn CephFS vorhanden
rm -f /tmp/monmap
Hinweis: Node-Namen und IPs an das eigene Setup anpassen. Aktuelle Versionen des Tools aktualisieren die MON-Map automatisch.
Fehlerbehebung: Ghost-Monitor entfernen (z.B. "Unknown" MON auf falschem Node)
Falls nach der Migration ein Monitor auf einem Node auftaucht, der eigentlich keinen MON haben sollte (z.B. mon.pvetest04 zeigt "Unknown" im Dashboard), wurde versehentlich eine MON-Map auf einen Nicht-MON-Node injiziert. Aktuelle Versionen des Tools erkennen automatisch welche Nodes tatsächlich einen MON betreiben und überspringen die anderen.
Symptom: Im Ceph-Dashboard oder bei ceph -s erscheint ein zusätzlicher Monitor mit Status "Unknown" oder "out of quorum" auf einem Node, der nie einen MON hatte.
Schritt 1: Ghost-Monitor aus dem Cluster entfernen
# Auf einem Node mit funktionierendem MON:
ceph mon remove pvetest04 # Name des Ghost-Monitors anpassen
# Prüfen ob der Ghost weg ist:
ceph mon stat
ceph -s
Schritt 2: Reste auf dem betroffenen Node aufräumen
# Auf dem Node, der den Ghost-Monitor hatte (z.B. pvetest04):
systemctl stop ceph-mon@$(hostname)
systemctl disable ceph-mon@$(hostname)
# MON-Datenverzeichnis entfernen (falls vorhanden):
rm -rf /var/lib/ceph/mon/ceph-$(hostname)
# Prüfen ob noch MON-Prozesse laufen:
ps aux | grep ceph-mon
# Wenn nur der grep-Prozess selbst erscheint, ist alles sauber:
# root 137377 0.0 0.0 6332 2176 pts/0 S+ 08:00 0:00 grep ceph-mon
# -> Kein ceph-mon läuft mehr, alles OK.
#
# Falls noch ein echter ceph-mon-Prozess läuft (z.B. /usr/bin/ceph-mon ...):
kill <PID>
Schritt 3: ceph.conf bereinigen (falls nötig)
# Prüfen ob eine [mon.pvetest04]-Sektion existiert:
grep -A3 '\[mon.pvetest04\]' /etc/pve/ceph.conf
# Falls ja, diese Sektion aus /etc/pve/ceph.conf entfernen:
nano /etc/pve/ceph.conf
# -> Die komplette [mon.pvetest04]-Sektion löschen
# Ebenso die IP aus der mon_host-Zeile entfernen, falls dort gelistet:
grep mon_host /etc/pve/ceph.conf
Hinweis: Dieses Problem tritt nur bei älteren Versionen des Tools auf. Aktuelle Versionen erkennen die tatsächlichen MON-Nodes anhand der
[mon.X]-Sektionen inceph.conf, dermon_host-Liste oder durch Prüfung des/var/lib/ceph/mon/-Verzeichnisses.
Fehlerbehebung: "X daemons have recently crashed" Warnung entfernen
Nach der Migration kann im Ceph-Dashboard unter Health folgende Warnung erscheinen:
Status: HEALTH_WARN
! clock skew detected on mon.pvetest03
! 23 daemons have recently crashed
Die Crash-Meldungen stammen von den Daemon-Neustarts während der Migration und sind nicht kritisch. Ceph speichert Crash-Dumps unter /var/lib/ceph/crash/ und meldet diese solange sie nicht archiviert wurden.
Crash-Dumps anzeigen:
ceph crash ls
Alle Crash-Dumps als gelesen markieren (archivieren):
ceph crash archive-all
Prüfen ob die Warnung weg ist:
ceph -s
# -> HEALTH_OK (oder nur noch clock skew, falls NTP nicht synchron)
Hinweis: Falls zusätzlich
clock skew detectedangezeigt wird, NTP auf den betroffenen Nodes prüfen:systemctl status chronyodersystemctl status ntp. Nach einer Migration mit Neustarts kann die Uhrzeit kurzzeitig abweichen — das korrigiert sich in der Regel automatisch.
Fehlerbehebung: CephFS/RBD-Storage nicht erreichbar nach Migration
Nach der Migration kann CephFS nicht erreichbar sein, weil der Kernel-Mount noch die alten MON-IPs cached. Das passiert unabhängig davon, ob monhost in der storage.cfg steht oder nicht. Aktuelle Versionen des Tools machen den Remount automatisch.
Symptom: CephFS-Storage zeigt Fehler in der GUI, mount | grep ceph zeigt alte IPs:
172.0.4.1,172.0.4.2,172.0.4.3:/ on /mnt/pve/cephfs type ceph (...)
Fall 1: Keine monhost-Einträge in storage.cfg (Standard bei Proxmox)
Proxmox holt sich die MON-IPs automatisch aus /etc/ceph/ceph.conf. Es reicht ein Remount:
# Auf JEDEM Node:
umount /mnt/pve/cephfs
mount /mnt/pve/cephfs
# Prüfen ob die neuen IPs verwendet werden:
mount | grep ceph
Fall 2: Explizite monhost-Einträge in storage.cfg
# 1. Prüfen ob monhost-Einträge vorhanden sind:
grep monhost /etc/pve/storage.cfg
# 2. Falls ja, monhost für CephFS aktualisieren (neue MON-IPs kommasepariert):
pvesm set cephfs --monhost 192.168.101.1,192.168.101.2,192.168.101.3
# 3. Falls RBD-Storage vorhanden:
pvesm set data --monhost 192.168.101.1,192.168.101.2,192.168.101.3
# 4. Dann Remount auf JEDEM Node:
umount /mnt/pve/cephfs
mount /mnt/pve/cephfs
Hinweis: Die Storage-Namen (
cephfs,data) können bei jedem Setup anders heißen. Mitpvesm statuswerden alle konfigurierten Storages angezeigt.
Hinweise
- Das Tool muss als root ausgeführt werden
- Alle Nodes müssen das gleiche Root-Passwort haben
- VMs/CTs werden nicht automatisch migriert oder gestoppt — das Netzwerk wird im laufenden Betrieb geändert
- Nach der Migration sollten VM-Netzwerke (Bridges in VM-Configs) geprüft werden, falls diese sich auf spezifische IPs beziehen
- Die Emergency-IPs (
ip addr add) sind temporär und werden durchifreload -aautomatisch entfernt - Bridges werden automatisch erkannt — keine manuelle Angabe nötig
- Beim Netzwerk-Reload werden Remote-Nodes zuerst umgestellt (fire-and-forget), der lokale Node zuletzt — so schneidet sich das Tool nicht selbst die Verbindung ab
- Getestet mit Proxmox VE 7.x und 8.x
Projektstruktur
proxmox-cluster-network-changer/
├── main.py # Entry-Point, CLI, .env-Loader
├── discovery.py # Phase 1: Cluster-Config lesen & parsen
├── planner.py # Phase 2: IP-Mapping, neue Configs generieren
├── backup.py # Phase 3: Backup aller Configs
├── migrator.py # Phase 4: Migration durchführen (7 Schritte)
├── verifier.py # Phase 5: Post-Migration Checks
├── rescue.py # Rescue-Netzwerk (Emergency Mode)
├── ssh_manager.py # SSH via sshpass (Passwort-Auth)
├── config_parser.py # Parser für Corosync/Ceph/Network Configs
├── models.py # Dataclasses (NodeInfo, CorosyncConfig, etc.)
├── .env.example # Vorlage für SSH-Credentials
└── requirements.txt # Keine externen Dependencies
Typische Szenarien
Szenario 1: Normaler Umzug (alles funktioniert noch)
echo 'SSH_PASSWORD=dein-passwort' > .env
python3 main.py --dry-run # Erst testen
python3 main.py # Dann ausführen
Szenario 2: Ein Node wurde bereits manuell geändert
PVE01 hat schon die neue IP, PVE02-04 noch die alte. Kein SSH möglich.
# Option A: Rescue-Befehle anzeigen und manuell ausführen
python3 main.py --rescue-commands 10.99.99.0/24
# -> Befehle auf allen Nodes per IPMI/KVM eingeben
# -> Dann normal starten:
python3 main.py --rescue
# Option B: Einfach starten, das Tool fragt automatisch
python3 main.py
# -> "3 Node(s) nicht erreichbar. Rescue-Netzwerk einrichten? [J/n]"
Szenario 3: Nur Discovery (schauen was los ist)
python3 main.py --discover
Szenario 4: Cluster komplett kaputt, kein Quorum
python3 main.py --rescue
# Das Tool:
# 1. Richtet Emergency-Netzwerk ein
# 2. Liest Configs über Emergency-IPs
# 3. Migriert alles
# 4. Erzwingt Quorum mit 'pvecm expected 1'
# 5. Schreibt Ceph-Config direkt (nicht über /etc/pve)
# 6. Räumt Emergency-IPs auf
