NVMe/TCP : partagez vos SSD depuis Ubuntu Server, notre script pour vous y aider

NVMe/TCP : partagez vos SSD depuis Ubuntu Server, notre script pour vous y aider

Share kiddie

Avatar de l'auteur
David Legrand

Publié dans

Hardware

21/09/2021 8 minutes
22

NVMe/TCP : partagez vos SSD depuis Ubuntu Server, notre script pour vous y aider

Le protocole NVMe a été pensé pour un accès depuis le réseau (over Fabrics). Si cela nécessite du matériel spécifique lorsque l'on exploite du Fibre Channel ou RDMA, il existe une solution accessible à tous : NVMe sur TCP. Elle est désormais exploitable depuis différentes distributions, dont Ubuntu. Voici comment faire.

S'il est courant de partager des données sur un réseau local via des protocoles comme NFS ou SMB/CIFS, ce n'est pas la méthode la plus efficace ou à utiliser pour donner accès à des HDD/SSD. Présents par exemple dans un serveur afin de les rendre exploitables depuis des clients ultra-compacts ou une machine virtuelle.

D'iSCSI à NVMe/TCP : la révolution du block storage

Pour cela, il faut passer au block storage, le protocole le plus connu étant iSCSI qui est notamment géré par les différents NAS du marché, tels que ceux vendus par ASUSTOR, QNAP ou Synology. Le serveur met alors à disposition une portion de HDD/SSD que le client voit comme un périphérique de stockage local.

Il peut le formater et y créer des partitions comme il le souhaite. On peut même l'utiliser pour installer un système entier comme nous l'avions vu dans un précédent article. Les performances sont plutôt bonnes puisque ce sont des commandes SCSI qui sont envoyées du client au serveur et inversement, encapsulées dans des paquets TCP/IP. 

Mais voilà, à l'heure des SSD PCIe, SCSI n'est plus vraiment la solution de référence pour gérer un périphérique de stockage. C'est pour cela qu'est né NVMe-oF (over Fabrics) pour faire transiter des commandes du protocole NVMe (créé pour gérer efficacement les SSD PCIe) sur un réseau. Différentes solutions existent, plus ou moins coûteuses et simples à implémenter. Mais une est désormais facilement exploitable, accessible à tous : NVMe/TCP.

Pour l'utiliser, il vous faut seulement un serveur avec au moins un SSD et un client sous Linux. L'installation ne demande que très peu de manipulations avec une distribution récente. On vous guide sur la manière de faire sous Ubuntu 21.04 Server, avec un script qui vous permettra d'automatiser entièrement le processus.

Notre dossier sur NVMe-oF :

On prépare le terrain

Nous partirons du principe que vous disposez déjà d'une machine sous Ubuntu Server dans sa dernière version. C'est important, car avant la 21.04 les modules nécessaires à l'utilisation de NVMe/TCP n'étaient pas toujours activés. On commence assez logiquement par mettre le système à jour, et installer ce qu'il faut :

sudo apt update && sudo apt full-upgrade -y && sudo apt autoremove
sudo apt install nvme-cli

L'application installée permet de gérer les périphériques NVMe en ligne de commandes (CLI). On vérifie d'ailleurs que nous avons bien un tel SSD au sein du système, on relève au passage le dossier qui lui correspond :

sudo nvme list

Qui sur notre système donne le résultat suivant :

Node         SN           Model       Namespace Usage                 Format      FW Rev
------------ ------------ ----------- --------- --------------------- ----------- -------
/dev/nvme0n1 2039******** CT500P5SSD8 1 500.11 GB / 500.11 GB 512 B + 0 B P4CR311
/dev/nvme1n1 2039******** CT500P5SSD8 1 500.11 GB / 500.11 GB 512 B + 0 B P4CR311

Le SSD accessible via /dev/nvme0n1 est celui où le système est installé, nous partagerons donc /dev/nvme1n1 sur le réseau via NVMe/TCP. On vérifie pour cela que nous avons les bons modules présents au sein du noyau :

cat /boot/config-`uname -r` | grep NVME_TARGET

Si tout se passe bien, vous devriez voir les lignes suivantes apparaître :

CONFIG_NVME_TARGET=m"
CONFIG_NVME_TARGET_TCP=m"

En langage NVMe/TCP, un serveur contenant des périphériques de stockage partagé est une « target », identifiée par son NQN (NVMe Qualified Name) que nous définirons plus loin.

Partage du périphérique NVMe sur le réseau

Pour continuer la configuration, il nous faut connaître l'adresse IP de la machine, affichez-là avec cette commande :

ip a

Parfois, plusieurs interfaces peuvent être connectées et configurées, notez l'IP de celle de votre choix. Privilégiez des connexions avec un bon débit, une faible latence et évitez bien entendu le Wi-Fi (même si en pratique, ça fonctionne). On peut désormais passer aux choses sérieuses, en activant les modules « nvmet » (t pour target).

sudo modprobe nvmet
sudo modprobe nvmet-tcp

Cela nous permet de créer un NQN (nvme.server.1n1 dans notre cas) :

cd /sys/kernel/config/nvmet/subsystems
sudo mkdir nvme.server.1n1
cd nvme.server.1n1

On permet ensuite à tous les hôtes du réseau de s'y connecter :

echo 1 | sudo tee -a attr_allow_any_host > /dev/null

Notez que NVMe/TCP permet différents modes d'identifications que nous ne couvrirons pas ici. On créé ensuite un espace de noms où l'on déclare et on active notre périphérique de stockage NVMe :

sudo mkdir namespaces/1
cd namespaces/1

echo -n /dev/nvme1n1 | sudo tee -a device_path > /dev/null
echo 1 | sudo tee -a enable > /dev/null

On créé le port (4420) et on l'active pour un transport via TCP en précisant l'IP d'accès (192.168.0.42 dans notre cas) :

sudo mkdir /sys/kernel/config/nvmet/ports/1
cd /sys/kernel/config/nvmet/ports/1

echo 192.168.0.42 | sudo tee -a addr_traddr > /dev/null
echo tcp | sudo tee -a addr_trtype > /dev/null
echo 4420 | sudo tee -a addr_trsvcid > /dev/null
echo ipv4 | sudo tee -a addr_adrfam > /dev/null

Enfin, on créé le lien entre le périphérique et le port créé :

sudo ln -s /sys/kernel/config/nvmet/subsystems/nvme.server.1n1 /sys/kernel/config/nvmet/ports/1/subsystems/nvme.server.1n1

On peut alors vérifier si tout s'est passé correctement via les messages du noyau :

sudo dmesg | grep "nvmet_tcp"

Qui donne dans notre cas le résultat suivant : 

[ 416.988452] nvmet_tcp: enabling port 1 (192.168.0.42:4420)

Accès depuis la machine distante

Passons maintenant sur le client, qui n'a pas forcément besoin d'être sous Ubuntu 21.04 Server. Ici nous utilisons la version de bureau et il nous faut à nouveau vérifier que les modules nécessaires sont présents :

cat /boot/config-`uname -r` | grep NVME

Cette fois cherchez les lignes suivantes :

CONFIG_NVME_CORE=m
CONFIG_NVME_TCP=m

Si elles s'affichent, chargez les modules, mettez à jour le système et installez les outils NVMe :

sudo modprobe nvme
sudo modprobe nvme-tcp

sudo apt update && sudo apt full-upgrade -y && sudo apt autoremove
sudo apt install nvme-cli

On peut alors se connecter à une target NVMe-oF. La première étape est de la découvrir via l'IP du serveur :

sudo nvme discover -t tcp -a 192.168.0.42 -s 4420

Dans notre cas cela donne le retour suivant :

Discovery Log Number of Records 1, Generation counter 2
=====Discovery Log Entry 0======
trtype: tcp
adrfam: ipv4
subtype: nvme subsystem
treq: not specified, sq flow control disable supported
portid: 1
trsvcid: 4420
subnqn: nvme.server.1n1
traddr: 192.168.0.42
sectype: none

On peut alors s'y connecter en précisant le NQN de la target :

sudo nvme connect -t tcp -a 192.168.0.42 -s 4420 -n nvme.server.1n1

Si tout s'est bien passé, vous devriez désormais voir le périphérique distant comme un SSD NVMe local. Vous pouvez désormais le formater comme bon vous semble et l'utiliser. Pour qu'il soit accessible dès le démarrage de la machine, vous devrez répéter le chargement des modules et la connexion manuellement ou via un script.

NVME sur TCP Ubuntu
Un SSD NVMe de 500 Go accessible dans une machine virtuelle, partagé depuis un serveur via NVMe/TCP

Créer simplement un partage NVMe via un script

Les étapes de création de la target, du port et son activation étant fastidieuse voir répétitives lorsque vous avez plusieurs SSD NVMe à partager, nous avons créé un script Bash pour l'automatiser dans Debian et ses dérivés (dont Ubuntu). Il est accessible ici. Il vous suffit de le télécharger et de le lancer. Adaptez-le à votre distribution si nécessaire :

curl -LO https://gist.github.com/davlgd/cab2506b82c9825ddc05e3cb43fc87f7/raw/2a38e128c7da3ed11b288c5cf9ff354b55f1d86b/nvmeTarget.sh
chmod +x nvmeTarget.sh
./nvmeTarget.sh

Il commence par afficher les modules NVME_TARGET du noyau vous permettant de quitter s'ils ne sont pas présents, installe ensuite les outils NVMe et vous demande de préciser l'IP de la machine, le dossier du périphérique à partager et le NQN désiré. Ces valeurs peuvent être précisées dans le fichier pour éviter cette étape.

Vous devrez ensuite préciser si c'est une création de target (C) ou une mise à jour avec de nouveaux périphériques (M). En effet, on peut partager plusieurs SSD NVMe de la sorte et pourquoi pas les monter en RAID ? Une fois ces trois questions posées, tout sera automatiquement activé et le message noyau de confirmation devrait être affiché.

Écrit par David Legrand

Tiens, en parlant de ça :

Sommaire de l'article

Introduction

D'iSCSI à NVMe/TCP : la révolution du block storage

On prépare le terrain

Partage du périphérique NVMe sur le réseau

Accès depuis la machine distante

Créer simplement un partage NVMe via un script

Fermer

Commentaires (22)


Je suis un fier abonné NextInpact depuis des années, je serais encore là pour les prochaines années.


:smack:


Classe! Je ne connaissais pas ce protocole.
Bon, vu que je suis en Wifi, pour le moment je vais rester sur mon mix SMB / (minio)[https://www.nextinpact.com/article/30308/106520-minio-creez-simplement-votre-propre-service-stockage-objet-compatible-s3-et-distribue]



Pour ceux qui ne pratiquent pas trop: iSCSI était super pour partager des disques entre VM, notamment dans le cadre d’un cluster avec continuité de service.


C’est vraiment top de faire des tutoriels technique pour Ubuntu.


Ça n’est pas une erreur donc je ne signale pas, mais il est plus élégant de faire un “grep pattern /path/to/file” plutôt que “cat /path/to/file | grep pattern”
De même que “tee -a” peut être facilement remplacé par “echo >>”
A part ces commentaires de Bash nazi, super intéressant cet article, je pense que je vais expérimenter ça !


Avec ces articles de fond, je vois tout l’intérêt d’être abonné. Merci !



(reply:60071:doktoil makresh)




tee remplace echo parce qu’il faut un sudo, pour grep je regarderais ça :chinois:


sysadmin ici :-)



Pour l’explication détaillée : “echo” est un shell builtin, donc ce n’est pas une commande que l’on peut lancer en sudo, c’est pourquoi tee est nécessaire.



Pour “cat … | grep”, je vois un avantage, c’est la lisibilité, particulièrement pour chaîner les grep.
“grep pattern file” est utile pour trouver dans quel fichier se trouve le pattern (-h)



Sinon pour les débutants en shell, je conseille de regarder du côté de “set -eu -o pipefail”, qui permettent respectivement (e) de quitter le script en cas de code de retour différent de 0, (u) et de quitter en cas de variable non définie, et (-o pipefail) de quitter le script si l’une des commandes dans une série de pipe échoue. Il est parfois nécessaire de revoir certaines constructions dans les scripts, mais c’est indispensable pour des scripts utilisés en prod.



Article très sympa !


Un pti bench’ ?



(reply:60075:Fab’z)




Chaque chose en son temps ;)



En général dans les scripts “publics” j’évite de mettre des commandes de ce type pour ne pas avoir à les expliquer vu qu’elles ne sont pas en rapport avec le sujet traité.



Après pour la gestion d’erreur “automatisée” ça peut être une bonne béquille, mais c’est un peu comme le “catch” général dans certains langages, ça sauve dans certains cas (parce que c’est simple et que ça va vite) mais ce n’est pas forcément l’usage recommandé en pratique (où il vaut mieux une gestion plus fine des erreurs éventuelles même si ça peut prendre un peu de temps au développement).



De mémoire, set -e (et ses dérivés) peut parfois poser problème donc je n’irais pas forcément le recommander à quelqu’un qui ne sait pas trop ce qu’il fait parce qu’il débute, ou alors en le prévenant des potentiels soucis.


Merci pour ces précisions :)



(reply:0:David_L) merci beaucoup pour cet article très intéressant.




Est-ce qu’il existe des mécanismes de sécurité (mot de passe, chiffrement de la communication par TLS avec authentification mutuelle…) sur ce protocole ?



Ou doit-on encapsuler le flux dans un tunnel TLS, SSH… ?



Merci!


De mémoire oui on peut encapsuler dans du TLS (ne serait-ce que si on veut transporter hors d’un réseau “de confiance”) mais je n’ai pas regardé comment le faire pour le moment (ce qui aurait potentiellement complexifié par mal l’explication avec la mécanique de certificats). SSH je ne sais pas je n’ai pas regardé.



Tu as aussi des mécaniques d’auth via les IP des hôtes ou de type “CHAP” (je n’ai plus les références exactes en tête) qui sont en général implémenté dans les appliances qui proposent du NVMe/TCP, mais de mémoire le travail est encore en cours sur certaines, là aussi ça demande de creuser (on en reparlera).



J’ai cru comprendre que Facebook utilisait déjà pas mal NVMe/TCP, donc c’est de toutes façons qu’il doit y avoir toutes les mécaniques suffisante à de la mise en prod, d’une manière ou d’une autre :D



David_L a dit:


J’ai cru comprendre que Facebook utilisait déjà pas mal NVMe/TCP, donc c’est de toutes façons qu’il doit y avoir toutes les mécaniques suffisante à de la mise en prod, d’une manière ou d’une autre :D




Certes, mais Facebook l’utilise sans doute dans ses datacenters, c’est-à-dire un environnement très contrôlé. Alors que par exemple sur un réseau d’entreprise, tu n’es jamais sûr qu’il n’y aura pas un stagiaire un peu indiscret qui écoute ce qui passe sur le LAN de sa station de travail.


David_L le nouveau Jeff Geerling de NXi!!!!



Youppi, je passerais plus de temps sur NXi que sur YouTube!! hihi



Continuez, c’est trop cool!!


J’imagine qu’on ne peut pas partager l’accès au disque pour plusieurs machines pour des risques de corruption de données n’est-ce pas ?


je me pose la question : le NVME-oF est-il utilisable seulement avec un périphérique NVMe ou bien on peut accéder aussi à une pool zfs/raid et si oui, est-ce que cela fonctionne avec une pool utilisant que du NVMe ou bien ça fonctionne avec des périphériques dédiés au cache ?


Le principe est de partager des périphériques, comme expliqué, le formatage se fait côté client. Donc si tu veux faire du ZFS/RAID, tu peux.


oui je sais mais par exemple avec iSCSI tu peux partager un périphérique virtuel. Avec zfs/mdadm tu crées une pool qui est vu par le système comme un volume de stockage au même titre qu’un DD & cie, c’est celui là que tu partages. Ma question est donc : est-ce que ça marche aussi ou volume physique only ?


ça doit être possible mais j’ai du mal à capter l’intérêt de faire ça dans cet ordre, parce que ça revient à faire passer un ZFS/RAID pour un NVMe natif, ce que ça n’est pas pour l’utiliser de manière distante comme un seul périphérique alors qu’on aurait pu tout gérer correctement côté client.



(reply:60175:David_L) Pour moi l’intérêt d’un SAN c’est de retirer la responsabilité du stockage à la machine cliente. On le voit bien avec iSCSI : on partage un LUN et on laisse le SAN s’occuper de gérer son RAID. Ça permet d’avoir d’un côté la machine cliente qui ne perd pas de temps à gérer ça et d’avoir un SAN qui peut facilement augmenter/diminuer/déplacer le stockage, gérer les backups/snapshots de manière transparente pour les clients. Donc si le but de NVMe-oF est d’être un successeur à iSCSI j’espère retrouver ce comportement à terme.




Après faudrait que je me renseigne déjà pour savoir comment est géré un pool/raid de péripéhriques mixtes SATA et NVMe.


L’esprit du block storage c’est de partager un périphérique de stockage brut. Si tu veux tout gérer côté serveur avec un gros niveau de redondance, il y a l’objet/fichier. Certes les NAS nous ont habitué à faire du RAID côté serveur avec des LUN partagés, mais ce n’est pas leur “intérêt” parce qu’on s’éloigne du protocole (ne serait-ce que parce que le périphérique n’est pas SCSI). Avec NVMe-oF le but c’est quand même de passer les commandes brutes au périphérique.



Comme dit plus haut, ça n’empêchera pas la segmentation, mais elle sera gérée de manière plus native, le protocole ayant été pensé pour ça.