Un OSD en Rust, le jour de sa sortie

croit a mis FlashStore OSD en préversion publique le 9 novembre 20261. C’est un OSD Ceph écrit de zéro en Rust, avec son propre magasin d’objets à la place de BlueStore, et il parle le protocole réseau de Ceph. La promesse, c’est qu’il s’insère dans un cluster que vous exploitez déjà : vos moniteurs, vos gestionnaires, votre CLI ceph et vos clients restent tels quels, et vous remplacez un disque à la fois1.

Cette promesse compte plus pour une boutique Proxmox que pour la plupart des autres. Sur un nœud Proxmox VE hyperconvergé, Ceph ne s’installe pas à part. Il sort de la GUI de Proxmox, des dépôts de Proxmox, compilé et patché par Proxmox, et le tout est piloté par pveceph. Si un OSD venu d’ailleurs peut s’installer là-dedans sans rien casser, vous gagnez un nouveau moteur de stockage sans renoncer à l’outillage. S’il ne le peut pas, vous l’apprenez à la dure, sur un nœud qui fait aussi tourner vos VM.

Alors je l’ai essayé.

Je travaille pour croit, qui fait FlashStore. C’est pour cela que je l’ai essayé moins de deux jours après sa sortie, et c’est aussi pour cela que rien de ce qui suit n’est adouci. C’est une préversion, le README dit qu’il est « not yet recommended for production data »1, et ceci est le compte rendu de ce qu’il a fallu sur du vrai matériel, pas une brochure.

Qui fournit quoi sur un nœudDisque de VM sur RBDQEMU avec la librbd livrée par ProxmoxDe Proxmox : pvecephceph-mon, ceph-mgr 21.2.0-pve1CLI, GUI, pools, stockage RBDinstallé via l'assistant web (8006)De croit : FlashStorecroit-flashstore-osd 21.2.0un démon par Optaneinstallé depuis un .deb, à la mainSN750 de démarrage : jamais un OSD8 × Optane P4800X, 4 Kio, namespace entier
Qui fournit quoi. Proxmox installe le moniteur et le gestionnaire et garde la GUI, les pools et la définition du stockage. Le paquet de croit ne fournit que les démons OSD, un par disque.

Réponse courte : ça marche. Huit OSD FlashStore servent un pool RBD à une VM sur un nœud Proxmox VE 9.2 de série au moment où j’écris, en HEALTH_OK. La réponse longue, c’est qu’il a fallu deux correctifs que la documentation ne mentionne pas, l’un à cause de la façon dont Proxmox range sa configuration Ceph, l’autre à cause du noyau de Proxmox, et le reste de cet article porte sur ces correctifs et sur la façon dont ils ont été trouvés. Si vous voulez seulement le faire tourner, un script vers la fin fait tout cela, et il a tourné sur ce nœud.

La machine

Le labo est un seul nœud, pve2, sur mon réseau domestique, et c’est un mini PC Minisforum B550 bas de gamme de 2021. Ceph sur un seul nœud, ce n’est pas comme ça qu’on fait de la production, et la règle CRUSH plus bas en est le prix, mais chaque étape ici est la même sur un nœud qui a des voisins.

Proxmox VEpve-manager 9.2.26, noyau 7.0.14-28-pve, Debian 13.7
Machinemini PC Minisforum B550, 2021 ; la carte s’annonce BESSTAR TECH B550, BIOS 5.17
CPUAMD Ryzen 7 5700G, 8 cœurs, 16 threads, 1 nœud NUMA
Mémoire58 Gio
Disques OSD8 × Intel Optane P4800X 375 Go (6 sous marque Dell, 2 Intel en boîte)
PCIe vers les Optaneles huit derrière un seul switch Broadcom PEX880xx, sur une seule liaison PCIe 3.0 x16 depuis l’APU
Disque de démarrageWD SN750 512 Go, VG pve, tenu à l’écart de tout ceci
Réseauun port 2,5 GbE, vmbr0
FlashStoresnapshot-2026-11-10, commit amont c5792750020e2

Les Optane sont là parce que FlashStore a deux exigences strictes que beaucoup de disques ne remplissent pas. Le disque doit avoir une protection contre les coupures de courant, et le namespace doit utiliser des blocs de 4096 octets, en namespace entier, sans partition ni système de fichiers dessus1. FlashStore acquitte une écriture quand elle est durable sur le disque, donc un disque qui ment sur la durabilité avec un cache volatil est refusé dès mkfs3. Chaque P4800X déclare ne pas avoir de cache d’écriture volatil dans ses données Identify (vwc 0), ce qui revient au disque lui-même qui dit que son cache ne peut pas perdre une écriture acquittée.

Du coup, c’est le mini PC qui est le facteur limitant de cette plongée en profondeur, pas FlashStore ni les disques. Huit cœurs, c’est un par OSD et aucun de reste, 58 Gio doivent nourrir Ceph et les VM à la fois, et huit Optane se partagent une liaison PCIe 3.0 parce que l’APU n’a rien de plus à offrir. Lisez chaque chiffre plus bas comme ce que cette machine permet.

Umbrella ou rien

FlashStore est compilé pour une seule version de Ceph à la fois. C’est la branche qui décide : main parle Ceph 21.2.0 Umbrella, et une branche v20.2.4 parle 20.2.4 Tentacle4. Le démon vérifie la version du cluster au démarrage et refuse celle qui sort de sa fenêtre4. Les paquets de la page de release sont compilés depuis main, et le binaire le dit lui-même : croit-flashstore-osd 21.2.0 umbrella.

Proxmox VE 9 propose trois dépôts Ceph, et un seul correspond.

La fenêtre de versionsDépôts de Proxmox VE 9Branches de FlashStoreceph-squid: 19.2.7pas de branche squidceph-tentacle: 20.2.520.2.5 n'est pas 20.2.4v20.2.4: tentacle 20.2.4ceph-umbrella: 21.2.0-pve121.2.0 concordemain: umbrella 21.2.0Le démon refuse une version de cluster hors de sa fenêtre.
Le dépôt Tentacle de Proxmox est déjà passé au-delà de 20.2.4, et il n’existe aucune branche Squid. Umbrella 21.2.0-pve1 est la seule version sur laquelle les deux côtés s’accordent.

Tentacle est le choix par défaut de Proxmox, alors est-ce le choix sûr ? C’est celui qui ne marchera pas. Le dépôt Proxmox porte Tentacle jusqu’à 20.2.5-pve1, et la branche Tentacle de FlashStore vise exactement 20.2.4. Umbrella dans le dépôt de Proxmox, c’est 21.2.0-pve1, la version même que vise main.

Proxmox ne cache pas ce qu’est Umbrella. PVE/Ceph/Releases.pm la liste avec unsupported => 15, et l’assistant de la GUI le dit en toutes lettres dès que vous la choisissez.

Assistant d’installation Ceph de Proxmox avec umbrella (21.2) sélectionné et le dépôt no-subscription, montrant la note indiquant que la version est une Technology Preview et que l’Enterprise Repository n’est pas encore disponible

« Technology Preview », pas de dépôt entreprise, et l’installateur redemande dans le terminal, continue (y/N)?, avant de toucher à apt. C’est la bonne dose d’avertissement, et elle vaut d’être lue comme un constat sur toute la pile : un OSD en préversion sur une version de Ceph en préversion.

L’installation est du Proxmox de série. Datacenter → Ceph → Install, version Umbrella, dépôt No-Subscription, puis le réseau public et le premier moniteur.

Terminal dans l’assistant Ceph de Proxmox listant les paquets Umbrella, dont ceph-osd et ceph-osd-classic, 13 mis à jour et 46 nouvellement installés

Treize paquets mis à jour, 46 nouveaux, 107 Mo téléchargés. Une chose dans cette liste est nouvelle avec Umbrella : ceph-osd-classic à côté de ceph-osd. Aucun des deux ne sert ici, car aucun OSD classique n’est jamais créé. Environ une minute plus tard, mon.pve2 et mgr.pve2 tournaient, ceph versions annonçait 21.2.0 … umbrella, et la santé était OK, sans rien à stocker pour l’instant.

Quatre disques à 512 octets

Quatre des huit Optane avaient été passés à une VM de labo et étaient encore au format 512 octets, avec de vieux labels ZFS dessus. Deux autres avaient le bon format et les mêmes labels. Le correctif est simple dans les deux cas : les retirer de la VM, formater en 4 Kio, effacer les labels.

Le P4800X propose 4096 octets sans métadonnées en format LBA 3, que nvme id-ns affiche comme lbaf 3 : ms:0 lbads:12.

nvme format /dev/nvme0n1 --lbaf=3 --force --timeout=900000
wipefs -a /dev/nvme0n1
sgdisk --zap-all /dev/nvme0n1

La première tentative a échoué, et une suivante aussi. Les deux fois, nvme format est revenu avec Interrupted system call et le disque était toujours à 512 octets. Le journal du noyau donne la raison :

nvme nvme0: I/O tag 0 (0000) opcode 0x2 (Admin Cmd) QID 0 timeout, reset controller
nvme nvme1: I/O tag 9 (0009) opcode 0x6 (Admin Cmd) QID 0 timeout, reset controller

L’opcode 0x2 est Get Log Page et 0x6 est Identify. Aucun des deux n’est le formatage. Un P4800X formate tout le support, et cela a pris de 345 à 351 secondes par disque ici. Pendant ce temps, le contrôleur ne répond pas aux autres commandes d’administration, donc tout ce qui pose une question au disque attend. Au bout du délai d’administration de 60 secondes du noyau, celui-ci abandonne et réinitialise le contrôleur, et la réinitialisation tue le formatage.

Comment un formatage est interrompunvme format345 à 351 spar P4800XCommande adminsmartctl, nvme list,un rafraîchissement GUIDélai de 60 sle noyau réinitialisele contrôleurFormatage avortéEINTR, rc 1disque encore à 512 oCorrectif : chaque formatage dans sa propre unité systemd, un disque à la fois,et rien d'autre n'est envoyé aux disques avant la fin.
Ce n’est pas le formatage qui expire. Autre chose pose une question au disque, attend derrière le formatage, et la réinitialisation qui suit l’interrompt.
TentativeCe qui a atteint le disqueRésultat
nvme0, la premièreun Get Log Page à 09:53:04, en pleine installation de Cephinterrompu, toujours 512 o
nvme0, dans une unitérien4 Kio en 345 s
nvme1mon propre nvme list, pour voir l’avancementinterrompu, toujours 512 o
nvme2, nvme3rien4 Kio en 351 s et 350 s
nvme1, seulrien4 Kio en 346 s

Le correctif consiste à lancer chaque formatage dans une unité transitoire avec un long délai, un disque à la fois, et à laisser les disques tranquilles jusqu’à la fin :

systemd-run --unit=fmt4k /root/fmt4k.sh
journalctl -u fmt4k -f       # read progress from the journal, not from the drive

Ainsi, le seul suivi de l’avancement passe par le journal, et rien n’atteint le contrôleur. Les huit affichaient ensuite 4 KiB dans nvme list.

Le paquet

La page de release porte des paquets .deb et .rpm, dont un pour Debian 13 trixie, la base de Proxmox VE 92. Un seul build sert toutes les distributions, à condition d’avoir glibc 2.34 ou plus récent6.

B=https://github.com/croit/ceph-rust/releases/download/snapshot-2026-11-10-0b6783237291
curl -LO "$B/flashstore_21.2.0+git.20261110063351.c5792750020e_debian-trixie_amd64.deb"
curl -LO "$B/sha256sums.txt"
sha256sum flashstore_*_debian-trixie_amd64.deb
grep debian-trixie/flashstore_ sha256sums.txt

Vérifiez à la main. sha256sum -c ne peut pas vérifier ce téléchargement, parce que le fichier de sommes le nomme debian-trixie/flashstore_…_amd64.deb alors que l’asset s’appelle flashstore_…_debian-trixie_amd64.deb. Les empreintes concordent, ce1fb352…26c8 des deux côtés, donc le fichier est bon et seule la liste est décalée par rapport aux assets.

apt install ./flashstore_*_debian-trixie_amd64.deb
croit-flashstore-osd --version
croit-flashstore-osd 21.2.0 umbrella (build 0.0.0) git c5792750020e
net tiers: kernel (+rdma upgrade)

Il s’est installé proprement à côté des ceph-osd et ceph-osd-classic de Proxmox. Le paquet n’installe un ceph-osd.target minimal que sur les hôtes qui n’en ont pas6, et Proxmox en a déjà un, donc les unités FlashStore se rattachent à la même cible que le feraient les classiques.

Trois choses à savoir sur le paquet avant d’écrire des scripts autour :

Ce que dit la docCe qu’est le paquet
Nom du paquetapt remove flashstore …6croit-flashstore-osd, le fichier de l’asset est flashstore_…
Backends de stockagel’ensemble de fonctionnalités de production de main est knet,spdk,rdma,mimalloc1pas de SPDK : --check affiche « SPDK NVMe driver: compiled out »
Valeurs de flashstore_devspdk:<pci>, ou file: dans les builds de développement7le tier noyau, kernel:/dev/…, est le seul vrai chemin de stockage de ce build

C’est la ligne du milieu qui compte. Le tier SPDK, le pilote NVMe en espace utilisateur qui exige que le disque soit lié à vfio-pci, n’est pas dans le paquet Debian publié. Ce qui s’y trouve, c’est le tier noyau : le disque reste sur le pilote nvme du noyau et FlashStore lui parle via io_uring. Le source montre qu’il est compilé, parce que la fonctionnalité knet tire kernel-nvme8, même si la ligne de synthèse du contrôle de l’hôte le dit « compiled out of this build ». Cette ligne est fausse. Un lecteur qui la croit s’arrêterait là.

Ce que dit le contrôle de l’hôte

croit-flashstore-osd --check est en lecture seule et s’exécute avant que quoi que ce soit ne soit écrit. Il contrôle le build, le CPU, la mémoire, l’IOMMU, chaque contrôleur NVMe, la carte réseau, le noyau et la configuration, et affiche le correctif exact pour chaque constat9. Sur ce nœud, il a fait 115 contrôles, et il est bon : chaque constat vient avec la commande qui le corrige, ce qui m’a épargné pas mal de recherches.

ConstatRésultatCe que j’ai fait
Hugepages : aucune réservéeFAILréservé les 16 Gio demandés, rendus persistants dans /etc/sysctl.d
Disque de démarrage SN750 : cache d’écriture volatilFAILrien, ce n’est pas un candidat OSD
vfio-pci non chargéWARNrien, ce build n’a pas de SPDK pour s’en servir
limite memlock de 8 MioWARNrien, il mesure le shell ; l’unité fixe LimitMEMLOCK=infinity
pas d’isolcpus / nohz_fullWARNnoté, réglage de latence
IOMMU en traduction, pas iommu=ptWARNnoté
init_on_alloc=1WARNnoté, coûte de 15 à 20 % de CPU sur les grosses lectures, d’après lui
port 2,5 GbE, anneaux de carte réseau par défaut, IRQ sur cinq CPUWARNnoté
8 × P4800X : pas de VWC, 4096+0 actif, x4 à 8 GT/s, libresOK
io_uring avec SEND_ZC et tampons fixes, noyau 7.0OK

Prévoyez le second FAIL. Le contrôle compte tous les contrôleurs de la machine, et le SSD de démarrage a un cache d’écriture, donc il échoue au test de protection contre les coupures, alors même que le contrôle le marque à juste titre « in use, not a candidate ». Le tutoriel dit que le code de sortie 0 signifie aucun FAIL9. Sur tout hôte qui démarre sur un SSD grand public, ce qui fait beaucoup d’hôtes Proxmox, --check ne peut pas sortir en 0, quoi que vous corrigiez. Scriptez sur les lignes de chaque contrôle, pas sur le code de sortie.

Les WARN de réglage sont restés. Chacun exige une modification de la ligne de commande du noyau et un redémarrage, et ceci est un déploiement, pas un benchmark. C’est la bonne liste à traiter avant que quiconque ne cite un chiffre tiré de cette machine.

Cœurs et hugepages pour huit OSD

FlashStore fonctionne en thread par cœur, et le contrôle explique ce que cela veut dire : « one core = one shard/PG owner », au plus 8 cœurs par OSD, et chaque cœur d’OSD sur son propre cœur physique plutôt que partagé avec un frère SMT. Huit cœurs physiques et huit OSD, cela fait un cœur chacun, flashstore_lcores = 0 à 7, les frères SMT étant laissés à Proxmox et aux VM. Relancé avec cela dans la configuration, le contrôle marque chaque plan de cœurs OK.

Cœurs et hugepages sur une machineUn OSD par cœur physique ; frères SMT laissés à l'hôte0: osd.01: osd.12: osd.23: osd.34: osd.45: osd.56: osd.67: osd.7threads 8 à 15 : Proxmox, VM, threads auxiliaires des OSDHugepages : 16 Gio réservés, 4 Gio utilisés par huit OSD4 Gio utilisés12 Gio réservés et inutilisés, sur 58 Gio de l'hôte
Un cœur physique par OSD. Le pool de hugepages est dimensionné selon la valeur par défaut du contrôle, 2048 Mio par OSD, et chaque OSD en service en a pris un quart.

Regardez à nouveau les hugepages. Le contrôle demande 2048 Mio par OSD, ce qui est le --mem par défaut du démon, donc huit OSD exigent 16 Gio réservés. En service, chaque OSD a utilisé 512 Mio sur ses 2048. Cela correspond à la note de conception de croit pour le backend noyau, qui réserve un quart de --mem à son allocateur de charge utile10. Donc sur cette machine, avec les huit OSD en service, 12 Gio de RAM restent réservés en hugepages auxquelles rien ne touche, sur un hôte qui a aussi des VM à nourrir. Un nœud de stockage n’y verrait rien. Sur un nœud Proxmox, cette mémoire, c’était une VM, et plus bas elle est ramenée à ce qu’utilisent les OSD.

Puis-je demander pourquoi il ne peut pas lire ceph.conf ?

Les disques formatés, le paquet installé et le contrôle de l’hôte au propre, le premier OSD refusait de démarrer.

croit-flashstore-tool: refused: /etc/ceph/ceph.conf: Permission denied (os error 13)

Sur Proxmox, /etc/ceph/ceph.conf est un lien symbolique vers /etc/pve/ceph.conf, et /etc/pve est pmxcfs, le système de fichiers de cluster qui garde la configuration de chaque nœud synchronisée. Les fichiers y sont en root:www-data 0640, et pmxcfs ne vous laisse pas changer cela fichier par fichier11. Les démons Ceph de Proxmox s’en accommodent parce qu’ils démarrent en root, lisent la configuration, puis passent à l’utilisateur ceph, ce que fait --setuser ceph --setgroup ceph sur chaque unité ceph-osd@.

L’unité de FlashStore ne démarre pas en root. Elle est en User=ceph dès la première instruction, ExecStartPre compris12, donc elle n’arrive jamais à lire le fichier.

Puis-je demander pourquoi un paquet compilé pour Debian, pour un produit présenté comme un remplacement direct, n’a pas été essayé sur la plateforme Ceph basée sur Debian la plus répandue qui soit ? Je ne demande pas qui. pveceph garde sa configuration sur pmxcfs, et chaque OSD FlashStore sur un nœud géré par pveceph se heurtera à cela à son premier démarrage.

Le démon a déjà la réponse intégrée. Son source décrit un abandon de privilèges classique --setuser/--setgroup : « started as root by a classic unit (--setuser ceph --setgroup ceph), the daemon becomes that user before it opens the store, a socket or a file »13. Un drop-in qui démarre l’unité comme Proxmox démarre ses propres OSD devrait donc suffire.

Pas tout à fait. Démarré en simple root, le refus suivant venait du disque.

activate: device kernel:/dev/ng0n1 not ready: /dev/nvme0n1: Permission denied (os error 13)

Le CapabilityBoundingSet de l’unité omet CAP_DAC_OVERRIDE12, donc root est tenu aux permissions de fichiers ordinaires, et les nœuds du namespace appartiennent à ceph:ceph. Démarrer en root avec le groupe ceph couvre les deux : root possède le fichier de configuration, le groupe ceph ouvre le disque, et le démon passe à ceph avant de faire quoi que ce soit d’autre.

Trois façons de démarrer l'unitéTelle que livréeUser=ceph Group=ceph/etc/pve/ceph.conf root:www-data 0640Lecture de la conf refuséeDémarrage en rootsans CAP_DAC_OVERRIDE/dev/nvme0n1 ceph:ceph 0660Ouverture du disque refuséeRoot, groupe cephpuis --setuser cephconf lue en propriétaire, disque ouvert en groupe,le démon tourne en ceph
L’unité telle que livrée ne peut pas lire pmxcfs. Root seul ne peut pas ouvrir le disque, parce que le bounding set lui retire l’override. Root avec le groupe ceph fait les deux, puis abandonne ses privilèges.
# /etc/systemd/system/croit-flashstore-osd@.service.d/pve-ceph-conf.conf
[Service]
User=root
Group=ceph
ExecStart=
ExecStart=/usr/bin/croit-flashstore-osd run --id %i --cluster ${CLUSTER} -f --setuser ceph --setgroup ceph

Le démon confirme l’abandon dans son propre journal : set uid:gid to 64045:64045 (ceph).

Il existe un correctif plus court, SupplementaryGroups=www-data, et je ne l’ai pas utilisé. Il laisserait l’OSD lire tous les fichiers lisibles par le groupe sous /etc/pve, pas seulement la configuration Ceph. Un OSD n’a rien à faire dans le reste de la configuration du cluster, et le drop-in ci-dessus ne lui donne rien de plus que ce que Proxmox donne aux siens.

Ensuite, les nœuds de périphérique. La doc de FlashStore dit que le nœud du namespace doit être accessible en écriture à ceph, « (udev rule) »14, et le paquet n’en livre aucune. Celle-ci reconnaît les disques par modèle, donc elle ne peut pas attraper le disque de démarrage, quoi que fasse la numérotation :

# /etc/udev/rules.d/70-croit-flashstore-optane.rules
SUBSYSTEM=="nvme-generic", KERNEL=="ng*n*", ATTRS{model}=="Dell Express Flash NVMe P4800X*|INTEL SSDPE21*", OWNER="ceph", GROUP="ceph", MODE="0660"
SUBSYSTEM=="block", KERNEL=="nvme*n*", ENV{DEVTYPE}=="disk", ATTRS{model}=="Dell Express Flash NVMe P4800X*|INTEL SSDPE21*", OWNER="ceph", GROUP="ceph", MODE="0660"

Après udevadm trigger, les seize nœuds Optane étaient en ceph:ceph 0660 et le SN750 restait à root.

Le passthrough que ce noyau refuse

Le tier noyau a deux modes, et c’est le nœud que vous nommez qui choisit. kernel:/dev/ngXnY envoie les commandes NVMe directement au disque via io_uring, ce que croit appelle kernel-cmd. kernel:/dev/nvmeXnY fait des lectures et écritures O_DIRECT sur le périphérique bloc, ce qu’on appelle kernel ou direct10. croit a mesuré kernel-cmd devant dans chaque cas testé10, et le démarrage rapide du README l’utilise1, c’est donc ce que j’ai configuré.

Les permissions réglées, le démon est passé à ceph, a lu sa configuration, et s’est arrêté à la première lecture :

croit-flashstore-osd: --dev kernel:/dev/ng0n1: /dev/ng0n1: kernel-cmd fixed-buffer probe read: Errno(13)

La même sonde était passée une minute plus tôt dans activate, qui avait encore les capacités de root. La question est donc de savoir si ce noyau laisse un processus non privilégié envoyer des commandes d’E/S sur /dev/ngXnY. On peut y répondre sans FlashStore, avec la même lecture via nvme-cli, en tant que ceph :

En tant queCommande sur /dev/ng0n1Résultat
cephIdentify Namespaceautorisé
cephRead, LBA 0, 4 KioPermission denied
rootRead, LBA 0, 4 Kioautorisé

Les huit Optane ont donné la même réponse, y compris deux que je n’avais jamais formatés ni réinitialisés, qui tournent avec le firmware d’Intel et non celui de Dell. Ce ne sont donc pas les disques, et ce ne sont pas les formatages du matin.

L’amont dit que cela devrait marcher. Dans Linux 7.0, nvme_cmd_allowed() laisse un processus non privilégié envoyer une commande d’E/S quand le journal Commands Supported and Effects du disque la marque comme prise en charge sans effets inhabituels, et n’exige une ouverture en écriture que pour les commandes qui écrivent ou modifient des données15. Le journal d’effets du P4800X marque Read comme pris en charge, 00000001, et rien d’autre. La lecture est autorisée.

Le noyau de Proxmox n’est pas celui de l’amont. Son changelog pour ce build inclut un correctif rétroporté sur exactement ce chemin, CVE-2026-90227: nvme/ioctl: check SUBMIT_IO with nvme_cmd_allowed(), qui à première vue couvre un autre ioctl que celui que j’ai testé. Je n’ai pas identifié quel changement du noyau 7.0.14-28-pve fait la différence, et je ne vais pas deviner. Ce qui est certain, c’est le comportement : sur ce noyau, les E/S NVMe en passthrough non privilégiées sont refusées.

FlashStore a un repli pour un passthrough refusé, et il ne s’est pas déclenché. La note de conception de croit dit que lorsque Identify est refusé, un périphérique kernel-cmd bascule en E/S directes sur son nœud bloc et l’annonce au démarrage10. Ici, Identify est autorisé et Read ne l’est pas, donc le repli ne se déclenche jamais et l’OSD s’arrête à la place.

Deux chemins vers le disquekernel-cmd : passthrough NVMekernel : E/S bloc directesio_uring URING_CMD/dev/ng0n1, char génériquerefusé à l'utilisateur ceph : EACCESio_uring READ/WRITE_FIXED/dev/nvme0n1, O_DIRECTmarche : rw sur le nœud suffit
Le passthrough passe par le contrôle de permissions de l’ioctl NVMe, et le noyau de Proxmox le refuse à l’utilisateur ceph. Les E/S directes sur le périphérique bloc n’ont besoin que de la lecture et de l’écriture sur le nœud, que la règle udev donne déjà.

Les E/S directes s’en moquent. C’est une ligne par OSD :

flashstore_store_backend = kernel

Avec cela, osd.0 a démarré.

croit-flashstore-osd: store mounted (1 shards, replayed 4 txns in 16 ms)
croit-flashstore-osd: set uid:gid to 64045:64045 (ceph)
[    1.398] crush location set (create-or-move updating item name 'osd.0' weight 0.3359 at location {host=pve2,root=default} to crush map)
[    2.406] osd.0 is now active (up_from 10, map 10)

Actif en 2,4 secondes.

Préparer et démarrer les OSD

Chaque OSD a une section dans la configuration Ceph, ce qui sur Proxmox veut dire éditer /etc/pve/ceph.conf, et le faire à la main ne pose aucun problème.

[osd.0]
	flashstore_dev = spdk:0000:05:00.0
	flashstore_store_backend = kernel
	flashstore_lcores = 0

Le périphérique est désigné par son adresse PCI, pas par /dev/nvme0n1, et le préfixe spdk: ne veut pas dire SPDK ici. Avec un backend noyau, le démon cherche l’adresse dans sysfs à chaque démarrage et trouve les nœuds actuels du contrôleur10.

Nommer un disque pour qu'il le reste[osd.0]spdk:0000:05:00.0recherche sysfsà chaque démarrage/dev/nvme0n1/dev/ng0n1les numéros nvme suivent l'ordre de détection, et ils ont bougé sur cet hôte :le SN750 était nvme7 en octobre et il est nvme8 maintenant.
Une adresse PCI est fixée par le slot. Un numéro nvme est fixé par l’ordre de détection, qui ne l’est pas.

Ici, cela compte. Le disque de démarrage SN750 était nvme7 en octobre et il est nvme8 maintenant, et les mineurs des nœuds génériques ne suivent pas non plus l’ordre des disques, avec ng1n1 au mineur 0 et ng0n1 au mineur 2. Une configuration qui dit /dev/nvme4n1 peut désigner un autre disque après un redémarrage. Une configuration qui dit 0000:0b:00.0 ne le peut pas.

Ensuite, une commande par disque, qui écrit le magasin et enregistre l’OSD auprès du moniteur :

croit-flashstore-tool prepare --dev spdk:0000:05:00.0 --id 0
kernel-cmd /dev/ng0n1: fixed-buffer NVMe passthrough probe ok (IORING_URING_CMD_FIXED on)
mkfs: device lba 4096 B x 91573146 (375083606016 B), awupf 1 lba, vwc false, max_xfer 32 lba
mkfs: 1 store shards, WAL ring 4096 MiB each
osd.0 prepared in /var/lib/ceph/osd/ceph-0

Deux secondes, en root. prepare lit la clé de bootstrap dans /var/lib/ceph/bootstrap-osd/ceph.keyring16, que pveceph n’écrit que la première fois qu’il crée un OSD à lui, donc sans OSD classique il faut d’abord aller la chercher :

ceph auth get client.bootstrap-osd -o /var/lib/ceph/bootstrap-osd/ceph.keyring

Six disques préparés du premier coup. Deux ont été refusés :

croit-flashstore-tool: refused: device is not empty (non-zero data in the first 8192 bytes); --wipe destroys it
croit-flashstore-tool: refused: device is not empty (non-zero data at 65536 bytes); --wipe destroys it

lsblk et blkid avaient tous deux déclaré ces deux disques vides. Ce qu’il y avait dessus, c’était la zone de métadonnées texte d’un groupe de volumes LVM d’un ancien labo, supprimé depuis longtemps, dont le label en tête avait déjà été mis à zéro. La sonde de FlashStore lit les 8 premiers Kio et les zones à 64 Kio et 256 Kio17, plus loin que ne regardent les outils habituels, et elle avait raison. Refuser un disque qui contient quoi que ce soit, sauf ordre de --wipe, c’est exactement ce que doit faire un outil d’OSD. Les effacer est une décision qui revient au propriétaire des disques, pas à l’outil. Une fois la décision prise, --wipe a préparé les deux en deux secondes environ, et ils ont rejoint le cluster après l’installation plus bas, ce qui explique pourquoi la capture du panneau et les chiffres de l’installation en montrent six.

Ensuite, on les démarre :

systemctl enable --now croit-flashstore-osd@0
ID  CLASS  WEIGHT   TYPE NAME      STATUS  REWEIGHT  PRI-AFF
-1         2.01535  root default
-3         2.01535      host pve2
 0   nvme  0.33589          osd.0      up   1.00000  1.00000
 1   nvme  0.33589          osd.1      up   1.00000  1.00000
 2   nvme  0.33589          osd.2      up   1.00000  1.00000
 3   nvme  0.33589          osd.3      up   1.00000  1.00000
 4   nvme  0.33589          osd.4      up   1.00000  1.00000
 5   nvme  0.33589          osd.5      up   1.00000  1.00000

Chaque OSD s’est placé sous host=pve2 avec la classe de périphérique nvme. Ce qu’ils disent d’eux-mêmes au cluster vaut d’être lu une fois :

ChampMoniteur et gestionnaireOSD FlashStore
ceph versions21.2.0 (087cd25db8f1) umbrella (dev - None)21.2.0 (b060042deb05) umbrella (dev - croit-flashstore-osd)
Compilé parProxmox, paquets -pve1croit, depuis le commit amont v21.2.0 que nomme le README1
osd_objectstorebluestore, avec chaque champ bluestore_bdev_* rempli
Ce que c’est vraimentFlashStore, sans BlueFS, sans RocksDB

La réponse BlueStore est délibérée. flashstore_report_objectstore vaut bluestore par défaut parce que les moniteurs classiques n’activent certaines fonctionnalités que lorsque tous les OSD le déclarent, donc la valeur par défaut garde un cluster mixte en état de marche7. Ce n’est pas vrai, et il vaut mieux le savoir avant de lire les métadonnées du cluster et de les croire.

Ce qu’en fait Proxmox

Le panneau OSD de Proxmox les liste tous les six, up et in, classe nvme, version 21.2.0, 344 Gio chacun. Il les appelle aussi FileStore.

Panneau OSD Ceph de Proxmox listant osd.0 à osd.5 sous l’hôte pve2, classe nvme, OSD Type filestore, up et in, version 21.2.0, 344.00 GiB chacun

FileStore est le magasin d’objets que BlueStore a remplacé. Proxmox déduit l’étiquette dans PVE/API2/Ceph/OSD.pm : si les métadonnées de l’OSD ont une clé bluefs, c’est BlueStore, et tout le reste est FileStore18. FlashStore n’a pas de BlueFS, puisqu’il n’y a pas de RocksDB dessous, donc il déclare BlueStore dans un champ et se fait étiqueter FileStore à partir d’un autre. Aucun des deux n’est juste. Et le panneau est l’endroit où la plupart des admins Proxmox regardent en premier.

Les colonnes de latence affichent 0 / 0 au repos. Pendant l’installation décrite plus bas, ceph osd perf a rapporté des latences de commit de 0 à 3 ms sur les six.

Start, Stop et Restart dans le panneau pilotent ceph-osd@N, l’unité classique, qui n’est pas ce qui tourne19. Le panneau est donc une vue sur ces OSD, pas une commande. Utilisez systemctl … croit-flashstore-osd@N et la CLI pour tout ce qui touche aux démons, et ne touchez surtout pas à « Create: OSD » ni à Destroy sur ceux-ci.

Un pool, un stockage et une VM Fisher-Price OS (Windows)

Le premier PG du cluster, celui du pool .mgr du gestionnaire, est resté undersized+degraded dès que les OSD ont démarré. La faute au nœud unique. La replicated_rule par défaut place chaque copie sur un hôte différent, et il n’y a qu’un hôte.

ceph osd crush rule create-replicated replicated_osd default osd nvme
ceph osd pool set .mgr crush_rule replicated_osd

Une règle avec le domaine de défaillance osd et la classe de périphérique nvme20 place chaque copie sur un OSD différent, et le PG est passé active+clean en quelques secondes. Sur un vrai cluster de trois hôtes ou plus, gardez la règle par hôte et sautez cette étape.

Tout ce qui suit, c’est la GUI de Proxmox comme d’habitude. Ceph → Pools → Create : nom flashstore, size 3, min size 2, règle replicated_osd, Add as Storage coché. Il est passé plus tard en size 2, min size 1, pour le test de charge plus bas.

Panneau des pools Ceph de Proxmox avec les pools .mgr et flashstore sur replicated_osd, et flashstore (pve2) ajouté à l’arborescence du stockage

Proxmox a créé le pool et la définition de stockage RBD d’un coup, et flashstore est apparu dans l’arborescence avec 654 Gio utilisables, soit les 2 Tio bruts divisés par trois copies, moins le surcoût. 129 PG sont passés active+clean, et l’autoscaler a ramené le nouveau pool de 128 à 32 peu après.

L’invité de test est une VM Fisher-Price OS (Windows). Ce n’est pas une préférence, c’est ce qu’une grande partie des clients font réellement tourner sur leurs pools Proxmox, donc c’est la charge qui compte : 16 Gio de mémoire, 4 cœurs, un disque de 60 Gio sur flashstore avec discard et iothread activés. Il est aussi bavard avec le disque et l’utilise de façon inefficace, et c’est tout l’intérêt : un test de stockage veut l’invité qui sollicite le disque le plus fort.

Du disque de VM à l'OptaneDisque de VMscsi0, 60 GioQEMU + librbd21.2.0-pve1pool flashstorereplicated_osd, size 2OSD FlashStore, copie 1OSD FlashStore, copie 2La librbd classique de Proxmox parle aux OSD de croit ; librustyrbd n'est pas installée ici.
Les écritures de la VM passent par la librbd que livre Proxmox, dans la règle du pool, et vers deux OSD FlashStore en size 2. La librustyrbd de croit n’est pas installée, donc c’est un client classique face à des OSD en Rust.

Échantillonnage du pool toutes les dix secondes pendant les quinze premières minutes de l’installation :

Écritures du poolmédiane 9,3 Mo/s en activité, pic à 302 Mo/s
Opérations d’écriturepic à 2 486 par seconde
Lectures du poolpic à 60 Mo/s
Espace brut utilisé35 Gio sur six OSD
SantéHEALTH_OK sur les 90 échantillons
Redémarrages d’OSD0
Mémoire résidente des OSDde 565 à 871 Mio chacun ensuite

Ce sont des chiffres d’installateur, avec la VM et les OSD sur le même hôte et les WARN de réglage intacts, et ils ne disent rien de la vitesse de FlashStore. Ce qu’ils disent, c’est qu’un client Proxmox classique a mené l’installation d’un système d’exploitation sur des OSD en Rust, 35 Gio bruts, sans un défaut, ce qui est précisément ce que cet article voulait tester.

Ce qu’il fait sous charge

Une installation prouve que ça marche. Elle ne vous dit pas ce que la VM donne à l’usage.

La VM a donc eu droit à CrystalDiskMark 9.0.321, trois fois : le profil Real World Performance [+Mix], Read&Write [+Mix], un fichier de 16 Gio sur C : et un mélange de 70 % de lectures et 30 % d’écritures, une fois en trois passes et deux fois en neuf. Ce profil envoie tout une requête à la fois, sur un seul thread, ce que fait réellement un poste de travail ou une petite base de données, pas une fiche technique.

Entre-temps, la configuration avait changé depuis l’installation. La VM avait six cœurs, et le pool avait été passé dans la GUI à size 2, min size 1 et 256 PG. Size 2 avec min size 1 est un réglage de labo sur une seule machine : avec une seule copie restante, le pool continue d’accepter des écritures qu’une seule panne peut alors faire perdre. Partout ailleurs, gardez 3 et 2.

Le disque était sur le réglage par défaut de Proxmox, sans cache, qui est le défaut depuis Proxmox 222.

CrystalDiskMark 9.0.3 dans une VM Fisher-Price OS (Windows) sur le pool flashstore, profil Real World Performance avec un mélange 70/30, 16 Gio sur C:, neuf passes\u00a0: SEQ1M Q1T1 1852,32 Mo/s en lecture, 580,08 en écriture, 986,10 en mixte\u00a0; RND4K Q1T1 23,37, 9,97 et 16,12 Mo/s\u00a0; 5705,57, 2434,81 et 3935,79 IOPS\u00a0; 174,73, 409,77 et 253,25 microsecondes

Real World Performance [+Mix], 16 Gio3 passes9 passes9 passes, à nouveau
SEQ1M Q1T1 lecture1 279,71 Mo/s1 675,33 Mo/s1 852,32 Mo/s
SEQ1M Q1T1 écriture563,67 Mo/s576,65 Mo/s580,08 Mo/s
SEQ1M Q1T1 mixte1 043,75 Mo/s1 043,28 Mo/s986,10 Mo/s
RND4K Q1T1 lecture5 342 IOPS, 186,57 µs5 659 IOPS, 176,17 µs5 706 IOPS, 174,73 µs
RND4K Q1T1 écriture2 419 IOPS, 412,51 µs2 405 IOPS, 414,79 µs2 435 IOPS, 409,77 µs
RND4K Q1T1 mixte3 938 IOPS, 253,13 µs3 826 IOPS, 260,49 µs3 936 IOPS, 253,25 µs

Les écritures et la latence des petits blocs restent à environ 1 % d’un test à l’autre. La lecture séquentielle grimpe de 45 % sur les trois. C’est le premier signe que la colonne de lecture ne mesure pas ce qu’elle semble mesurer.

L’hôte a été échantillonné toutes les cinq secondes pendant les trois tests, depuis /proc/diskstats pour les huit Optane, ceph status pour le pool et /proc pour chaque processus et chaque thread, et les deux points de vue ne racontent pas la même histoire.

Écritures : le disque est la petite partie

Une écriture aléatoire de 4 Kio à la fois, dernier test
Temps par écriture, vu par la VM409,77 µs
Temps par écriture, sur chaque Optane17 µs
Écritures arrivant aux Optane par écriture de la VM4,05 : deux copies, à peu près deux écritures chacune
Grosses écritures séquentielles580 Mo/s depuis la VM, 1,14 Go/s sur les Optane, la deuxième copie double le chiffre

Le disque représente moins de 5 % d’une petite écriture. Les 393 µs restantes, c’est le trajet : QEMU, librbd, le messenger jusqu’à l’OSD, l’OSD lui-même et l’attente de la deuxième copie. Rien de tout cela n’a été mesuré séparément ici, je ne mettrai donc pas de chiffre sur chaque morceau. Ce que cela dit en revanche, c’est que sur cette machine les Optane ne sont pas la limite pour des E/S une à une, et qu’un disque plus rapide ne ferait pas beaucoup bouger ces 410. La limite est passée du côté client, la librbd livrée par Proxmox, et la suite viendra quand la librustyrbd de croit sera déployée ici.

Lectures : le cache, pas les Optane

Lors du dernier test, la passe de lecture aléatoire de 4 Kio a fait 5 700 lectures par seconde sur tout le fichier de 16 Gio, et les huit Optane n’ont rien lu du tout. La passe séquentielle a atteint 2,2 Go/s au pool pendant que les lectures des disques eux-mêmes tombaient de 755 Mo/s à zéro. CrystalDiskMark contourne le cache de l’invité et le disque n’en a aucun dans QEMU, donc la mémoire qui fait le travail est dans les OSD. flashstore_obj_cache est activé par défaut dans ce build, la part du fichier de chaque OSD est d’environ 2 Gio en size 2, et chaque OSD avait grossi jusqu’à environ 2,6 Gio. FlashStore ne rapporte pas ses hits, donc disons quasi certain plutôt que prouvé. C’est aussi pour cela que la lecture séquentielle a progressé à chaque test : une plus grande part du fichier était déjà là. Lisez la colonne de lecture comme un chiffre de cache, pas comme un chiffre du store.

CPU : où sont passés les cœurs

Dernier test, en cœursHôte occupéOSDvCPU de l’invitélibrbd et client CephQEMU
Au repos entre les passes20 à 24 %3,30,10,030,03
Écriture aléatoire 4 Kio30 %3,90,380,200,08
Lecture aléatoire 4 Kio30 %3,60,470,390,15
Mixte séquentiel41 à 53 %3,81,5 à 2,30,50,12

Les trois colonnes de la VM viennent de ses threads : QEMU nomme les vCPU de l’invité, et les threads messenger et worker de librbd tournent dans le même processus.

La colonne des OSD bouge à peine. Huit OSD en polling coûtent 3,3 cœurs à ne rien faire et 3,9 à plein régime, donc sur une machine à 16 threads un cinquième du CPU est parti avant qu’une VM demande quoi que ce soit. Rien d’autre n’a approché sa limite. Le thread le plus occupé était un vCPU de l’invité à 47 %, et le plus occupé de librbd est resté sous 15 %. Avec une requête à la fois, la limite est l’attente, pas le travail, et un chiffre de CPU ne peut pas montrer une attente.

Mémoire : prévoyez le pic

Sur les trois tests
SantéHEALTH_OK dans chaque échantillon, chaque PG active+clean, aucun redémarrage d’OSD
Hugepages utilisées4 Gio du début à la fin
Ce qui reste à distribuer pour l’hôte, avec une VM de 16 Gio en marche3,1 à 4,0 Gio

La ligne des hugepages, c’est la section sur le budget, cette fois sous charge : 512 Mio par OSD, et les 12 Gio restants jamais touchés.

La mémoire ordinaire est le chiffre à surveiller, parce que le cache ci-dessus en est fait. Une fois qu’une lecture avait chargé le fichier, chaque OSD restait à environ 2,5 Gio, et voici ce que Ceph occupait sur un hôte de 58,7 Gio :

Mémoire de Ceph au pic, cible par défaut de 4 Gio
Processus OSD, les huit ensemble19,9 Gio, de 2,4 à 2,6 Gio chacun
Hugepages réservées aux OSD16 Gio, dont 4 Gio utilisés
Moniteur et gestionnaire0,3 Gio
Total36,2 Gio, 62 % de l’hôte
Ce qui reste à distribuer pour l’hôte, avec une VM de 16 Gio en marche3,6 Gio

Elle revient, mais selon aucun calendrier que j’aie pu voir. Elle est restée à 19,9 Gio pendant 25 minutes, pauses comprises, puis est tombée à 13,9 Gio à la fin du dernier test, et l’hôte avait de nouveau 10,2 Gio à distribuer. osd_memory_target était pendant tout cela à sa valeur par défaut de 4 Gio par OSD, donc huit OSD avaient droit à 32 Gio avant même de compter une seule hugepage. Sur un nœud qui doit aussi faire tourner des VM, c’est le pic qu’il faut budgéter avant les disques, et c’est là que les 12 Gio de hugepages inutilisés font le plus mal.

Trois VM à la fois, avec un budget plus serré

Une VM laisse beaucoup de place. À trois, le budget doit être juste. Deux réglages ont donc changé d’abord.

ceph config set osd osd_memory_target 1073741824   # 1 GiB per OSD, was 4
sysctl -w vm.nr_hugepages=2048                     # what eight OSDs use, was 8192

La cible ne demande rien d’autre : chaque OSD a annoncé la nouvelle valeur en quelques secondes, et ils ont quand même été redémarrés un par un, les 257 PG revenant en active+clean avant le suivant. Les hugepages ont un piège. Avant chaque démarrage d’OSD, croit-flashstore-prep veut un --mem entier de libre, 2048 Mio, et agrandit le pool s’il en manque, mais ne le réduit jamais. Le redémarrage d’osd.7 après la réduction a fait remonter le pool aussitôt :

croit-flashstore-prep[7]: hugepages 2048kB: free 256 < need 1024, nr_hugepages 2048 -> 2816

Le plancher qui survit à un redémarrage ou à un reboot, c’est donc ce qu’utilisent les OSD plus la marge d’un démarrage : 2 816 pages, 5,5 Gio, contre les 16 Gio que demande le contrôle. Le script d’installation plus haut réserve désormais exactement cela. Réduire à nouveau à 2 048 une fois les huit démarrés rapporte encore 1,5 Gio jusqu’au prochain redémarrage.

Ensuite, trois clones de la VM, à 10 Gio chacun, ont lancé CrystalDiskMark en même temps : Real World Performance [+Mix], trois passes, mais sur un fichier de 1 Gio chacun au lieu de 16 Gio. La colonne de lecture est donc plus que jamais un chiffre de cache, alors lisez les écritures.

CrystalDiskMark, trois VM à la foisVM 104VM 105VM 106Les troisUne VM seule
SEQ1M Q1T1 écriture346,99 Mo/s318,99 Mo/s446,98 Mo/s1 113 Mo/s580,08 Mo/s
SEQ1M Q1T1 lecture796,05 Mo/s905,03 Mo/s1 160,93 Mo/s2 862 Mo/s1 852,32 Mo/s
RND4K Q1T1 écriture1 901 IOPS1 928 IOPS1 862 IOPS5 691 IOPS2 435 IOPS
RND4K Q1T1 latence d’écriture524,56 µs517,00 µs535,42 µs409,77 µs
RND4K Q1T1 lecture3 773 IOPS3 916 IOPS3 909 IOPS11 598 IOPS5 706 IOPS
RND4K Q1T1 mixte2 978 IOPS3 027 IOPS3 411 IOPS9 416 IOPS3 936 IOPS

Trois VM ont obtenu 2,3 fois les petites écritures d’une seule, et chacune l’a payé d’environ 27 % de latence. Les Optane n’en étaient toujours pas la cause. Elles ont culminé à 20 900 écritures par seconde à 17 µs chacune, les mêmes 17 µs qu’avec une VM, et la plus occupée des huit l’était à 14 %.

Hôte, toutes les cinq secondes pendant le testCible par défaut 4 Gio, une VMCible 1 Gio, trois VM
Plus gros processus OSD2,7 Gio1,15 Gio au pic, 0,8 ensuite
Les huit processus OSD ensemble19,9 Gio8,0 Gio au pic, 5,8 ensuite
Hugepages réservées16 Gio, 4 utilisés4 Gio, tous utilisés
Mémoire donnée aux VM16 Gio30 Gio
Ce qui reste à distribuer pour l’hôte, au plus bas3,1 Gio14,8 Gio
Croissance du swapaucuneaucune

FlashStore respecte donc bien osd_memory_target. Il l’a dépassé de 15 % au pic d’une passe de lecture et est repassé en dessous, le cache faisant son travail dans le budget plutôt qu’en dehors. Entre la cible et la réduction, 26 Gio sont revenus aux VM sur la même machine.

CPU en cœurs, trois VMHôte occupéOSDInvitéslibrbd et client CephQEMU
Trois démarrages de Fisher-Price OS (Windows)81 à 89 %3,4 à 3,66,3 à 7,90,4 à 0,70,3
Benchmark42 à 73 %3,7 à 4,51,2 à 4,00,4 à 1,60,2 à 0,4
Au repos ensuite20 à 24 %3,30,300

Démarrer trois invités a plus sollicité le CPU que les benchmarker. Le stockage en dessous n’en a jamais approché, et c’est le mini PC qui fixe la limite, comme il était écrit qu’il le ferait.

Tout cela, en un seul script

Tout ce qui précède tient dans un seul script. Donnez-lui les adresses PCI des disques que vous voulez comme OSD et il fait le reste, dans l’ordre de cet article, avec les deux correctifs Proxmox intégrés.

flashstore-pve-setup.sh : des OSD FlashStore sur un nœud Proxmox VE flashstore-pve-setup.sh · 17 kB
lspci -D -d ::0108                                    # find the drives
bash flashstore-pve-setup.sh --dry-run 0000:05:00.0   # show the plan, change nothing
bash flashstore-pve-setup.sh 0000:05:00.0 0000:06:00.0
Il vérifieIl écritIl exécute
Proxmox VE 9 et Ceph 21.2.0 Umbrellale trousseau bootstrap-osdune lecture en passthrough en tant que ceph, pour choisir kernel-cmd ou kernel
chaque disque : NVMe, sans cache d’écriture, ni monté, ni partitionné, ni tenule drop-in qui démarre en root puis passe par --setuserprepare et systemctl enable --now pour chaque disque
aucune donnée dans les zones que lit la sonde de FlashStoreune règle udev par disque, par numéro de sériela vérification de l’hôte, qui ne s’arrête que sur ce dont les OSD ont besoin
des blocs de 4 Kioune section [osd.N] par disque, un cœur physique chacunele téléchargement du paquet, vérifié contre le SHA-256 de la version

Rien n’est détruit sans que vous le demandiez. --format-4k reformate un disque qui n’est pas en 4 Kio, un à la fois dans sa propre unité pour que rien ne l’interrompe, et --wipe l’autorise à écraser un disque qui contient des données. --single-node ajoute la règle replicated_osd, et une nouvelle exécution saute les disques qui sont déjà des OSD.

Il a été testé ici, pas seulement écrit. Il a refusé le SN750 à cause de son cache d’écriture, refusé le disque d’osd.7 tant qu’il contenait encore un store, puis, osd.7 purgé et ses nœuds de périphérique rendus à root, l’a reconstruit à partir de rien en 10,5 secondes, en choisissant tout seul le backend kernel. Ce qu’il ne fera pas, c’est installer Ceph. Cette étape vous demande d’accepter une Technology Preview, et c’est votre décision, pas celle d’un script.

Ce qui est à corriger

Rien de tout cela n’arrête un admin déterminé, et tout cela arrêterait un admin débordé. Chaque point est une affirmation que croit fait à quiconque télécharge le paquet, et je me suis heurté à chacun dès le premier essai.

OùCe qui se passeCe qui corrigerait
unité systemdUser=ceph ne peut pas lire pmxcfs, donc l’OSD ne démarre jamais sur un nœud pvecephlivrer le démarrage en root puis --setuser, ou un drop-in Proxmox
repli kernel-cmdne se replie que si Identify est refusé ; sur le noyau de PVE, c’est Read qui l’est, et l’OSD s’arrêtese replier en E/S directes sur toute E/S passthrough refusée
udevla doc exige une règle qui donne à ceph les nœuds du namespace ; aucune n’est livréeen livrer une calée sur les périphériques configurés
synthèse de --checkdit que le NVMe noyau est « compiled out » alors que c’est le seul chemin de stockage compilécorriger le libellé
code de sortie de --checkle SSD de démarrage échoue au test PLP, donc le 0 est inatteignablene noter que les périphériques configurés ou candidats
hugepages2048 Mio par OSD, et prep les veut libres à chaque démarrage ; le backend noyau en utilise 512dimensionner le backend noyau selon son usage, et que prep demande la même chose
sha256sums.txtles noms de fichiers ne correspondent pas aux assets de la releaseles nommer comme publiés
nom du paquetla doc dit apt remove flashstore ; le paquet est croit-flashstore-osdun seul nom, ou le bon dans la doc
référence de flashstore_devne liste que spdk: et file:documenter kernel: et spdk: avec un backend noyau

Rien de tout cela n’est du travail neuf. Le démon a déjà l’abandon de privilèges, le backend direct et la logique de repli. Ils n’ont simplement pas été reliés pour la plateforme sur laquelle la plupart des gens l’essaieront en premier.

C’est dans une préversion qu’on découvre cela

Une préversion est le bon endroit pour chacun de ces constats, et le mauvais endroit pour les y laisser. C’est à cela que sert une préversion : quelqu’un la ramène chez lui, la met sur le matériel qu’il a vraiment, et note où elle tombe. Ce qui compte a tenu. Le magasin a démarré en quelques millisecondes, les OSD ont rejoint un cluster construit par l’outillage de quelqu’un d’autre, et l’installation d’un système d’exploitation s’est faite dessus sans un défaut.

Ce qui l’a fait trébucher, c’est tout ce qu’il y a autour du démon. Un fichier de configuration sur un système de fichiers que l’unité ne pouvait pas lire, un noyau qui dit non à un appel que l’amont autorise, un disque de démarrage que le contrôle ne voulait pas cesser de compter. Rien de tout cela n’est difficile. Tout cela fait la différence entre un logiciel qui marche et un logiciel qui marche sur votre machine, et la seule façon de combler l’écart, c’est de tester sur les machines que les gens ont plutôt que sur celles que vous avez construites pour lui.

Malgré tout, c’est un début prometteur. Sur un mini PC bas de gamme, avec encore la librbd classique côté client et les huit disques sur une seule liaison PCIe 3.0, les Optane travaillent ici plus dur que sous BlueStore. À mesure que cela évolue, j’y reviendrai pour creuser davantage, à mesure qu’une plus grande partie de la pile sera remplacée, avec aussi un regard sur CephFS2.

« Remplacement direct » est une promesse faite à un admin qui n’a pas le temps de lire le source. Les moniteurs de Proxmox, la GUI de Proxmox, le noyau de Proxmox et un paquet de quelqu’un d’autre, c’est exactement la situation à laquelle s’adresse cette promesse. Elle est presque tenue aujourd’hui. Neuf petits correctifs et elle le sera, et je préfère être celui qui les a trouvés un mercredi matin plutôt qu’un client qui les trouve un vendredi soir.


  1. croit/ceph-rust README — en préversion publique depuis le 9 novembre 2026, « not yet recommended for production data », exigences, démarrage rapide, ensemble de fonctionnalités de production, commit Ceph testé. ↩︎ ↩︎ ↩︎ ↩︎ ↩︎ ↩︎ ↩︎

  2. croit/ceph-rust release snapshot-2026-11-10 — les paquets utilisés ici, dont flashstore_…_debian-trixie_amd64.deb et sha256sums.txt. ↩︎ ↩︎

  3. croit/ceph-rust — hardware requirements — contrôle du cache d’écriture volatil, hugepages, notes sur les versions du noyau. ↩︎

  4. croit/ceph-rust — branches and versions — main vise v21.2.0, v20.2.4 vise v20.2.4 ; « The daemon refuses a cluster release outside its supported window. » ↩︎ ↩︎

  5. Proxmox pve-manager, PVE/Ceph/Releases.pm — umbrella listé avec release => '21.2' et unsupported => 1. ↩︎

  6. croit/ceph-rust — build and install packages — distributions, glibc 2.34, gestion de ceph-osd.target, la ligne apt remove. ↩︎ ↩︎ ↩︎

  7. croit/ceph-rust — configuration reference — flashstore_dev, flashstore_lcores, flashstore_report_objectstore et pourquoi il vaut bluestore par défaut. ↩︎ ↩︎

  8. croit-flashstore-osd Cargo.toml — ligne 29, knet = [… "kernel-nvme"]. ↩︎

  9. croit/ceph-rust — first OSD tutorial — le contrôle de l’hôte en lecture seule ; « Exit 0 means no FAIL. » ↩︎ ↩︎

  10. croit/ceph-rust — ADR 0169, kernel NVMe backend — les deux modes noyau, la comparaison mesurée, le budget de l’allocateur de charge utile, la résolution des adresses spdk: et le repli limité à Identify (amendement 6). Ajouté au dépôt le soir même de la release. ↩︎ ↩︎ ↩︎ ↩︎ ↩︎

  11. Proxmox VE — Proxmox Cluster File System (pmxcfs) — le système de fichiers de cluster sous /etc/pve, avec son propriétaire et ses permissions fixes. ↩︎

  12. croit-flashstore-osd@.service — User=ceph, ExecStartPre=… activate, et un CapabilityBoundingSet sans CAP_DAC_OVERRIDE. ↩︎ ↩︎

  13. croit-flashstore-osd privdrop.rs — l’abandon de privilèges classique --setuser/--setgroup. ↩︎

  14. croit/ceph-rust — prepare the host — « the namespace node must be readable and writable by user ceph (udev rule) ». ↩︎

  15. Linux v7.0, drivers/nvme/host/ioctl.c — nvme_cmd_allowed(), la règle du passthrough NVMe non privilégié. ↩︎

  16. croit/ceph-rust — security — « prepare defaults --keyring to /var/lib/ceph/bootstrap-osd/<cluster>.keyring ». ↩︎

  17. croit/ceph-rust — prepare, activate and list — la sonde de périphérique non vide et --wipe. ↩︎

  18. Proxmox pve-manager, PVE/API2/Ceph/OSD.pm — osdtype ne vaut bluestore que si les métadonnées portent bluefs, sinon filestore. ↩︎

  19. Proxmox pve-manager, PVE/Ceph/Services.pm — ceph_service_cmd() associe osd.N à l’unité systemd ceph-osd@N. ↩︎

  20. Ceph documentation — CRUSH maps — règles répliquées, domaines de défaillance et classes de périphérique. ↩︎

  21. CrystalDiskMark — Crystal Dew World’s disk benchmark ; “Various measure mode (Peak/Real World/Demo)”. ↩︎

  22. Proxmox VE wiki — Performance Tweaks — the disk cache modes : “cache=none seems to be the best performance and is the default since Proxmox 2.X”. ↩︎