
Introduction #
Dans l’annexe A02, nous avons déployé une instance Garage S3 sur la LXC 121 (storage) du nœud Morpheus, avec Docker Compose. À ce stade, les deux répertoires d’état de Garage — garage/meta (la base SQLite) et garage/data (les blocs d’objets) — sont des dossiers ordinaires sous /opt/docker/storage-stack/, donc sur le disque racine du conteneur.
Ce disque racine, c’est rpool/datastore/subvol-121-disk-0 : environ 17 Go, dont 13 encore libres. Suffisant pour des backups Proxmox modestes et quelques tests. Trop court dès que le stockage objet devient un vrai service — et c’est précisément ce qui arrive : à la suite de la série QFieldCloud auto-hébergé, un bucket de production doit atterrir sur cette instance. L’annexe A02 de QFieldCloud posait déjà un quota de 5 Go sur un nœud qui n’en déclarait que 4 : le genre de détail qui ne se voit qu’au moment où le disque se remplit.
meta/ et data/ sur un dataset ZFS dédié de Morpheus, le monter dans la LXC 121 par un point de montage Proxmox, et brancher Garage dessus via un simple interrupteur dans le .env — sans toucher au sous-module ni au déploiement de l’A02, et de façon entièrement réversible.
Au passage, une corvée préalable : le dataset rpool/tank/matrix ne sert plus rien depuis la mise au placard de la stack Matrix. Il contient encore des données, il est encore monté dans la LXC — on le retire proprement avant de créer le nouveau.
garage.toml ni le réseau de l’A02. On change uniquement où vivent les octets. La bascule passe par une variable d’environnement : la retirer remet le stockage sur le disque racine, à l’identique.
Table des matières #
- 🧭 Pourquoi un dataset dédié
- 🗺️ La chaîne de montage, bout à bout
- 🧹 Prérequis : retirer le dataset
rpool/tank/matrix - 📦 Créer le dataset ZFS sur Morpheus
- 🔗 Monter le dataset dans la LXC 121
- ⚙️ Câbler Garage sur le dataset
- 🚚 Migrer les données existantes
- 📈 Réviser la capacité du layout
- 🎯 Accueillir le bucket QFieldCloud de production
- 🔍 Troubleshooting
- ✅ Vérifications
- 🏁 Conclusion
Pourquoi un dataset dédié #
Trois raisons, dans l’ordre d’importance.
Le plafond. subvol-121-disk-0 fait 17 Go. On peut l’agrandir (pct resize 121 rootfs +50G), mais on empile alors backups Proxmox, base SQLite, blocs d’objets et journaux du conteneur sur le même volume — celui dont la saturation fige tout le conteneur d’un coup. Sortir data/ et meta/ sur leur propre dataset, c’est isoler le domaine de panne.
L’unité de sauvegarde. Un dataset est l’unité que ZFS sait snapshoter, envoyer et recevoir. zfs snapshot rpool/tank/garage@… fige meta et data au même instant : exactement ce dont l’annexe de sauvegarde a besoin pour un cliché cohérent. La politique Sanoid mise en place à l’annexe A01 couvre déjà rpool/tank en récursif — le nouveau dataset héritera de ses snapshots automatiques sans une ligne de configuration.
La lisibilité. zfs list -o space rpool/tank/garage répond en une ligne à « combien pèse Garage, snapshots compris ». Noyé dans le disque racine, ce chiffre n’existe pas.
rpool/tank vit sur le même pool, donc les mêmes disques que subvol-121-disk-0. On ne gagne pas des I/O plus rapides ni un support séparé — on gagne de la place, une frontière de snapshot et une cible de sauvegarde propre. Si vous cherchez de la performance ou de la résilience matérielle, c’est un autre chantier (pool dédié, vdev miroir supplémentaire).
La chaîne de montage, bout à bout #
graph TB
subgraph MORPHEUS["Nœud Morpheus (PVE)"]
SUBVOL[("rpool/datastore/subvol-121-disk-0
disque racine LXC · 17 Go")]
DS[("rpool/tank/garage
dataset dédié · 215 Go dispo")]
HOSTMP["/mnt/tank/garage (hôte)"]
end
subgraph CT121["LXC 121 · storage"]
CTMP["/mnt/garage (conteneur)"]
VOL["/var/lib/garage/{meta,data}"]
GARAGE["conteneur garage"]
end
DS -->|"mountpoint hérité"| HOSTMP
HOSTMP -->|"pct set 121 -mp0 …,mp=/mnt/garage"| CTMP
CTMP -->|"bind Docker Compose"| VOL
VOL -->|"data_dir / metadata_dir (garage.toml)"| GARAGE
SUBVOL -.->|"avant : ./meta ./data
sur le disque racine"| GARAGE
style DS fill:#c8e6c9,stroke:#2e7d32,stroke-width:2px,color:#000
style SUBVOL fill:#ffcdd2,stroke:#c62828,stroke-width:2px,color:#000
style GARAGE fill:#ffe0b2,stroke:#e65100,stroke-width:2px,color:#000
| # | Maillon | Où | Défini par |
|---|---|---|---|
| 1 | Dataset rpool/tank/garage |
Morpheus | zfs create |
| 2 | Point de montage /mnt/tank/garage |
Morpheus | propriété mountpoint (héritée de rpool/tank) |
| 3 | Point de montage /mnt/garage |
LXC 121 | pct set 121 -mp0 … |
| 4 | Bind /var/lib/garage/{data,meta} |
conteneur garage |
volumes: du Compose (via .env) |
| 5 | data_dir / metadata_dir |
processus Garage | garage.toml (inchangé) |
Prérequis : retirer le dataset rpool/tank/matrix
#
1. Inspecter avant de toucher #
Sur Morpheus :
[root@morpheus:~] $ zfs list -o name,used,refer,mountpoint rpool/tank/matrix
NAME USED REFER MOUNTPOINT
rpool/tank/matrix 52.8M 52.8M /mnt/tank/matrix
# Des snapshots ? (Sanoid couvre rpool/tank en récursif — il y en a)
[root@morpheus:~] $ zfs list -t snapshot -o name,used rpool/tank/matrix
NAME USED
rpool/tank/matrix@autosnap_2026-09-08_00:00:00_daily ...
# Qui l'ouvre encore ? (le point de montage de l'écran de config de la LXC)
[root@morpheus:~] $ grep -rn 'tank/matrix' /etc/pve/lxc/*.conf
/etc/pve/lxc/121.conf:mp0: /mnt/tank/matrix,mp=/mnt/matrixTrois faits : 52 Mo de données bien réelles, des snapshots autosnap accrochés au dataset, et un point de montage mp0 encore déclaré sur la LXC 121. Aucun des trois ne se laisse ignorer.
2. Détacher le point de montage de la LXC #
Tant que mp0 pointe dessus, le dataset est « busy » et la LXC embarque un montage mort. On retire l’entrée — c’est aussi le slot qu’on réutilisera pour Garage juste après :
[root@morpheus:~] $ pct set 121 --delete mp0
[root@morpheus:~] $ pct reboot 1213. Mettre de côté, puis détruire #
zfs destroy est immédiat et sans corbeille. À cette échelle (52 Mo), le plus sûr est de garder un filet quelques jours plutôt que de détruire séance tenante — soit un renommage hors de la vue, soit un send vers un fichier sur rpool/backups.
- Renommer (repli rapide)
- Archiver puis détruire
# Le dataset disparaît de /mnt/tank sans perdre un octet
[root@morpheus:~] $ zfs rename rpool/tank/matrix rpool/tank/_trash-matrix
[root@morpheus:~] $ zfs set mountpoint=none rpool/tank/_trash-matrix
# … quelques jours plus tard, une fois certain de ne rien regretter :
[root@morpheus:~] $ zfs destroy -r rpool/tank/_trash-matrix# Cliché cohérent, envoyé compressé dans un fichier
[root@morpheus:~] $ zfs snapshot rpool/tank/matrix@adieu
[root@morpheus:~] $ zfs send rpool/tank/matrix@adieu | zstd \
> /rpool/backups/matrix-adieu-$(date +%F).zfs.zst
# Vérifier que le fichier est lisible (liste le flux sans l'écrire)
[root@morpheus:~] $ zstd -dc /rpool/backups/matrix-adieu-*.zfs.zst | zfs receive -nv rpool/tank/verif-matrix
# Puis détruire la source, snapshots compris
[root@morpheus:~] $ zfs destroy -r rpool/tank/matrixzfs destroy rpool/tank/matrix sans -r échoue avec cannot destroy … filesystem has children — ce sont les snapshots autosnap de Sanoid. Le -r les emporte avec le dataset. N’utilisez jamais -R ici : il détruirait aussi d’éventuels clones dépendants, sans prévenir.
stateDiagram-v2
[*] --> Actif : dataset en service
Actif --> Détaché : pct set 121 --delete mp0
Détaché --> MisÀLécart : zfs rename → _trash-matrix
ou zfs send → fichier
MisÀLécart --> Détruit : zfs destroy -r
Détruit --> [*]
Créer le dataset ZFS sur Morpheus #
zfs create, quelques propriétés choisies pour un stockage d’objets, et le point de montage tombe tout seul au bon endroit.
[root@morpheus:~] $ zfs create rpool/tank/garage
# rpool/tank est monté sur /mnt/tank → l'enfant hérite de /mnt/tank/garage
[root@morpheus:~] $ zfs get -o property,value mountpoint rpool/tank/garage
PROPERTY VALUE
mountpoint /mnt/tank/garageTrois propriétés méritent d’être posées d’emblée :
# Blocs alignés sur la taille de bloc par défaut de Garage (1 Mio)
[root@morpheus:~] $ zfs set recordsize=1M rpool/tank/garage
# Compression légère à abandon rapide : Garage compresse déjà ses objets
# (compression_level = 2 dans garage.toml), lz4 ne s'acharne pas sur
# de l'incompressible et coûte quasi rien sur le reste.
[root@morpheus:~] $ zfs set compression=lz4 rpool/tank/garage
# Pas d'intérêt à réécrire un atime à chaque lecture de bloc
[root@morpheus:~] $ zfs set atime=off rpool/tank/garagerecordsize=1M est idéal pour data/ (gros blocs) mais peu flatteur pour meta/ (SQLite, petites écritures aléatoires). À l’échelle d’un homelab, meta/ pèse quelques dizaines de Mo et l’écart est invisible. S’il venait à grossir, créez un enfant dédié — zfs create -o recordsize=16K rpool/tank/garage/meta — qui apparaîtra sous le même point de montage sans rien changer au reste.
Sanoid (annexe A01) verra le nouveau dataset au prochain passage de son timer et commencera à le snapshoter selon le template data. Rien à faire.
Monter le dataset dans la LXC 121 #
1. Déclarer le point de montage #
Le slot mp0 a été libéré en retirant Matrix. On le réutilise :
[root@morpheus:~] $ pct config 121 | grep -E '^mp[0-9]|unprivileged'
unprivileged: 1
[root@morpheus:~] $ pct set 121 -mp0 /mnt/tank/garage,mp=/mnt/garage,backup=0
[root@morpheus:~] $ pct reboot 121backup=0 n’est pas cosmétique. Sans lui, vzdump (et donc PBS) tenterait d’avaler l’intégralité des objets Garage à chaque sauvegarde du conteneur — potentiellement des centaines de Go. Les objets se sauvegardent au niveau du dataset ZFS, pas du conteneur.
2. Régler les droits (conteneur non privilégié) #
unprivileged: 1 : dans la LXC 121, root (UID 0) correspond à l’UID 100000 sur Morpheus, et l’utilisateur allfab (UID 1000) à l’UID 101000. Le dataset fraîchement créé appartient à root:root de l’hôte (UID 0) — vu depuis le conteneur, il apparaît en nobody:nogroup et n’est pas inscriptible.
Le conteneur garage tourne en root (l’image dxflrs/garage ne déclare pas d’utilisateur — docker exec garage id le confirme). Il faut donc donner le dataset au root du conteneur, c’est-à-dire à l’UID 100000 côté hôte :
# Sur Morpheus, AVANT de rebrancher Garage
[root@morpheus:~] $ chown -R 100000:100000 /mnt/tank/garagelxc.idmap dans /etc/pve/lxc/121.conf (mapper l’UID 0 du conteneur sur l’UID 0 de l’hôte pour ce sous-arbre). Plus fin, mais plus verbeux, et à réserver au cas où le dataset est partagé avec d’autres conteneurs ayant des UID différents. Pour un dataset dédié à une seule LXC, le chown suffit.
Pour un conteneur privilégié (unprivileged: 0), pas de décalage : chown -R 0:0 /mnt/tank/garage (ou l’UID applicatif si Garage tournait sous un utilisateur dédié).
3. Vérifier depuis le conteneur #
[allfab@storage:~] $ df -h /mnt/garage
Filesystem Size Used Avail Use% Mounted on
rpool/tank/garage 215G 128K 215G 1% /mnt/garage
[allfab@storage:~] $ sudo -u '#0' touch /mnt/garage/.rw-test && echo OK && sudo rm /mnt/garage/.rw-test
OKCâbler Garage sur le dataset #
.env, une interpolation dans le Compose. Absente, le comportement de l’A02 est conservé au bit près.
1. L’interrupteur, dans .env
#
Le .env de la stack (/opt/docker/storage-stack/.env) reçoit une variable :
# /opt/docker/storage-stack/.env
COMPOSE_PROJECT_NAME=garage
# --- STOCKAGE ---
# Racine des répertoires meta/ et data/ de Garage.
# Vide ou absente -> "." (dossier garage/), comportement A02, disque racine LXC.
# /mnt/garage -> dataset ZFS rpool/tank/garage monté dans la LXC.
GARAGE_STORAGE_ROOT=/mnt/garage
# GARAGE
RPC_SECRET = "…"
ADMIN_TOKEN = "…"
METRICS_TOKEN = "…"
# … (inchangé)2. L’interpolation, dans garage/docker-compose.yml
#
# /opt/docker/storage-stack/garage/docker-compose.yml
---
services:
garage:
container_name: garage
image: dxflrs/garage:v2.3.0
hostname: allfabox
restart: unless-stopped
ports:
- 3900:3900
- 3901:3901
- 3902:3902
- 3903:3903
volumes:
- ./config/garage.toml:/etc/garage.toml
- ${GARAGE_STORAGE_ROOT:-.}/meta:/var/lib/garage/meta # <- était ./meta
- ${GARAGE_STORAGE_ROOT:-.}/data:/var/lib/garage/data # <- était ./data
networks:
- storage
# garage-webui : inchangé${GARAGE_STORAGE_ROOT:-.} se lit « la valeur de GARAGE_STORAGE_ROOT, ou . si elle est vide ou absente ». Compose interpole depuis le .env du dossier courant. Le . se résout relativement à l’emplacement du fichier Compose (garage/) : le défaut reste donc garage/meta et garage/data, à l’identique de l’A02.
docker compose up. La configuration est prête, mais les données sont toujours dans garage/data et garage/meta. Passer à /mnt/garage maintenant démarrerait Garage sur un dataset vide — et le nœud se réamorcerait sous une nouvelle identité. La migration d’abord.
Migrer les données existantes #
1. Arrêter Garage #
meta/ est une base SQLite : elle doit être au repos pendant la copie.
[allfab@storage:storage-stack] $ docker compose stop garage garage-webui2. Recopier meta/ puis data/ #
Depuis la LXC 121, en root (les chemins source et destination traversent le décalage d’UID, d’où --numeric-ids) :
[root@storage:~] $ rsync -aHAX --numeric-ids --info=progress2 \
/opt/docker/storage-stack/garage/meta/ /mnt/garage/meta/
[root@storage:~] $ rsync -aHAX --numeric-ids --info=progress2 \
/opt/docker/storage-stack/garage/data/ /mnt/garage/data/
# Deuxième passe à blanc : elle ne doit rien avoir à transférer
[root@storage:~] $ rsync -naHAX --numeric-ids --itemize-changes \
/opt/docker/storage-stack/garage/data/ /mnt/garage/data/3. Rebrancher et vérifier l’identité du nœud #
[allfab@storage:storage-stack] $ docker compose up -d
# Le nœud doit reparaître avec le MÊME ID qu'avant la migration
[allfab@storage:storage-stack] $ docker exec -ti garage /garage status
==== HEALTHY NODES ====
ID Hostname Address Tags Zone Capacity DataAvail
0f6796f7b25ec365 allfabox 10.10.20.21:3901 allfabox 4.0 GB 215 GB (99.9%)DataAvail a bondi : Garage voit désormais l’espace du dataset. L’ID 0f6796f7b25ec365 est inchangé — c’est la preuve que meta/ a bien suivi. Un ID différent signifierait que seul data/ a été copié : dans ce cas, on arrête tout, on recopie meta/, on repart. Surtout, on n’applique aucun layout dans cet état.
# Contrôle de lecture rapide
[allfab@storage:storage-stack] $ docker exec -ti garage /garage bucket list
[allfab@storage:storage-stack] $ mc ls garage/4. Garder l’ancien répertoire quelques jours #
[allfab@storage:storage-stack] $ mv garage/data garage/data.old && mv garage/meta garage/meta.oldIl ne coûte que de la place, et il vaut cher le jour où quelque chose a été oublié. On le supprime une fois la nouvelle configuration éprouvée.
sequenceDiagram
participant A as Admin (LXC 121)
participant D as Docker Compose
participant R as rsync
participant G as Garage
A->>D: docker compose stop garage garage-webui
A->>R: rsync meta/ puis data/ → /mnt/garage
R-->>A: 2ᵉ passe à blanc : 0 transfert
A->>A: .env : GARAGE_STORAGE_ROOT=/mnt/garage
A->>D: docker compose up -d
D->>G: montage /mnt/garage/{meta,data}
G-->>A: garage status → même ID de nœud
A->>A: mv garage/data → data.old (repli)
Réviser la capacité du layout #
L’A02 l’expliquait en détail : la valeur -c d’un layout assign n’est ni un quota, ni une réservation — c’est une clé de répartition proportionnelle entre nœuds. Sur un nœud unique elle n’a aucun effet observable, mais la consigne tenait : déclarer une valeur honnête vis-à-vis du disque, pour qu’elle soit juste le jour où un second nœud arrive.
[allfab@storage:storage-stack] $ docker exec -ti garage /garage layout assign -c 200G 0f6796f7b25ec365
[allfab@storage:storage-stack] $ docker exec -ti garage /garage layout show
[allfab@storage:storage-stack] $ docker exec -ti garage /garage layout apply --version 3Sans danger sur un nœud unique : il n’existe nulle part où déplacer des données. Le numéro de version (--version 3 ici) s’incrémente à chaque apply — layout show donne le bon.
Accueillir le bucket QFieldCloud de production #
À la suite de la série QFieldCloud, l’instance de production consommera ce Garage. On lui dédie un bucket et une clé, avec un quota qui — cette fois — se situe sous la capacité du nœud :
[allfab@storage:storage-stack] $ docker exec -ti garage /garage bucket create qfieldcloud-prod
[allfab@storage:storage-stack] $ docker exec -ti garage /garage key create qfieldcloud-prod-app
[allfab@storage:storage-stack] $ docker exec -ti garage /garage bucket allow \
--read --write --owner qfieldcloud-prod --key qfieldcloud-prod-app
[allfab@storage:storage-stack] $ docker exec -ti garage /garage bucket set-quotas qfieldcloud-prod --max-size 100GCôté QFieldCloud, rien à changer dans les octets : l’endpoint_url du bloc STORAGES reste http://10.10.20.21:3900. Rien, dans le stockage, ne mémorise l’adresse par laquelle on l’a atteint — le dataset sous-jacent est invisible pour le client S3.
| Bucket | Usage | Quota |
|---|---|---|
proxmox-backups |
Datastore S3 de PBS | selon besoin |
qfieldcloud |
Instance QFieldCloud de test (A02 QFC) | 5 G |
qfieldcloud-prod |
Instance QFieldCloud de production | 100 G |
mon-site |
Site statique via S3 Web | — |
Tous partagent le même dataset rpool/tank/garage : un seul snapshot ZFS les fige tous ensemble.
Troubleshooting #
flowchart TD
START["Garage ne démarre pas
ou /mnt/garage est vide"] --> Q1{"/mnt/garage visible
dans la LXC ?"}
Q1 -->|Non| F1["pct config 121 : mp0 présent ?
pct reboot 121"]
Q1 -->|Oui, mais nobody:nogroup| F2["chown -R 100000:100000
/mnt/tank/garage (sur l'hôte)"]
Q1 -->|Oui, accessible| Q2{"garage status :
même ID de nœud ?"}
Q2 -->|Non, ID nouveau| F3["meta/ non migré →
stop, rsync meta/, up
NE PAS apply de layout"]
Q2 -->|Oui| Q3{"Erreurs
Permission denied
os error 13 ?"}
Q3 -->|Oui| F2
Q3 -->|Non| OK["Chaîne OK"]
style F2 fill:#ffe0b2,stroke:#e65100,stroke-width:2px,color:#000
style F3 fill:#ffcdd2,stroke:#c62828,stroke-width:2px,color:#000
style OK fill:#c8e6c9,stroke:#2e7d32,stroke-width:2px,color:#000
zfs destroy : « filesystem has children » ou « dataset is busy »
#
cannot destroy 'rpool/tank/matrix': filesystem has children → snapshots Sanoid accrochés, ajoutez -r. cannot unmount '/mnt/tank/matrix': pool or dataset is busy → un point de montage mpX d’une LXC pointe encore dessus (grep -rn 'tank/matrix' /etc/pve/lxc/*.conf, puis pct set <id> --delete mpX).
Garage démarre avec un nœud « inconnu » #
Symptôme : garage status liste un ID différent, bucket list est vide. Cause : le dataset a été branché avec data/ mais sans meta/ — Garage a créé un nœud neuf.
Solution : docker compose stop garage, rsync -aHAX --numeric-ids /opt/docker/storage-stack/garage/meta.old/ /mnt/garage/meta/, docker compose up -d. Vérifier le retour de l’ID d’origine avant toute commande layout.
Permission denied (os error 13) sur /var/lib/garage/data
#
Le décalage d’UID n’a pas été appliqué, ou l’a été après le premier démarrage. Sur Morpheus : chown -R 100000:100000 /mnt/tank/garage (conteneur non privilégié), puis docker compose restart garage.
La sauvegarde du conteneur 121 explose en taille #
Le point de montage a été ajouté sans backup=0. Corriger : pct set 121 -mp0 /mnt/tank/garage,mp=/mnt/garage,backup=0.
Vérifications #
# --- Sur Morpheus ---
[root@morpheus:~] $ zfs list -o name,used,avail,mountpoint,compression,recordsize rpool/tank/garage
[root@morpheus:~] $ zfs list -t snapshot rpool/tank/garage # Sanoid a pris le relais
[root@morpheus:~] $ pct config 121 | grep ^mp0
mp0: /mnt/tank/garage,mp=/mnt/garage,backup=0
# --- Dans la LXC 121 ---
[allfab@storage:storage-stack] $ df -h /mnt/garage
[allfab@storage:storage-stack] $ docker inspect garage -f '{{ range .Mounts }}{{ .Source }} -> {{ .Destination }}{{ "\n" }}{{ end }}'
/mnt/garage/meta -> /var/lib/garage/meta
/mnt/garage/data -> /var/lib/garage/data
# --- Garage ---
[allfab@storage:storage-stack] $ docker exec -ti garage /garage status # ID de nœud inchangé
[allfab@storage:storage-stack] $ docker exec -ti garage /garage bucket list # buckets intactsTest de bout en bout — écrire et relire un objet :
[allfab@storage:storage-stack] $ echo "dataset ok $(date)" > /tmp/probe.txt
[allfab@storage:storage-stack] $ mc cp /tmp/probe.txt garage/qfieldcloud-prod/
[allfab@storage:storage-stack] $ mc cat garage/qfieldcloud-prod/probe.txt
[allfab@storage:storage-stack] $ mc rm garage/qfieldcloud-prod/probe.txtConclusion #
garage.toml ait bougé.
Ce que vous avez mis en place :
- Un ancien dataset (
rpool/tank/matrix) retiré proprement : détaché de la LXC, mis à l’écart, puis détruit avec-r. - Un dataset
rpool/tank/garageavecrecordsize=1M,compression=lz4,atime=off, monté dans la LXC 121 par un point de montage Proxmoxbackup=0. - Le décalage d’UID des conteneurs non privilégiés réglé côté hôte.
- Une bascule opt-in dans le
.env(GARAGE_STORAGE_ROOT) : la retirer restaure le comportement de l’A02. - Une migration
rsyncqui préserve l’ID de nœud Garage — meta d’abord, data ensuite, contrôle avant toutlayout. - Une capacité de layout révisée à 200 Go et un bucket
qfieldcloud-proddont le quota tient enfin sous celle du nœud.
zfs snapshot rpool/tank/garage@… fige meta et data au même instant, et zfs send l’expédie hors-site en incrémental. Et le jour où un second nœud rejoint le cluster, la capacité -c déclarée ici cesse d’être décorative : elle décide de la part des données qui atterrit sur chaque nœud.