Files
pve-confsync/docs/proposition-replication-noeuds.md
T
cedricandClaude Opus 5.5 1e667ce8b9 Réplication de nœuds : réseau et DNS par l'API, multipath, chrony, sysctl par SSH
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>
2026-10-23 20:29:55 +02:00

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 (stanzas iface) et multipath.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é :

  1. Lecture : cat + sha256sum + propriétaire et droits, sur le maître et chaque cible.
  2. 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).
  3. Dry-run (par défaut) : rien n'est écrit, on affiche le fichier final exact et la commande de rechargement.
  4. 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 -t sur 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.
  5. Filet de sécurité réseau : avant ifreload -a, on programme sur le nœud une restauration automatique (systemd-run --on-active=120s qui remet la sauvegarde et relance ifreload -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.
  6. 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

  1. Liste v1 : celle recommandée ci-dessus, ou plus large ?
  2. resolv.conf et hosts par l'API plutôt que par fichier : d'accord ?
  3. Identifiants SSH : hérités du cluster avec surcharge par nœud, d'accord ?