325 lines
10 KiB
Markdown
325 lines
10 KiB
Markdown
# 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
|
|
- SSH-Key-Sicherung vor pve-cluster-Stop (verhindert SSH-Abbrüche)
|
|
- 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
|
|
- SSH-Zugriff (Key-basiert) zu allen anderen Cluster-Nodes (oder Konsolenzugriff für Rescue-Modus)
|
|
- Keine externen Python-Pakete nötig (nur stdlib)
|
|
|
|
## Installation
|
|
|
|
```bash
|
|
# 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
|
|
```
|
|
|
|
## Verwendung
|
|
|
|
### Aktuelle Konfiguration anzeigen (Discovery)
|
|
|
|
```bash
|
|
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)
|
|
|
|
```bash
|
|
python3 main.py --dry-run
|
|
```
|
|
|
|
Durchläuft den kompletten Prozess, zeigt alle geplanten Änderungen an, schreibt aber nichts.
|
|
|
|
### Migration durchführen
|
|
|
|
```bash
|
|
python3 main.py
|
|
```
|
|
|
|
Das Tool führt interaktiv durch den Prozess:
|
|
|
|
```
|
|
=== 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-key PFAD` | Pfad zum SSH-Key (Standard: Default-Key) |
|
|
| `--ssh-port PORT` | SSH-Port (Standard: 22) |
|
|
|
|
## 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 |
|
|
|
|
## Migrationsablauf (Phase 4)
|
|
|
|
1. Neue Konfigurationen werden auf alle Nodes verteilt (Staging)
|
|
2. SSH-Keys sichern (`/etc/pve/priv/authorized_keys` → `~/.ssh/authorized_keys`)
|
|
3. Corosync wird auf allen Nodes gestoppt
|
|
4. pve-cluster (pmxcfs) wird gestoppt → `/etc/pve` unmounted
|
|
5. Corosync-Config wird direkt geschrieben (`/etc/corosync/corosync.conf`)
|
|
6. `/etc/hosts` wird aktualisiert
|
|
7. `/etc/network/interfaces` wird aktualisiert + `ifreload -a` (alle Bridges)
|
|
8. Services starten, Quorum abwarten, Ceph aktualisieren, SSH-Keys aufräumen
|
|
|
|
## 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
|
|
|
|
```bash
|
|
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
|
|
|
|
```bash
|
|
python3 main.py --rescue
|
|
```
|
|
|
|
oder einfach starten — wenn Nodes nicht erreichbar sind, wird automatisch gefragt:
|
|
|
|
```bash
|
|
python3 main.py
|
|
```
|
|
|
|
```
|
|
3 Node(s) nicht erreichbar.
|
|
Rescue-Netzwerk einrichten? [J/n]: j
|
|
```
|
|
|
|
Ablauf:
|
|
1. Du gibst ein freies Subnetz an (z.B. `10.99.99.0/24`)
|
|
2. Das Tool zeigt für jeden Node den `ip addr add` Befehl
|
|
3. Auf dem lokalen Node wird die IP automatisch gesetzt
|
|
4. Du führst die Befehle auf den anderen Nodes per Konsole aus
|
|
5. Das Tool testet die Verbindung und liest die Configs
|
|
6. Danach läuft die normale Migration
|
|
7. Am Ende werden die Emergency-IPs automatisch 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 1` genutzt, 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)
|
|
|
|
```bash
|
|
# 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
|
|
|
|
1. `pvecm status` — Cluster-Status prüfen
|
|
2. `pvecm expected 1` — Quorum erzwingen (Notfall)
|
|
3. `ceph -s` — Ceph-Status prüfen
|
|
4. `ceph -w` — Ceph-Recovery beobachten
|
|
5. `journalctl -u corosync` — Corosync-Logs prüfen
|
|
6. `journalctl -u pve-cluster` — pmxcfs-Logs prüfen
|
|
|
|
## Hinweise
|
|
|
|
- Das Tool muss als **root** ausgeführt werden
|
|
- SSH-Keys müssen **vorher** zwischen den Nodes eingerichtet sein (bei Proxmox-Clustern standardmäßig der Fall)
|
|
- 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 überleben keinen Reboot — sie werden nur zur SSH-Kommunikation während der Migration genutzt
|
|
- Bridges werden automatisch erkannt — keine manuelle Angabe nötig. Alle betroffenen Bridges (Management, Ceph Public, Ceph Cluster) werden per `ifreload -a` aktualisiert
|
|
- SSH-Keys werden vor dem pve-cluster-Stop gesichert und danach wiederhergestellt, damit SSH während der Migration nicht abbricht
|
|
- Getestet mit Proxmox VE 7.x und 8.x
|
|
|
|
## Projektstruktur
|
|
|
|
```
|
|
proxmox-cluster-network-changer/
|
|
├── main.py # Entry-Point, CLI mit allen Optionen
|
|
├── 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 (8 Schritte)
|
|
├── verifier.py # Phase 5: Post-Migration Checks
|
|
├── rescue.py # Rescue-Netzwerk (Emergency Mode)
|
|
├── ssh_manager.py # SSH-Verbindungen (lokal + remote)
|
|
├── config_parser.py # Parser für Corosync/Ceph/Network Configs
|
|
├── models.py # Dataclasses (NodeInfo, CorosyncConfig, etc.)
|
|
└── requirements.txt # Keine externen Dependencies
|
|
```
|
|
|
|
## Typische Szenarien
|
|
|
|
### Szenario 1: Normaler Umzug (alles funktioniert noch)
|
|
|
|
```bash
|
|
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.
|
|
|
|
```bash
|
|
# 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)
|
|
|
|
```bash
|
|
python3 main.py --discover
|
|
```
|
|
|
|
### Szenario 4: Cluster komplett kaputt, kein Quorum
|
|
|
|
```bash
|
|
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
|
|
```
|