Deuxième mode de réplication, séparé de la réplication cluster vers cluster
(sélecteur « Clusters (API) | Nœuds (fichiers) » en haut de page) : un profil
réplique la configuration système d'un nœud maître vers des nœuds cibles.
- réseau par /nodes/{node}/network (interfaces.new puis rechargement), adresses
et passerelles propres à chaque nœud, mapping des noms d'interfaces par cible ;
DNS par /nodes/{node}/dns ; multipath.conf, wwids (ajout seul), chrony,
sysctl.d, interfaces.d (hors sdn) par SSH
- découverte des nœuds (/cluster/status), accès SSH par nœud (mot de passe du
cluster ou propre), clé d'hôte épinglée, contrôle du nom du nœud
- dry-run avec diff des fichiers ; apply (admin) avec contrôle SHA-256,
sauvegarde et restore.sh sur le nœud, écriture atomique, rechargements,
restauration si un rechargement échoue, timer systemd de restauration si le
nœud est injoignable après le rechargement du réseau, confirmation tapée
- vue Nœuds et profils, journal séparé par mode, démo avec nœuds simulés
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
11 KiB
Proposition : réplication de fichiers système nœud à nœud (SSH)
Statut : validée par Cédric le 2026-10-23 (liste v1, API dès que possible, identifiants
SSH hérités du cluster avec surcharge par nœud), puis implémentée. Écart avec la
proposition : /etc/network/interfaces passe par l'API PVE (/nodes/{node}/network) et
non par fichier, et le DNS est ajouté par l'API (/nodes/{node}/dns). Le fonctionnement
réel est décrit dans le README (« Réplication de nœuds »).
Deuxième mode de réplication, séparé de la réplication cluster à cluster (API) : un nœud maître et un ou plusieurs nœuds cibles (même cluster ou non), fichiers lus et écrits en SSH root. Même moteur : lecture, normalisation, diff, plan, apply, vérification.
Constat dans le code actuel : l'accès SSH est défini par cluster, sur un seul
hôte (SSHHost, internal/config/config.go:33). Il faut le passer par
nœud : nœuds découverts par l'API (GET /cluster/status, champ ip), identifiants
root hérités du cluster et surchargeables par nœud, clé d'hôte épinglée par nœud
(même TOFU que maintenant).
1. Fichiers candidats
Légende : 🟢 v1 recommandée, 🟡 v1 possible avec garde-fous, 🔴 exclu.
| Fichier | Intérêt | Risques | Propre au nœud (mapper / exclure) | Rechargement |
|---|---|---|---|---|
🟢 /etc/network/interfaces |
bonds, VLAN, bridges, MTU identiques partout | perte d'accès au nœud ; noms de NIC différents d'un nœud à l'autre | address, gateway, hwaddress, IP de management, éventuellement noms de NIC (nic1 maître ↔ enp65s0f0 cible) |
ifreload -a |
🟢 /etc/network/interfaces.d/* |
idem | interfaces.d/sdn est généré par le SDN PVE |
exclure sdn d'office |
ifreload -a |
🟢 /etc/multipath.conf |
defaults, blacklist, devices identiques sur tout le cluster |
erreur de syntaxe = chemins perdus | rien en général | multipathd reconfigure |
🟢 /etc/multipath/wwids |
mêmes LUN vues par tous les nœuds | ajouter un WWID local (disque système) par erreur | mode additif seulement, jamais de suppression | multipathd reconfigure |
🟡 /etc/multipath/bindings |
alias mpathX identiques sur tous les nœuds (important si LVM partagé référence les noms) |
renommer un alias en service | additif seulement, conflit d'alias = bloquant | multipathd reconfigure |
🟢 /etc/chrony/chrony.conf (+ sources.d) |
mêmes sources NTP | faible | rien | systemctl restart chrony |
🟡 /etc/systemd/timesyncd.conf |
si chrony absent | faible | rien | systemctl restart systemd-timesyncd |
🟢 /etc/sysctl.d/*.conf |
tuning réseau / mémoire homogène | réglage inadapté au matériel | rien ; ne jamais toucher les fichiers des paquets (/usr/lib/sysctl.d) |
sysctl --system |
🟡 /etc/modprobe.d/*.conf |
options ZFS (zfs_arc_max), blacklist de modules |
effet au reboot seulement ; ARC dépend de la RAM | zfs_arc_max à surcharger par nœud |
update-initramfs -u, redémarrage requis (signalé, jamais fait) |
🟡 /etc/apt/sources.list.d/*.sources |
mêmes dépôts (enterprise / no-subscription / ceph) | dépôt enterprise sans abonnement sur la cible | rien | aucun (pas d'apt update automatique) |
🟡 /etc/lvm/lvm.conf |
global_filter pour iSCSI / multipath |
filtre faux = volumes invisibles | rien en général | aucun ; vérification pvs avant / après |
🟡 /etc/iscsi/iscsid.conf |
timeouts, node.startup |
contient les secrets CHAP | secrets chiffrés au repos, jamais affichés en clair dans le diff | systemctl restart iscsid (signalé) |
🟡 /etc/vzdump.conf |
défauts de sauvegarde par nœud | faible | tmpdir éventuellement |
aucun |
🟡 /etc/postfix/main.cf |
relais SMTP des notifications | faible | myhostname |
postfix reload |
🔵 /etc/resolv.conf |
DNS identiques | écrasé par DHCP / resolvconf | rien | aucun. Existe aussi en API (/nodes/{node}/dns), à préférer : à vérifier dans l'API viewer |
🔵 /etc/hosts |
résolution des nœuds entre eux | ligne du nœud lui-même ; corosync dépend du nom | ligne 127.0.1.1 et la ligne du nœud cible |
aucun. Existe aussi en API (/nodes/{node}/hosts), à vérifier |
🔴 /etc/pve/* (dont corosync.conf) |
déjà partagé par pmxcfs dans un cluster | casser le cluster | ||
🔴 /etc/corosync/*, /etc/hostname, /etc/machine-id, clés SSH d'hôte, /etc/iscsi/initiatorname.iscsi |
identité unique du nœud | |||
🔴 /etc/frr/* |
géré par le SDN EVPN (hors périmètre) | |||
🔴 /etc/kernel/cmdline, /etc/default/grub |
démarrage du nœud | v2 éventuellement |
🔵 = je propose de passer par l'API PVE plutôt que par le fichier (déjà le modèle du reste de l'outil).
Ma recommandation v1 : interfaces (+ interfaces.d hors sdn), multipath.conf, wwids, chrony.conf, sysctl.d. Le reste en v1.1 une fois le mécanisme éprouvé.
2. Modèle
Profil de réplication : un nœud maître, des nœuds cibles, une liste de fichiers, et par fichier des règles.
Règles par fichier, deux niveaux :
- Adaptateur structuré pour
interfaces(stanzasiface) etmultipath.conf(sections) : politique par champ comme pour l'API (sync / ignorer / surcharger par cible). Exemple :iface vmbr0 / address= surcharger, valeur par cible. - Mode texte pour les autres : diff ligne à ligne, avec des lignes protégées (regex) conservées telles quelles sur la cible, et des variables (
{{hostname}},{{ip}}, valeurs saisies par cible). - Mapping de noms de NIC par cible (
eno1→enp1s0f0), appliqué avant le diff.
Déroulé :
- Lecture :
cat+sha256sum+ propriétaire et droits, sur le maître et chaque cible. - Diff : diff unifié par fichier et par cible, après application des règles. Statut : à jour / écarts / bloquant (ex. NIC du maître absente sur la cible, alias multipath en conflit).
- Dry-run (par défaut) : rien n'est écrit, on affiche le fichier final exact et la commande de rechargement.
- Apply, après confirmation explicite (comme le SDN), un nœud à la fois, arrêt au premier échec :
- le hash de la cible doit être celui lu au plan (sinon : modifié entre-temps, on refuse) ;
- sauvegarde sur le nœud (
/var/lib/pve-confsync/backup/<chemin>.<horodatage>) et en base (SQLite, historique) ; - validation avant écriture quand l'outil existe :
multipath -tsur un fichier temporaire, contrôle de syntaxe ifupdown2 (ifup --no-act, option exacte à vérifier) ; - écriture atomique (fichier temporaire +
mv), propriétaire et droits conservés ; - rechargement (colonne de droite du tableau), seulement si coché ;
- vérification : relecture du hash, et pour le réseau, reconnexion SSH.
- Filet de sécurité réseau : avant
ifreload -a, on programme sur le nœud une restauration automatique (systemd-run --on-active=120squi remet la sauvegarde et relanceifreload -a). Si l'outil se reconnecte en SSH dans le délai, il annule la restauration. Sinon le nœud revient seul à l'ancienne config. - Suppression : jamais par défaut. Un fichier absent du maître n'est pas supprimé sur la cible sauf option explicite (cohérent avec le mode additif du reste).
Journal et audit : chaque exécution (profil, nœud, fichier, hash avant / après, sauvegarde, sortie du rechargement) dans le journal existant, avec un type « Nœuds ».
Droits : opérateur = dry-run, admin = apply (le SSH root est le droit le plus fort de l'outil).
3. Maquette de l'interface
Un sélecteur en tête sépare les deux modes. Chaque mode garde les onglets Écarts / Profils (ou Clusters) / Journal.
┌──────────────────────────────────────────────────────────────────────┐
│ pve-confsync [ Clusters (API) | Nœuds (fichiers) ] 👤 ⏻ │
├──────────────────────────────────────────────────────────────────────┤
│ [Écarts] [Profils] [Journal] Profil: [Réseau stockage ▾] 2 écarts │
│ [Dry-run global] [Appliquer]│
├────────────────────────────┬─────────────────────────────────────────┤
│ MAÎTRE pve1 (lab-a) │ pve2 · /etc/network/interfaces ÉCARTS │
│ │ │
│ CIBLES │ auto bond0 │
│ ┌────────────────────────┐ │ iface bond0 inet manual │
│ │ pve2 (lab-a) ÉCARTS │ │ - bond-mode active-backup │
│ │ interfaces ✎ 3 │ │ + bond-mode 802.3ad │
│ │ multipath.conf ✓ │ │ + bond-xmit-hash-policy layer3+4 │
│ │ chrony.conf ✓ │ │ iface vmbr0 inet static │
│ └────────────────────────┘ │ address 10.0.0.12/24 🔒 surchargé │
│ ┌────────────────────────┐ │ bridge-ports bond0 │
│ │ pve3 (lab-a) À JOUR │ │ │
│ └────────────────────────┘ │ Après écriture : ifreload -a ☑ │
│ ┌────────────────────────┐ │ Restauration auto si perte SSH : 120 s │
│ │ pve7 (lab-b) BLOQUANT │ │ │
│ │ interfaces NIC eno2 │ │ [Dry-run] [Appliquer sur pve2] │
│ │ absente, à mapper │ │ │
│ └────────────────────────┘ │ │
└────────────────────────────┴─────────────────────────────────────────┘
Onglet Profils : maître, cibles (nœuds découverts par cluster, cases à cocher), fichiers (cases parmi la liste du §1), règles par fichier (champs à surcharger, lignes protégées, mapping de NIC par cible).
Fenêtre de confirmation d'apply : liste des nœuds dans l'ordre, fichiers, commandes de rechargement, avertissements (« redémarrage requis », « accès réseau »), saisie du nom du nœud pour confirmer quand interfaces est concerné.
Questions ouvertes
- Liste v1 : celle recommandée ci-dessus, ou plus large ?
resolv.confethostspar l'API plutôt que par fichier : d'accord ?- Identifiants SSH : hérités du cluster avec surcharge par nœud, d'accord ?