Dawan Proxmox VE — TSSR

Chapitre 3 — Réseau et stockage

Ateliers — chapitre 3

Infrastructure : nœud pxe2<N>1 — carte ens19 pour le pont du cluster ; disques /dev/sdc, /dev/sdd disponibles pour ZFS.

Adressage : votre poste dispose d'un réseau NATé qui lui est propre. Toutes les ressources que vous créez portent une adresse fixe — aucune ne dépend d'un DHCP de la salle.


État du lab en fin de chapitre :

  • Pont du cluster vmbr1 sur ens19 (adresse Corosync 10.<site>.<N+10>.11/24) et bridge isolé vmbr9
  • Pool ZFS miroir datapool (snapshot/rollback validé) intégré comme stockage zfs-vms
  • Disque de la VM 140 déplacé à chaud de local-lvm vers zfs-vms sans perte de ping (atelier 4), puis VM supprimée
  • VLAN et NAT éprouvés sur vmbr9 (atelier 2), puis vmbr9 rendu isolé et conteneurs 311-312 supprimés
  • Serveur NFS dans un conteneur, partage déclaré et sauvegarde écrite (atelier 5) — CT 260 et stockage nfs-partage supprimés

Atelier 1 — Réseau Linux et bridges

Contexte

Tout ce qui se connecte au réseau dans Proxmox — VM, conteneur, cluster — passe par un bridge, un commutateur virtuel logiciel. Le nœud en a déjà un, vmbr0, qui le relie au monde. Savoir lire cette configuration et en créer d'autres est le préalable à tout le reste.

Le réseau isolé pour des VMs entre elles. Et surtout le réseau dédié qu'un cluster exige pour Corosync.

Résultat à obtenir : une lecture claire du réseau existant, et un bridge isolé sans interface physique (pour un réseau interne). Puis vmbr1 monté sur la seconde carte physique, prêt à porter le trafic du cluster.

Les cinq cartes réseau d'un nœud du lab et les ponts de l'atelier

Les cinq cartes de votre nœud, et les trois ponts de l'atelier. vmbr0 existe déjà sur ens18. Vous créez vmbr9, sans carte, puis vmbr1 sur ens19.

Les cartes ens20 à ens22 restent libres. Cliquez sur un pont pour lire son rôle et le résultat obtenu.

Arborescence attendue

/etc/network/interfaces   ← la configuration réseau persistante du nœud
├── vmbr0   ← existant : pont principal, relié à la carte physique + Internet
├── vmbr9   ← à créer : pont ISOLÉ, sans interface physique (réseau interne)
└── vmbr1   ← à créer : pont dédié au cluster, sur ens19, adresse 10.<site>.<N+10>.11/24

Ce que vous devez faire

  1. Explorer l'existant : lister les interfaces et lire la configuration de vmbr0 — quelle carte physique il englobe, quelle adresse il porte.
  2. Créer un bridge isolé, sans interface physique attachée : il servira à faire communiquer des VMs entre elles sans les exposer au réseau.
  3. Créer vmbr1 sur la carte ens19, celle du réseau interne cluster — c'est lui qui portera le réseau Corosync du cluster.

💡 Un bridge sans interface physique = réseau purement interne au nœud. Un bridge avec interface = pont vers le réseau réel. Cette distinction commande toute l'architecture réseau de la formation.

Cliquez pour vous aider

Étape 1 — Explorer le réseau existant

Dans le Shell du nœud (interface web → votre nœud → Shell) :

# Toutes les interfaces, une ligne chacune
ip -br link
ip -br addr show vmbr0   # l'adresse portée par vmbr0
bridge link show   # les ports rattachés aux ponts
# La configuration persistante, telle que Proxmox l'a écrite
cat /etc/network/interfaces

Machine d'exemple : nœud pxe211 (Proxmox VE 9.2.21), construit comme le vôtre : cinq cartes ens18 à ens22. C'est le nœud du stagiaire 1 du site 59 : son vmbr0 est en 10.59.1.11 ; le vôtre est en 10.<site>.<N>.11.

Résultat attendu (extraits) :

ens18            UP             bc:24:11:01:a1:11 <BROADCAST,MULTICAST,UP,LOWER_UP>
ens19            DOWN           bc:24:11:01:b1:11 <BROADCAST,MULTICAST>
ens20            DOWN           bc:24:11:01:c1:11 <BROADCAST,MULTICAST>
ens21            DOWN           bc:24:11:01:d1:11 <BROADCAST,MULTICAST>
ens22            DOWN           bc:24:11:01:e1:11 <BROADCAST,MULTICAST>
vmbr0            UP             10.59.1.11/24 fe80::be24:11ff:fe01:a111/64
2: ens18: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 master vmbr0 state forwarding priority 32 cost 100
auto vmbr0
iface vmbr0 inet static
    address 10.59.1.11/24
    gateway 10.59.1.1
    bridge-ports ens18
    bridge-stp off
    bridge-fd 0

vmbr0 porte l'adresse du nœud ; bridge link show montre sa carte physique, ens18, avec master vmbr0. Les quatre autres cartes sont DOWN : elles mènent aux réseaux internes du lab, encore inutilisés. bridge link show liste aussi des interfaces veth…, tap…, fwbr… : ce sont les cartes des conteneurs et des VM en marche, branchées sur vmbr0 — chaque invité est un port du commutateur virtuel.

Étape 1 bis — Un filet avant de toucher au réseau

Apply Configuration recharge le réseau du nœud à chaud. Une erreur (la carte de vmbr0 reprise par un autre pont, une passerelle en trop) peut vous couper l'accès.

Votre nœud est distant : sans accès physique, personne ne pourrait le rattraper. Avant de créer quoi que ce soit, gardez une copie de la configuration et programmez son retour automatique.

Dans le Shell du nœud (interface web → votre nœud → Shell) :

# Copie de la configuration réseau actuelle, qui fonctionne
cp /etc/network/interfaces /root/interfaces.avant-tp3
# Dans 10 minutes, la remettre en place et recharger le réseau, sauf si on annule avant
systemd-run --on-active=10min --unit=filet-reseau sh -c "cp /root/interfaces.avant-tp3 /etc/network/interfaces && ifreload -a"

Résultat attendu :

Running timer as unit: filet-reseau.timer
Will run service as unit: filet-reseau.service

Si un Apply vous coupait l'accès, il suffirait d'attendre la fin du délai : la configuration d'origine revient, et les ponts ajoutés disparaissent. Sur le lab, avec un délai d'une minute, le fichier a bien été restauré et le pont de test vmbr9 supprimé (Device "vmbr9" does not exist.).

Étape 2 — Créer un bridge supplémentaire isolé

Nœud → Network → Create → Linux Bridge : Name vmbr9, Autostart ✓, Bridge ports (laisser vide — bridge interne isolé), Comment LAB-ISOLE → Create → Apply Configuration.

Dans le Shell du nœud (interface web → votre nœud → Shell) :

# Le nouveau pont existe-t-il ?
ip -br link show vmbr9
# Combien de ports y sont branchés ?
bridge link show | grep -c 'master vmbr9'

Résultat attendu :

vmbr9            UNKNOWN        8e:1d:76:ca:3e:4e <BROADCAST,MULTICAST,UP,LOWER_UP>
0

Aucune ligne master vmbr9 dans bridge link show. Le pont existe sans interface physique : un réseau isolé entre les VM et conteneurs qu'on y branchera.

Désactiver, puis réactiver le pont. L'interface n'a pas de bouton pour cela : la colonne Active de Network ne fait qu'afficher l'état. On passe par le Shell :

Dans le Shell du nœud :

ifdown vmbr9                # désactiver le pont : il disparaît du système
ip -br link show vmbr9      # vérifier
ifup vmbr9                  # le réactiver, d'après /etc/network/interfaces
ip -br link show vmbr9      # vérifier

Résultat attendu (pxe212) :

Device "vmbr9" does not exist.
vmbr9            UNKNOWN        6a:09:e0:40:4f:f9 <BROADCAST,MULTICAST,UP,LOWER_UP>

Désactivé, le pont n'existe plus, et la colonne Active de Network passe à No ; réactivé, il revient. Sa déclaration, elle, reste dans /etc/network/interfaces : c'est Autostart (la ligne auto vmbr9) qui le remonte à chaque démarrage du nœud.

Étape 3 — Créer vmbr1, le pont dédié au cluster

Votre serveur a une seconde carte physique inutilisée. Elle portera le réseau réservé aux échanges du cluster.

Chaque carte de votre nœud mène à un réseau du lab :

Carte Réseau interne Usage
ens18 10.<site>.<N>.0/24 (NAT) déjà sous vmbr0 : gestion, interface web, Internet
ens19 10.<site>.<N+10>.0/24 cluster (Corosync) — cet atelier
ens20 10.<site>.<N+20>.0/24 Ceph, réseau du cluster
ens21 10.<site>.<N+30>.0/24 Ceph, réseau public
ens22 10.<site>.<N+40>.0/24 migration des VM

Lisez la liste réelle avant de choisir une carte. Sur les nœuds du lab, les cartes s'appellent ens18 à ens22. La carte à prendre est celle qui n'apparaît dans la colonne Ports/Slaves d'aucun pont.

Dans le Shell du nœud (interface web → votre nœud → Shell) :

# Lister les cartes et leur etat. Celle qui porte deja vmbr0 est prise ;
# une carte "DOWN" sans bridge associe est celle que vous cherchez.
ip -br link

# La meme lecture, cote Proxmox, avec la correspondance nom <-> bridge
cat /etc/network/interfaces

Nœud → Network → Create → Linux Bridge :

Champ Valeur
Name vmbr1
IPv4/CIDR l'adresse Corosync de votre nœud : 10.<site>.<N+10>.11/24
Gateway (IPv4) (laisser vide)
Bridge ports ens19
Autostart ✓
Comment COROSYNC

Les trois nœuds partageront ce réseau, une adresse chacun, avec le même dernier octet que sur vmbr0 :

Nœud IP Corosync Exemple : stagiaire 1 du site 59 (le lab d'exemple)
pxe2<N>1 10.<site>.<N+10>.11/24 10.59.11.11/24
pxe2<N>2 10.<site>.<N+10>.12/24 10.59.11.12/24
pxe2<N>3 10.<site>.<N+10>.13/24 10.59.11.13/24

Le troisième octet vaut votre numéro de stagiaire plus 10 : stagiaire 4 du site 59 → 10.59.14.x. C'est le même calcul pour les trois nœuds — c'est ce qui les met sur le même réseau ; seul le dernier octet change.

Fenêtre Create Linux Bridge pour vmbr1

Les valeurs du lab : Name vmbr1, IPv4/CIDR 10.59.11.11/24, Bridge ports ens19, Comment COROSYNC, et Gateway laissé vide. Autostart est coché par défaut.

→ Create, puis Apply Configuration.

Onglet Network avant Apply Configuration

Les deux ponts sont créés, mais pas encore actifs : colonne Active à No. Le panneau Pending changes montre la différence entre /etc/network/interfaces et /etc/network/interfaces.new, le fichier que Proxmox a préparé. Rien n'est appliqué tant que vous n'avez pas cliqué Apply Configuration (ou redémarré le nœud).

Pas de passerelle sur vmbr1. Ce réseau ne sort pas : il ne reliera que les trois serveurs entre eux. Une seconde passerelle sur la machine casserait le routage par défaut, et vous perdriez l'accès à l'interface.

Dans le Shell du nœud (interface web → votre nœud → Shell) :

# Le pont du cluster, son adresse, puis sa configuration persistante
ip -br addr show vmbr1
grep -A 6 vmbr1 /etc/network/interfaces   # les lignes de vmbr1 dans le fichier réseau
bridge link show | grep ens19   # la carte ens19, rattachée à vmbr1

Résultat attendu :

vmbr1            UP             10.59.11.11/24 fe80::be24:11ff:fe01:b111/64
auto vmbr1
iface vmbr1 inet static
    address 10.59.11.11/24
    bridge-ports ens19
    bridge-stp off
    bridge-fd 0
#COROSYNC
3: ens19: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 master vmbr1 state forwarding priority 32 cost 100

vmbr1 est UP, avec son adresse, sur ens19 ; bridge link show montre désormais ens19 … master vmbr1. Le pont n'a encore personne à qui parler : votre serveur est seul à ce stade.

Onglet Network après Apply Configuration

Après Apply Configuration, le panneau Pending changes a disparu. vmbr0 (sur ens18) et vmbr1 (sur ens19, 10.59.11.11/24) portent chacun une adresse, et la colonne Active est passée à Yes, pour ens19 aussi ; vmbr9 n'a ni port ni adresse.

Ne confondez pas les deux ponts que vous venez de créer. vmbr9 isole (aucun port physique, aucune adresse) ; vmbr1 relie les serveurs entre eux (seconde carte + adresse Corosync). Vider vmbr1 de son port couperait le cluster.

Tout répond : annulez le filet, sinon il remettra l'ancienne configuration et supprimera vos deux ponts à la fin du délai.

Dans le Shell du nœud :

# Arrêter le minuteur : la restauration programmée n'aura pas lieu
systemctl stop filet-reseau.timer
# Vérifier qu'il n'est plus armé
systemctl is-active filet-reseau.timer

Résultat attendu : inactive.


Atelier 2 — VLAN et NAT sur le pont isolé

Contexte

Le pont vmbr9 de l'atelier 1 isole ses invités. Cet atelier le fait travailler de deux façons, celles du cours §2.

D'abord il segmente : rendu VLAN-aware, il sépare deux conteneurs branchés sur lui selon leur VLAN. Puis il fait sortir : il devient la passerelle d'un réseau privé, que le nœud traduit vers l'extérieur par NAT.

Tout se passe sur vmbr9. Le pont vmbr0, qui porte votre accès au nœud, n'est jamais modifié.

Résultat à obtenir : deux conteneurs qui se voient dans le même VLAN et ne se voient plus dans deux VLAN différents. Puis un conteneur du réseau privé 10.0.0.0/24 qui sort par le NAT du nœud, avec la preuve que c'est bien la règle MASQUERADE qui le permet. Enfin vmbr9 rendu à son état isolé.

Atelier 2 : VLAN et NAT sur le pont vmbr9

Le schéma suit vmbr9 de la copie de sécurité au nettoyage. Cliquez sur chaque bloc pour les commandes et ce qu'elles prouvent.

Arborescence attendue

Nœud pxe2<N>1
└── vmbr9   ← VLAN-aware, puis passerelle 10.0.0.1/24 avec NAT vers vmbr0
    ├── CT 311 « ct-vlan311 »   10.0.0.11/24   VLAN 10, puis sans VLAN, passerelle 10.0.0.1
    └── CT 312 « ct-vlan312 »   10.0.0.12/24   VLAN 10, puis VLAN 20
(les deux conteneurs et la configuration de l'atelier sont retirés à la fin)

Ce que vous devez faire

  1. Garder une copie de /etc/network/interfaces, comme à l'atelier 1.
  2. Rendre vmbr9 VLAN-aware.
  3. Créer deux conteneurs sur vmbr9, dans le VLAN 10, et vérifier qu'ils se joignent. Puis passer le second dans le VLAN 20 et constater qu'ils ne se joignent plus.
  4. Faire de vmbr9 une passerelle NATée : adresse 10.0.0.1/24, routage et règle MASQUERADE attachés au pont (cours §2.4).
  5. Sortir par le NAT depuis le premier conteneur, sans VLAN : joindre la passerelle de votre vmbr0, puis une adresse extérieure. Retirer la règle, refaire le test, la remettre.
  6. Nettoyer : conteneurs supprimés, vmbr9 rendu isolé, règle NAT et routage retirés.
Cliquez pour vous aider

Machine d'exemple : nœud pxe211 (Proxmox VE 9.2.21), avec vmbr9 dans l'état de fin d'atelier 1. Son vmbr0 est en 10.59.1.11, sa passerelle en 10.59.1.1 ; chez vous, 10.<site>.<N>.11 et 10.<site>.<N>.1. Les adresses 10.0.0.x sont internes à vmbr9 : elles sont les mêmes chez vous.

Étape 1 — Une copie de la configuration réseau

Dans le Shell du nœud (interface web → votre nœud → Shell) :

cp /etc/network/interfaces /root/interfaces.avant-atelier2   # l'état de fin d'atelier 1, pour le nettoyage
cat /proc/sys/net/ipv4/ip_forward                            # le routage du nœud avant l'atelier : notez la valeur

Résultat attendu : 0 : le nœud ne route pas. L'étape 4 l'activera, l'étape 6 remettra la valeur notée.

Étape 2 — Rendre vmbr9 VLAN-aware

Via l'interface : votre nœud → System → Network → vmbr9 → Edit → cocher VLAN aware → OK → Apply Configuration.

En ligne de commande, ce sont les deux lignes du cours §2.1, ajoutées au bloc de vmbr9 dans /etc/network/interfaces (avec nano), puis ifreload -a :

auto vmbr9
iface vmbr9 inet manual
    bridge-ports none
    bridge-stp off
    bridge-fd 0
    bridge-vlan-aware yes
    bridge-vids 2-4094
#LAB-ISOLE

Dans le Shell du nœud :

ifreload -a                    # appliquer
bridge vlan show dev vmbr9     # les VLAN que le pont connaît

Résultat attendu :

port              vlan-id
vmbr9             1 PVID Egress Untagged

Le pont lui-même est dans le VLAN 1, sans étiquette : c'est son VLAN natif. Les VLAN 2 à 4094 lui sont permis (bridge-vids) ; ils apparaîtront avec les ports qui les utilisent.

Étape 3 — Deux conteneurs, un VLAN, puis deux

Via l'interface : Create CT, deux fois, avec le modèle Debian 13 du chapitre 1 :

Champ CT 311 CT 312
CT ID / Hostname 311 / ct-vlan311 312 / ct-vlan312
Disk / Memory 2 Gio / 256 Mio 2 Gio / 256 Mio
Network → Bridge / VLAN Tag vmbr9 / 10 vmbr9 / 10
Network → IPv4 Static, 10.0.0.11/24, sans passerelle Static, 10.0.0.12/24, sans passerelle

Dans le Shell du nœud :

# Les deux conteneurs, dans le VLAN 10 de vmbr9 (nesting=1 : requis par le systemd de Debian 13)
pct create 311 local:vztmpl/debian-13-standard_13.6-1_amd64.tar.zst --hostname ct-vlan311 --password dawan \
  --rootfs local-lvm:2 --memory 256 --unprivileged 1 --features nesting=1 \
  --net0 name=eth0,bridge=vmbr9,ip=10.0.0.11/24,tag=10
# le second, même VLAN
pct create 312 local:vztmpl/debian-13-standard_13.6-1_amd64.tar.zst --hostname ct-vlan312 --password dawan \
  --rootfs local-lvm:2 --memory 256 --unprivileged 1 --features nesting=1 \
  --net0 name=eth0,bridge=vmbr9,ip=10.0.0.12/24,tag=10
pct start 311                               # démarrer le premier
pct start 312                               # puis le second
pct exec 311 -- ping -c 2 -W 2 10.0.0.12    # même VLAN
bridge vlan show | grep -A1 veth            # le VLAN de chaque port

Résultat attendu :

2 packets transmitted, 2 received, 0% packet loss, time 1003ms
veth200i0         1 PVID Egress Untagged
fwbr200i0         1 PVID Egress Untagged
--
veth311i0         10 PVID Egress Untagged
veth312i0         10 PVID Egress Untagged

Failed to create the network au démarrage : vmbr9 n'est pas VLAN-aware. Sur le lab, avec un conteneur étiqueté tag=10 sur un vmbr9 resté sans l'option :

run_buffer: 569 Script exited with status 255
lxc_create_network_priv: 3731 Success - Failed to create network device
lxc_spawn: 2032 Failed to create the network
startup for container '311' failed

L'étape 2 n'a pas pris effet : case VLAN aware cochée sans Apply Configuration, ou fichier modifié sans ifreload -a. Vérifiez avec grep -A7 "iface vmbr9" /etc/network/interfaces : les lignes bridge-vlan-aware yes et bridge-vids 2-4094 doivent y être.

Les lignes présentes ne suffisent pas : cat /sys/class/net/vmbr9/bridge/vlan_filtering dit si le pont en marche les applique (sur le lab : 0 tant que ifreload -a n'a pas été lancé, 1 après). Appliquez, puis relancez pct start 311; pct start 312 : sur le lab, le conteneur a alors démarré.

Si le message est bridge 'vmbr9' does not exist, c'est le pont lui-même qui manque : ifup vmbr9 (atelier 1, étape 2).

Dans le résultat, les deux premières lignes sont le CT 200 du chapitre 1, branché sur vmbr0 : ses ports sont dans le VLAN 1, celui par défaut. Si votre nœud porte d'autres conteneurs, leurs ports apparaissent de la même façon.

Chaque conteneur de l'atelier est un port du pont, dans le VLAN 10 : ils se joignent. Egress Untagged : le pont retire l'étiquette avant de livrer la trame, le conteneur ne la voit jamais (cours §2.2).

Sans nesting=1, pct create avertit : WARN: Systemd 257 detected. You may need to enable nesting. L'assistant de l'interface coche Nesting d'office.

Passez maintenant le CT 312 dans le VLAN 20 : CT 312 → Network → net0 → Edit → VLAN Tag 20 → OK. En ligne de commande, recopiez l'adresse MAC (pct config 312 | grep net0) : sans hwaddr=, pct set en tire une nouvelle.

Dans le Shell du nœud :

pct set 312 --net0 name=eth0,bridge=vmbr9,hwaddr=<MAC-du-312>,ip=10.0.0.12/24,tag=20   # le 312 dans le VLAN 20
pct exec 311 -- ping -c 2 -W 2 10.0.0.12    # VLAN 10 vers VLAN 20
bridge vlan show | grep -A1 veth            # le VLAN de chaque port

Résultat attendu :

2 packets transmitted, 0 received, 100% packet loss, time 1003ms
veth311i0         10 PVID Egress Untagged
veth312i0         20 PVID Egress Untagged

Même pont, même sous-réseau, même nœud : seul le VLAN diffère, et plus rien ne passe. C'est la segmentation du cours §2.1, sans un câble de plus.

Étape 4 — vmbr9 devient une passerelle NATée

Via l'interface : vmbr9 → Edit → IPv4/CIDR 10.0.0.1/24 (sans passerelle) → OK. Les règles de NAT, elles, n'ont pas de champ dans l'interface : elles s'ajoutent au fichier.

Dans le Shell du nœud, avec nano /etc/network/interfaces, le bloc de vmbr9 devient celui du cours §2.4 :

auto vmbr9
iface vmbr9 inet static
    address 10.0.0.1/24
    bridge-ports none
    bridge-stp off
    bridge-fd 0
    bridge-vlan-aware yes
    bridge-vids 2-4094
    post-up   echo 1 > /proc/sys/net/ipv4/ip_forward
    post-up   iptables -t nat -A POSTROUTING -s 10.0.0.0/24 -o vmbr0 -j MASQUERADE
    post-down iptables -t nat -D POSTROUTING -s 10.0.0.0/24 -o vmbr0 -j MASQUERADE
#LAB-ISOLE

Dans le Shell du nœud :

ifreload -a                          # appliquer
ip -br addr show vmbr9               # l'adresse du pont
iptables -t nat -S POSTROUTING       # la règle posée par post-up
cat /proc/sys/net/ipv4/ip_forward    # le routage activé

Résultat attendu :

vmbr9            UP             10.0.0.1/24 fe80::6c52:eff:feb3:deb3/64
-P POSTROUTING ACCEPT
-A POSTROUTING -s 10.0.0.0/24 -o vmbr0 -j MASQUERADE
1

Étape 5 — Sortir par le NAT

Le CT 311 sort du VLAN 10 et prend la passerelle : CT 311 → Network → net0 → Edit → VLAN Tag vide, Gateway (IPv4) 10.0.0.1 → OK. L'adresse du pont est portée par son VLAN natif, le VLAN 1 sans étiquette (étape 2). On retire donc l'étiquette du CT 311 pour le mettre sur le même segment que sa passerelle.

Dans le Shell du nœud :

pct set 311 --net0 name=eth0,bridge=vmbr9,hwaddr=<MAC-du-311>,ip=10.0.0.11/24,gw=10.0.0.1   # ou par l'interface
pct exec 311 -- ping -c 2 -W 2 10.0.0.1             # la passerelle : le pont
pct exec 311 -- ping -c 2 -W 2 10.<site>.<N>.1      # la passerelle de votre vmbr0, de l'autre côté du NAT
pct exec 311 -- ping -c 2 -W 2 1.1.1.1              # une adresse extérieure
iptables -t nat -L POSTROUTING -v -n | grep MASQUERADE   # le compteur de la règle

Résultat attendu : 0% packet loss pour les trois, puis :

    2   168 MASQUERADE  all  --  *      vmbr0   10.0.0.0/24          0.0.0.0/0

Le compteur a compté 2 paquets : un par connexion traduite, les deux pings vers l'extérieur. Le premier paquet d'une connexion passe par la règle ; les suivants suivent la traduction déjà établie.

La contre-épreuve : la règle retirée, puis remise.

Dans le Shell du nœud :

iptables -t nat -D POSTROUTING -s 10.0.0.0/24 -o vmbr0 -j MASQUERADE   # retirer la règle
pct exec 311 -- ping -c 2 -W 2 1.1.1.1                                  # sans la règle
iptables -t nat -A POSTROUTING -s 10.0.0.0/24 -o vmbr0 -j MASQUERADE   # la remettre
pct exec 311 -- ping -c 2 -W 2 1.1.1.1                                  # avec la règle

Résultat attendu : 2 packets transmitted, 0 received, 100% packet loss, puis 0% packet loss : c'est bien la traduction d'adresse qui fait sortir le réseau privé.

Si 1.1.1.1 ne répond pas même avec la règle, le réseau autour de votre nœud ne route peut-être pas vers Internet (cours §2.4). La passerelle de votre vmbr0 et le compteur de la règle suffisent alors à prouver le NAT.

Étape 6 — Nettoyer

Dans le Shell du nœud :

pct stop 311                                              # arrêter le premier conteneur
pct destroy 311 --purge                                   # le supprimer
pct stop 312                                              # puis le second
pct destroy 312 --purge                                   # le supprimer
cp /root/interfaces.avant-atelier2 /etc/network/interfaces   # vmbr9 tel qu'à la fin de l'atelier 1
ifreload -a                                               # appliquer
iptables -t nat -S POSTROUTING                            # la règle est-elle partie ?
cat /proc/sys/net/ipv4/ip_forward                         # et le routage ?

Résultat attendu :

-P POSTROUTING ACCEPT
-A POSTROUTING -s 10.0.0.0/24 -o vmbr0 -j MASQUERADE
1

ifreload -a n'exécute pas les post-down d'une configuration qu'on a retirée. La règle MASQUERADE et le routage restent actifs après le retour au fichier d'origine, vu ci-dessus. Retirez-les à la main.

Dans le Shell du nœud :

iptables -t nat -D POSTROUTING -s 10.0.0.0/24 -o vmbr0 -j MASQUERADE   # retirer la règle
echo 0 > /proc/sys/net/ipv4/ip_forward    # la valeur notée à l'étape 1 (0 sur le lab)
iptables -t nat -S POSTROUTING            # → -P POSTROUTING ACCEPT, seul

ip -br link show vmbr9 répond alors DOWN et NO-CARRIER : un pont sans port ni invité n'a pas de lien. Il redevient UP dès qu'un invité s'y branche.


Atelier 3 — Pool ZFS en miroir

Contexte

ZFS est bien plus qu'un système de fichiers : il réunit la gestion des volumes, le RAID logiciel, la compression transparente et les snapshots instantanés en une seule couche. Sur ce nœud, deux disques lui sont réservés (sdc et sdd) pour un miroir — l'équivalent d'un RAID1, où chaque donnée existe en double.

Vous allez le construire de bout en bout : le pool en miroir, un dataset compressé, un snapshot avec retour arrière, puis son intégration comme stockage Proxmox.

Résultat à obtenir : un pool ZFS en miroir sur sdc/sdd. Deux datasets compressés selon leur usage, et la mesure de ce que chacun fait gagner. Un snapshot restauré avec succès, et le stockage visible et utilisable dans Proxmox.

Le miroir datapool de l'atelier sur sdc et sdd, face au RAIDZ1 d'un pool d'essai

Deux façons de rendre un pool redondant. Le miroir écrit la même donnée sur deux disques (comme RAID 1) : c'est ce que vous construisez ici, avec sdc et sdd.

RAIDZ1 répartit les données et une parité sur trois disques ou plus (comme RAID 5) et tolère la perte d'un disque. En production pour la virtualisation, le miroir est préféré pour ses performances en accès aléatoire. Cliquez sur un pool pour son détail.

Arborescence attendue

Pool ZFS « datapool »  (miroir sdc + sdd)
├── dataset « datapool/vms »          ← compression lz4 (disques de VM : la vitesse)
│   └── snapshot @avant-modif          ← créé puis rollback
└── dataset « datapool/sauvegardes »  ← compression zstd (archives : la place), comparé puis supprimé
Intégré dans Proxmox → stockage de type « ZFS »

Ce que vous devez faire

  1. Identifier les disques disponibles et confirmer que sdc et sdd sont bien libres — surtout pas sdb, réservé à Ceph, ni sda, le système.
  2. Créer le pool en miroir sur les deux disques, puis un dataset avec la compression activée.
  3. Un cran plus loin : un réglage par usage. Créez un second dataset, datapool/sauvegardes, compressé en zstd. Écrivez les mêmes données texte dans les deux datasets et comparez ce qu'elles occupent réellement.

    Supprimez ensuite ce second dataset.

  4. Éprouver les snapshots : prendre un snapshot du dataset, modifier des données, puis revenir en arrière et constater la restauration.

  5. Intégrer le pool dans Proxmox comme stockage, et vérifier qu'il accepte bien des disques de VM.

⚠️ Attention au disque : monter ZFS sur sdb rendrait Ceph impossible (Ceph refuse un disque portant une signature ZFS). Respectez le plan des disques.

Cliquez pour vous aider

Étape 1 — Identifier les disques disponibles

Dans le Shell du nœud (interface web → votre nœud → Shell) :

# Les disques entiers (-d), puis le contenu des deux disques visés
lsblk -d -o NAME,SIZE,TYPE,MODEL
fdisk -l /dev/sdc   # le disque sdc
fdisk -l /dev/sdd   # le disque sdd

Résultat attendu (nœud pxe211, construit comme le vôtre) :

NAME  SIZE TYPE MODEL
sda   150G disk QEMU HARDDISK
sdb    70G disk QEMU HARDDISK
sdc    50G disk QEMU HARDDISK
sdd    50G disk QEMU HARDDISK
Disk /dev/sdc: 50 GiB, 53687091200 bytes, 104857600 sectors
Disk model: QEMU HARDDISK
...

Quatre disques : sda (système), sdb (70 Go, Ceph) et sdc, sdd de même taille (50 Go). Pour ces deux derniers, fdisk -l n'affiche aucune ligne de partition — seulement la taille et le modèle.

Attention : vérifiez bien que sdc et sdd sont des disques vides, sans données. La création du pool est irréversible.

Étape 2 — Créer un pool ZFS miroir

Fenêtre Create: ZFS remplie

La fenêtre remplie sur le lab. Seuls les deux disques de taille identique sont cochés — sdc et sdd, 53.69 GB chacun sur ce nœud (50 Gio exprimés en gigaoctets décimaux).

La taille varie d'un nœud à l'autre : seule compte l'égalité des deux disques. Dans un miroir, la capacité du pool est celle du plus petit disque, et sdb reste réservé aux OSD Ceph.

RAID Level est passé de Single Disk à Mirror, Add Storage est décoché. Les valeurs par défaut Compression on et ashift 12 conviennent.

Via l'interface : pxe2<N>1 → Disks → ZFS → Create: ZFS — Name datapool, RAID Level Mirror, Add Storage décoché (on l'ajoute manuellement à l'étape 5), Disk 1 /dev/sdc, Disk 2 /dev/sdd → Create.

Équivalent CLI :

Dans le Shell du nœud (interface web → votre nœud → Shell) :

# Pool en miroir ; -f passe outre un avertissement de signature résiduelle (à n'utiliser
# qu'après avoir vérifié à l'étape 1 que les disques sont bien vides)
zpool create -f -o ashift=12 datapool mirror /dev/sdc /dev/sdd

zpool status   # état du pool et de ses disques
zpool list   # taille et remplissage du pool

Résultat attendu :

  pool: datapool
 state: ONLINE
config:
        NAME        STATE     READ WRITE CKSUM
        datapool    ONLINE       0     0     0
          mirror-0  ONLINE       0     0     0
            sdc     ONLINE       0     0     0
            sdd     ONLINE       0     0     0

errors: No known data errors

zpool list affiche une taille d'environ 49,5 Go : celle d'un disque, puisque le miroir écrit tout en double.

Résultat attendu, pool créé par l'interface :

    NAME                                      STATE     READ WRITE CKSUM
    datapool                                  ONLINE       0     0     0
      mirror-0                                ONLINE       0     0     0
        scsi-0QEMU_QEMU_HARDDISK_drive-scsi2  ONLINE       0     0     0
        scsi-0QEMU_QEMU_HARDDISK_drive-scsi3  ONLINE       0     0     0
NAME       SIZE  ALLOC   FREE  CKPOINT  EXPANDSZ   FRAG    CAP  DEDUP    HEALTH  ALTROOT
datapool  49.5G   624K  49.5G        -         -     0%     0%  1.00x    ONLINE  -

Remarquez les noms des disques. L'interface ne les désigne pas par sdc et sdd, mais par leur identifiant stable (/dev/disk/by-id/…). Un nom comme sdc peut changer au redémarrage suivant, si l'ordre de détection des disques change ; l'identifiant, jamais.

C'est la bonne pratique en production. En ligne de commande, zpool create … mirror /dev/sdc /dev/sdd garde les noms courts du tableau précédent.

Le pool dans Disks → ZFS

datapool apparaît sous Disks → ZFS, Health ONLINE. La taille affichée, 53.15 GB, est la même capacité que les 49,5 Gio de zpool list, exprimée en gigaoctets décimaux.

Étape 3 — Créer un dataset et activer la compression

Dans le Shell du nœud (interface web → votre nœud → Shell) :

# Un dataset dédié aux VM, compressé en lz4
zfs create datapool/vms
zfs set compression=lz4 datapool/vms   # compression lz4 sur ce dataset

zfs get compression,used,available datapool/vms   # compression, espace occupé et disponible

Résultat attendu :

NAME          PROPERTY     VALUE           SOURCE
datapool/vms  compression  lz4             local
datapool/vms  used         96K             -
datapool/vms  available    48.0G           -

SOURCE local signifie que la propriété est posée sur ce dataset ; un dataset enfant afficherait inherited from datapool/vms. C'est ainsi qu'on repère d'où vient un réglage.

Étape 3 bis — Un réglage par usage

Tous les datasets n'ont pas le même besoin. Les disques de VM demandent de la vitesse : lz4 compresse peu mais presque sans coût.

Des archives de sauvegarde demandent de la place : zstd compresse davantage, au prix d'un peu plus de calcul. Sur ZFS, ce choix se fait dataset par dataset.

Dans le Shell du nœud (interface web → votre nœud → Shell) :

# Un second dataset, compressé en zstd dès sa création
zfs create -o compression=zstd datapool/sauvegardes
# Les mêmes données texte (les modules Perl de Proxmox), écrites séparément dans chaque dataset
tar -cf /datapool/vms/perl.tar -C /usr/share perl5           # dans le premier dataset
tar -cf /datapool/sauvegardes/perl.tar -C /usr/share perl5   # puis dans le second
sync   # forcer l'écriture sur disque avant de mesurer
# Taux de compression, place réellement occupée, taille avant compression
zfs get -o name,property,value compressratio,used,logicalused datapool/vms datapool/sauvegardes

Résultat attendu :

NAME                  PROPERTY       VALUE
datapool/sauvegardes  compressratio  3.81x
datapool/sauvegardes  used           3.25M
datapool/sauvegardes  logicalused    12.2M
datapool/vms          compressratio  2.56x
datapool/vms          used           4.82M
datapool/vms          logicalused    12.2M

Les mêmes 12,2 Mo (logicalused) occupent 4,82 Mo en lz4 et 3,25 Mo en zstd : un tiers de place en moins pour les sauvegardes. Deux pièges vus sur le lab :

  • Écrivez les données dans chaque dataset. Un cp d'un dataset à l'autre du même pool ne réécrit pas les blocs : OpenZFS les clone (zpool get feature@block_cloning datapool répond enabled), et la copie garde la compression d'origine. Les deux taux affichaient alors 2.56x.
  • Des données déjà compressées ne gagnent rien. Avec une archive de /usr/share/doc, faite surtout de fichiers .gz, les deux datasets plafonnaient au même taux (1.54x), quel que soit l'algorithme.

Supprimez les deux archives de test, puis le dataset sauvegardes, qui ne sert plus.

Dans le Shell du nœud :

rm /datapool/vms/perl.tar /datapool/sauvegardes/perl.tar   # les deux archives de test
zfs destroy datapool/sauvegardes                           # le dataset

Les ateliers suivants partent d'un pool qui ne contient que datapool/vms.

Étape 4 — Snapshots ZFS

Dans le Shell du nœud (interface web → votre nœud → Shell) :

# Un fichier témoin dans le dataset (monté d'office sur /datapool/vms)
mkdir -p /datapool/vms/test
nano /datapool/vms/test/fichier.txt   # un fichier de test : la ligne « données importantes »

zfs snapshot datapool/vms@avant-modif   # snapshot du dataset
zfs list -t snapshot   # vérifier qu'il existe

# Simuler une erreur
rm /datapool/vms/test/fichier.txt

# Revenir au snapshot
zfs rollback datapool/vms@avant-modif

cat /datapool/vms/test/fichier.txt   # le contenu actuel du fichier

Résultat attendu :

NAME                       USED  AVAIL  REFER  MOUNTPOINT
datapool/vms@avant-modif     0B      -   104K  -
données importantes

Le snapshot n'occupe rien (USED 0B) tant que rien n'a changé ; après le rollback, cat affiche de nouveau données importantes — le fichier supprimé est revenu, sans aucune copie préalable.

Étape 5 — Intégrer ZFS dans Proxmox

Via l'interface : Datacenter → Storage → Add → ZFS — ID zfs-vms, ZFS Pool datapool/vms, Content Disk image, Container, Nodes (laisser vide = tous les nœuds) → Add.

Équivalent CLI :

Dans le Shell du nœud (interface web → votre nœud → Shell) :

# Déclarer le dataset comme stockage : disques de VM et racines de conteneurs
pvesm add zfspool zfs-vms \
  --pool datapool/vms \
  --content images,rootdir

pvesm status   # le stockage zfs-vms doit apparaître

Résultat attendu : zfs-vms zfspool active 50298460 104 50298356 0.00%. Dans Datacenter → Storage, le stockage zfs-vms apparaît avec le type ZFS.

zfspool en ligne de commande, ZFS dans l'interface : c'est le même type. zfspool est son identifiant technique, celui de pvesm et de /etc/pve/storage.cfg ; ZFS est son libellé dans l'interface.

Attention au piège inverse : l'identifiant zfs, en ligne de commande, désigne un autre type, ZFS over iSCSI. Cela se lit dans le code de l'interface de Proxmox VE 9.2.21 : zfspool → ZFS, zfs → ZFS over iSCSI.

Validation finale

Dans le Shell du nœud (interface web → votre nœud → Shell) :

# Le pool, la compression, le stockage Proxmox
zpool list -H -o health datapool   # l'état du pool
zfs get compression datapool/vms   # la compression du dataset
pvesm status | grep zfs-vms   # le stockage zfs-vms est-il actif ?

Résultat attendu : ONLINE, datapool/vms compression lz4 local, et la ligne zfs-vms zfspool active.


Atelier 4 — Déplacer à chaud un disque de VM de LVM-thin vers ZFS

Contexte

Votre nœud a maintenant deux stockages de disques : local-lvm (LVM-thin) et zfs-vms (le miroir de l'atelier 3). Une VM installée sur le premier peut passer sur le second sans être arrêtée.

Proxmox recopie le disque pendant que la VM tourne, puis bascule sur la copie (cours, §4.5). C'est le geste qui permet de profiter du miroir ZFS sans réinstaller une machine.

Résultat à obtenir : une VM 140 vm-disque, clonée sur local-lvm, dont le disque passe sur zfs-vms sans perte de ping ; l'ancien volume LVM supprimé ; puis la VM supprimée.

Atelier 4 : un disque déplacé à chaud vers ZFS

Le schéma suit le disque de la VM 140 de local-lvm vers zfs-vms. Cliquez sur chaque bloc pour son détail.

Arborescence attendue

Nœud pxe2<N>1
├── Avant : VM 140 « vm-disque » (10.<site>.<N>.66), running   ← étapes 1 et 2
│   └── scsi0 : local-lvm:vm-140-disk-0        → volume LVM  pve/vm-140-disk-0
└── Après : la même VM, toujours running                       ← étapes 3 et 4
    └── scsi0 : zfs-vms:vm-140-disk-0          → zvol        datapool/vms/vm-140-disk-0

Ce que vous devez faire

  1. Cloner le template 100 du chapitre 2 en VM 140 vm-disque, clone complet sur local-lvm, adresse .66, et la démarrer.
  2. Relever l'état initial : où est le disque, et quel volume LVM le porte.
  3. Déplacer le disque vers zfs-vms, VM démarrée, en supprimant la source, pendant qu'un ping tourne.
  4. Constater : où est le disque maintenant, et combien de pings ont été perdus.
  5. Supprimer la VM 140.
Cliquez pour vous aider

Machine d'exemple : nœud pxe211 (Proxmox VE 9.2.21, lab 10.59.1.x), avec le template de 20 Go de l'atelier 7 du chapitre 2. La VM 140 y avait l'adresse 10.59.1.66 ; chez vous, 10.<site>.<N>.66. Les captures, plus anciennes, montrent un disque de 3 Go.

Étape 1 — La VM de l'atelier

Dans le Shell du nœud (interface web → votre nœud → Shell) :

qm clone 100 140 --name vm-disque --full --storage local-lvm   # clone intégral de la VM 100
qm set 140 --ipconfig0 ip=10.<site>.<N>.66/24,gw=10.<site>.<N>.1   # son adresse fixe
qm start 140   # la démarrer

Attendez une trentaine de secondes, le temps que la VM démarre.

Étape 2 — L'état initial

Dans le Shell du nœud :

ping -c2 10.<site>.<N>.66   # la VM répond
qm config 140 | grep scsi0   # son disque, sur local-lvm
lvs pve | grep vm-140   # le volume LVM correspondant

Résultat attendu :

2 packets transmitted, 2 received, 0% packet loss, time 1014ms
scsi0: local-lvm:vm-140-disk-0,discard=on,iothread=1,size=20G
  vm-140-cloudinit pve Vwi-aotz--  4.00m data        9.38
  vm-140-disk-0    pve Vwi-aotz-- 20.00g data        6.17

Le disque de 20 Go est un volume du pool LVM-thin data, rempli à 6 % : à peine plus d'1 Go réellement écrit.

Étape 3 — Déplacer le disque, VM démarrée

Via l'interface : VM 140 → Hardware → sélectionner Hard Disk (scsi0) → Disk Action → Move Storage.

Champ Valeur
Target Storage zfs-vms
Format grisé : un stockage ZFS n'accepte que le format raw
Delete source coché

Fenêtre Move disk ouverte depuis l'onglet Hardware de la VM 140 : Disk scsi0, Target Storage à choisir, Format grisé, Delete source

La fenêtre Move disk telle qu'elle s'ouvre. Target Storage est encadré en rouge tant qu'aucune cible n'est choisie. Format est grisé : c'est le stockage cible qui impose le format.

Delete source décide du sort de l'ancien volume. Non coché, il reste en unused0 dans la configuration de la VM et continue d'occuper local-lvm. (Capture prise après le déplacement, d'où zfs-vms déjà affiché sur la ligne du disque.)

Ou en ligne de commande. Dans le Shell du nœud, avec un ping qui tourne pendant le déplacement :

ping -i 0.2 10.<site>.<N>.66 > /tmp/ping140.txt 2>&1 &   # ping toutes les 0,2 s, en arrière-plan
qm disk move 140 scsi0 zfs-vms --delete 1   # déplacer le disque vers ZFS, VM allumée
kill %1                     # arrêter le ping
tail -2 /tmp/ping140.txt    # lire le bilan

Résultat attendu (lignes de progression abrégées) :

create full clone of drive scsi0 (local-lvm:vm-140-disk-0)
allocated target volume 'zfs-vms:vm-140-disk-0'
drive mirror is starting for drive-scsi0
mirror-scsi0: transferred 20.0 GiB of 20.0 GiB (100.00%) in 8s, ready
all 'mirror' jobs are ready
mirror-scsi0: Completing block job...
mirror-scsi0: Completed successfully.
mirror-scsi0: mirror-job finished
removing source volume 'local-lvm:vm-140-disk-0' after successful copy
  Logical volume "vm-140-disk-0" successfully removed.

Lisez les lignes dans l'ordre. Proxmox crée le volume cible, puis lance un miroir (drive mirror) : QEMU copie le disque et répercute sur la copie chaque écriture de la VM. Quand les deux sont identiques (ready), il bascule la VM sur la copie (Completing block job).

Enfin il supprime la source. L'opération a duré 12 secondes sur le lab ; le ping, une réponse toutes les 0,2 s, n'en a manqué aucune (57 reçues sur 57).

Étape 4 — Constater

Dans le Shell du nœud :

qm config 140   # le disque est maintenant sur zfs-vms ; à lire : scsi0, unused
zfs list -o name,used,refer,volsize -r datapool/vms   # le volume ZFS de la VM
lvs pve | grep vm-140   # plus de volume LVM

Résultat attendu (les lignes qui comptent) :

scsi0: zfs-vms:vm-140-disk-0,discard=on,iothread=1,size=20G
NAME                         USED  REFER  VOLSIZE
datapool/vms                20.3G    96K        -
datapool/vms/vm-140-disk-0  20.3G   787M      20G

Onglet Hardware de la VM 140 : Hard Disk (scsi0) sur zfs-vms:vm-140-disk-0, CloudInit Drive resté sur local-lvm

L'onglet Hardware après le déplacement. Hard Disk (scsi0) pointe sur zfs-vms:vm-140-disk-0.

Le CloudInit Drive (ide2) est resté sur local-lvm : seul le disque choisi a bougé. En bas, la tâche VM 140 - Move disk est OK.

Deux constats. Le disque est devenu un zvol ZFS de 20 Go, dont 787 Mo réellement écrits (REFER). Pourtant USED vaut 20,3G : sur un stockage zfs-vms qui n'est pas en Thin provision, Proxmox réserve d'avance toute la taille du disque.

Il n'y a plus de ligne unused0 ni de volume vm-140-disk-0 dans LVM : la source est supprimée. Et aucun ping n'a été perdu : la VM n'a pas été interrompue.

Un disque sur zfs-vms est local au nœud. Dans un cluster, une VM dont le disque est sur ce stockage ne peut pas être migrée vers un nœud qui n'a pas de pool datapool. C'est pourquoi l'atelier se fait sur une VM dédiée, supprimée à la fin : vos VM 101 et 102 restent sur local-lvm.

Validation finale

Contrôle Attendu
qm config 140 | grep scsi0 zfs-vms:vm-140-disk-0
Pings perdus pendant le déplacement 0% packet loss
lvs pve | grep vm-140-disk-0 rien

Nettoyage :

Dans le Shell du nœud :

qm stop 140                             # arrêter la VM 140
qm destroy 140 --purge                  # puis la supprimer
zfs list -r datapool/vms   # vérifier que son volume a disparu

Résultat attendu : plus de vm-140-disk-0 sous datapool/vms.


Atelier 5 — Un serveur NFS dans un conteneur

Cours : §5.1 (ajouter un partage NFS à Proxmox).

Contexte

Au §5.1, le partage NFS est fourni par l'infrastructure : on ne fait que le déclarer. Ici, vous montez vous-même le serveur, dans un conteneur, pour voir l'autre côté : ce qu'il exporte, à qui, et avec quels droits.

Le serveur NFS du noyau Linux (nfsd) tourne dans le noyau, que le conteneur partage avec l'hôte. Un conteneur non privilégié n'a pas le droit de le piloter : ce conteneur-ci sera privilégié, un choix à justifier et à documenter (chapitre 1, conteneurs privilégiés).

Résultat à obtenir : un conteneur ct-nfs qui exporte /srv/partage vers votre réseau. Le partage monté depuis le nœud, où root est ramené à nobody (root_squash), et où un UID étranger passe tel quel.

Puis ce partage déclaré comme stockage de sauvegardes, et une sauvegarde écrite dessus. Tout est supprimé à la fin.

Atelier 5 : un serveur NFS dans le conteneur 260

Le schéma suit le partage du serveur jusqu'au stockage de sauvegardes. Cliquez sur chaque bloc pour son détail.

Arborescence attendue

CT 260 « ct-nfs » — privilégié, nesting, 10.<site>.<N>.81
└── /srv/partage            ← exporté vers 10.<site>.<N>.0/24, root_squash
    ├── test.txt            ← créé dans le conteneur
    ├── depuis-root         ← écrit par root du nœud : propriétaire 65534 (nobody)
    ├── equipe/rapport.txt  ← écrit par l'UID 2000 du nœud : propriétaire 2000
    └── dump/               ← sauvegarde du CT 200, via le stockage nfs-partage

Ce que vous devez faire

  1. Créer le conteneur 260 ct-nfs, privilégié, avec nesting, à l'adresse .81, depuis le modèle Debian 13. Y installer nfs-kernel-server.
  2. Exporter /srv/partage vers votre réseau, avec root_squash.
  3. Monter le partage sur le nœud et y écrire en root : expliquer le refus, le corriger.
  4. Écrire avec l'UID 2000 depuis le nœud : quel propriétaire voit le serveur ?
  5. Déclarer le partage comme stockage nfs-partage (contenu : sauvegardes), et y sauvegarder le CT 200.
  6. Nettoyer dans le bon ordre : le stockage d'abord, le conteneur ensuite.
Cliquez pour vous aider

Machine d'exemple : nœud pxe211 (Proxmox VE 9.2.21). Le conteneur 260 y a l'adresse 10.59.1.81 et exporte vers 10.59.1.0/24 ; chez vous, 10.<site>.<N>.81 et 10.<site>.<N>.0/24. Les heures affichées par le conteneur sont en UTC (Coordinated Universal Time, temps universel), celles du nœud en heure de Paris.

Étape 1 — Le conteneur et le serveur

Via l'interface : Create CT — General : CT ID 260, Hostname ct-nfs, Unprivileged container décoché, Nesting coché, mot de passe. Template : debian-13-standard ; Disks : local-lvm, 4 Go ; CPU 1 ; Memory 512. Network : vmbr0, IPv4 10.<site>.<N>.81/24, passerelle 10.<site>.<N>.1 → Finish, puis Start.

Équivalent CLI, dans le Shell du nœud :

# Conteneur privilégié (--unprivileged 0), nesting activé
pct create 260 local:vztmpl/debian-13-standard_13.6-1_amd64.tar.zst --hostname ct-nfs \
  --unprivileged 0 --features nesting=1 --cores 1 --memory 512 --swap 512 --rootfs local-lvm:4 \
  --net0 name=eth0,bridge=vmbr0,ip=10.<site>.<N>.81/24,gw=10.<site>.<N>.1 --password proxmoxx
pct start 260   # le démarrer

Dans la console du conteneur 260 (CT 260 → Console, compte root) :

apt update                                       # la liste des paquets
apt install -y nfs-kernel-server                 # le serveur NFS du noyau
systemctl is-active nfs-server                   # le service doit être actif

Résultat attendu :

● nfs-server.service - NFS server and services
     Loaded: loaded (/usr/lib/systemd/system/nfs-server.service; enabled; preset: enabled)
     Active: active (exited) since Tue 2026-10-06 18:28:55 UTC; 868ms ago

Sur Proxmox VE 9, le conteneur privilégié avec nesting suffit : aucun réglage AppArmor supplémentaire n'a été nécessaire.

Étape 2 — Exporter le répertoire

Dans la console du conteneur 260 :

Dans la console du conteneur 260 :

mkdir -p /srv/partage                                # le répertoire à partager
nano /srv/partage/test.txt                           # un fichier de test : la ligne « Fichier de test NFS »
nano /etc/exports                                    # le partage

La ligne à écrire dans /etc/exports : le partage, pour tout votre réseau, en lecture-écriture, root ramené à nobody.

/srv/partage 10.<site>.<N>.0/24(rw,sync,no_subtree_check,root_squash)

Dans la console du conteneur 260 :

exportfs -ra   # relire /etc/exports
exportfs -v    # ce qui est réellement exporté, options comprises
ls -ld /srv/partage   # propriétaire et droits du répertoire

Résultat attendu :

/srv/partage    10.59.1.0/24(sync,wdelay,hide,no_subtree_check,sec=sys,rw,secure,root_squash,no_all_squash)
drwxr-xr-x 2 root root 4096 Oct  6 18:29 /srv/partage
Option Effet
rw lecture et écriture (ro : lecture seule)
sync le serveur ne confirme une écriture qu'une fois sur disque
no_subtree_check pas de vérification coûteuse de l'arborescence, recommandé pour un répertoire entier
root_squash le root du client devient nobody sur le serveur : la protection par défaut

Étape 3 — Le nœud comme client

Dans le Shell du nœud :

showmount -e 10.<site>.<N>.81   # ce que le serveur propose
mkdir -p /mnt/essai-nfs         # le point de montage
mount -t nfs4 10.<site>.<N>.81:/srv/partage /mnt/essai-nfs   # monter le partage
cat /mnt/essai-nfs/test.txt     # lire le fichier de test
touch /mnt/essai-nfs/depuis-root   # écrire en root

Résultat attendu :

Export list for 10.59.1.81:
/srv/partage 10.59.1.0/24
Fichier de test NFS
touch: cannot touch '/mnt/essai-nfs/depuis-root': Permission denied

Vous êtes root sur le nœud, et pourtant refusé. root_squash vous a ramené à nobody, et /srv/partage appartient à root, en 755 : nobody n'y écrit pas.

Dans la console du conteneur 260 :

chown nobody:nogroup /srv/partage   # le répertoire à nobody
chmod 775 /srv/partage              # écriture pour nobody, traversée pour les autres

Dans le Shell du nœud :

touch /mnt/essai-nfs/depuis-root   # écrire en root, de nouveau
ls -ln /mnt/essai-nfs   # -n : les numéros d'UID, pas les noms

Résultat attendu :

-rw-r--r-- 1 65534 65534  0 Oct  6 20:29 depuis-root
-rw-r--r-- 1     0     0 20 Oct  6 20:29 test.txt

Le fichier écrit par root appartient à 65534, l'UID de nobody : c'est root_squash au travail.

Étape 4 — Un UID étranger

Dans la console du conteneur 260 :

mkdir /srv/partage/equipe             # un sous-répertoire
chown 2000:2000 /srv/partage/equipe   # un répertoire à l'UID 2000, qui n'existe pas ici

Dans le Shell du nœud :

# Écrire sous l'UID 2000 et le GID 2000, sans créer de compte
setpriv --reuid=2000 --regid=2000 --clear-groups touch /mnt/essai-nfs/equipe/rapport.txt

Dans la console du conteneur 260 :

ls -l /srv/partage/equipe   # le contenu, vu du serveur
getent passwd 2000   # existe-t-il un compte 2000 ?

Résultat attendu :

-rw-r--r-- 1 2000 2000 0 Oct  6 18:29 rapport.txt

getent ne répond rien : aucun compte 2000 n'existe dans le conteneur. NFS transmet le numéro d'UID tel quel, sans traduction par nom. Deux machines qui partagent des fichiers doivent donc avoir les mêmes UID.

Avec un chmod 770 sur /srv/partage au lieu de 775, l'UID 2000 ne peut même pas traverser le répertoire : Permission denied, alors que le sous-répertoire equipe lui appartient. Pour atteindre un fichier, il faut le droit x sur chaque répertoire du chemin.

Étape 5 — Le partage comme stockage de sauvegardes

Dans le Shell du nœud, démontez d'abord le montage d'essai :

umount /mnt/essai-nfs                        # démonter
rmdir /mnt/essai-nfs                         # retirer le point de montage

Via l'interface : Datacenter → Storage → Add → NFS — ID nfs-partage, Server 10.<site>.<N>.81, Export /srv/partage, Content Backup → Add. Puis CT 200 → Backup → Backup now — Storage nfs-partage, Mode Snapshot, Compression ZSTD → Backup.

Équivalent CLI, dans le Shell du nœud :

pvesm add nfs nfs-partage --server 10.<site>.<N>.81 --export /srv/partage --content backup   # déclarer le partage
pvesm status | grep nfs-partage                                    # actif ?
vzdump 200 --storage nfs-partage --mode snapshot --compress zstd   # une sauvegarde dessus

Résultat attendu (extrait) :

nfs-partage         nfs     active         4046848          720896         3099648   17.81%
INFO: Finished Backup of VM 200 (00:00:07)
INFO: Backup job finished successfully

Datacenter → Storage : nfs-partage, de type NFS, contenu Backup, monté sous /mnt/pve/nfs-partage, Shared Yes

Datacenter → Storage : nfs-partage est de type NFS, contenu Backup, monté sous /mnt/pve/nfs-partage. Sa colonne Shared vaut Yes, contrairement aux trois stockages locaux.

Stockage nfs-partage → Backups : la sauvegarde vzdump-lxc-200 au format tar.zst, 206.79 MiB

Le stockage nfs-partage → Backups : la sauvegarde du CT 200, 206,79 Mio. Sa capacité (4 Go) est celle du disque du conteneur 260 : un partage n'offre que la place de ce qu'il exporte.

Dans la console du conteneur 260 :

ls -ln /srv/partage/dump   # la sauvegarde, vue du serveur

Résultat attendu :

-rw-r--r-- 1 65534 65534       742 Oct  6 18:29 vzdump-lxc-200-2026_10_06-20_29_34.log
-rw-r--r-- 1 65534 65534 216834678 Oct  6 18:29 vzdump-lxc-200-2026_10_06-20_29_34.tar.zst

Proxmox écrit ses sauvegardes en root : sur ce partage, root_squash les fait appartenir à nobody, comme le fichier depuis-root de l'étape 3.

Validation finale

Contrôle Attendu
exportfs -v dans le conteneur /srv/partage vers votre réseau, root_squash
Propriétaire de depuis-root 65534
Propriétaire de equipe/rapport.txt 2000
pvesm status | grep nfs-partage active

Nettoyage — dans cet ordre, dans le Shell du nœud :

pvesm remove nfs-partage        # 1. le stockage d'abord : Proxmox cesse de l'utiliser
umount /mnt/pve/nfs-partage     # 2. pvesm remove ne démonte pas
pct stop 260                            # 3. le serveur ensuite : l'arrêter
pct destroy 260 --purge                 # puis le supprimer
pvesm status                    # nfs-partage a disparu, tout est active

Résultat attendu (pvesm status) :

local             dir     active        24527236         9683680        13680676   39.48%
local-lvm     lvmthin     active        64876544        41929710        22946833   64.63%
zfs-vms       zfspool     active        29965724              96        29965628    0.00%

Détruire le conteneur avant de retirer le stockage laisserait un nfs-partage déclaré mais injoignable. Sur le lab, serveur arrêté : pvesm status le montre inactive, avec une capacité de 0. Et umount -f -l est resté bloqué plusieurs minutes, jusqu'au redémarrage du serveur.