Setup-Guide NVMe-oF unter Proxmox VE

KI generiert

NVMe Storage (KI generiert)

NVMe over TCP

Standardmäßig kommuniziert NVMe-oF via TCP auf Port 4420.

 

Voraussetzung

Folgendes Paket muss installiert sein: nvme-cli

apt install nvme-cli -y

Anschließend kann das nvme_tcp Modul manuell geladen werden (nicht persistent über reboots hinweg):

modprobe nvme_tcp

Damit dieses beim booten standardmäßig geladen wird:

echo "nvme_tcp" > /etc/modules-load.d/nvme_tcp.conf

 

Anpassungen der hostnqn

NVMe-oF besitzt wie iSCSI (IQN) eine einzigartige Host-Adresse, die hostnqn.

Die NVMe Base Specification definiert für NVMe Qualified Names (NQN) zwei zulässige Formate. Standardmäßig wird beim Erzeugen der Datei /etc/nvme/hostnqn das UUID-basierte Format verwendet:

nqn.2014-08.org.nvmexpress:uuid:8e5e052f-8c2a-86d1-ed11-f3f8bac1a80e

 

Das Präfix nqn.2014-08.org.nvmexpress ist dabei ausschließlich für diese UUID-Form reserviert und darf nicht mit eigenen Bezeichnern kombiniert werden. Um stattdessen eine sprechende NQN mit dem Hostnamen zu verwenden, muss das domainbasierte Format genutzt werden:

nqn.<jjjj-mm>.<umgekehrte Domain>:<eindeutiger Bezeichner>

 

Dabei gelten folgende Bedingungen:

  • <jjjj-mm>: Jahr und Monat, zu dem die Domain im Besitz der Organisation war.
  • Die Domain wird in umgekehrter Reihenfolge angegeben (z. B. de.example für example.de).
  • Der Bezeichner nach dem Doppelpunkt ist frei wählbar, muss aber innerhalb der NVMe-oF-Umgebung eindeutig sein – hierfür eignet sich der Hostname.
  • Die Gesamtlänge darf maximal 223 Bytes betragen; empfohlen sind Kleinbuchstaben, Ziffern, -, . und :.

Beispiel – Umstellung von UUID- auf Hostnamen-basierte NQN für den Host pve-01:

Vorher: nqn.2014-08.org.nvmexpress:uuid:8e5e052f-8c2a-86d1-ed11-f3f8bac1a80e 
Nachher: nqn.2005-03.de.example:pve-01

Die neue NQN wird in /etc/nvme/hostnqn eingetragen. Die Datei /etc/nvme/hostid bleibt unverändert bestehen. Nach der Änderung muss die neue NQN im Host-Mapping des Storage-Targets hinterlegt werden, da bestehende Zuordnungen auf der alten NQN basieren.

Discovery

NVMe-oF TCP Targets können nun wie folgt erkannt werden:

nvme discover --transport=tcp --traddr=<IP-STORAGE>

Je nach Implementation des NVMe-oF Protokolls auf dem SAN, werden hier alle verfügbaren Controller / IPs des SANs zurückgegeben. In manchen Fällen erhält man allerdings nur ein Log Entry von der IP, auf welchem der Request gestellt worden ist. Meist sind aber noch weitere IPs (bspw. bei hochverfügbaren Multicontroller Systemen) zum Verbinden verfügbar.

 

Eine Ausgabe mit allen Endpunkten sieht bspw. wie folgt aus:

root@pve-01:~# nvme discover --transport=tcp --traddr=192.168.50.10 --trsvcid=4420

Discovery Log Number of Records 2, Generation counter 7
=====Discovery Log Entry 0======
trtype:  tcp
adrfam:  ipv4
subtype: nvme subsystem
treq:    not specified, sq flow control disable supported
portid:  1
trsvcid: 4420
subnqn:  [FAKE]
traddr:  192.168.50.10
eflags:  none
sectype: none
=====Discovery Log Entry 1======
trtype:  tcp
adrfam:  ipv4
subtype: nvme subsystem
treq:    not specified, sq flow control disable supported
portid:  2
trsvcid: 4420
subnqn:  [FAKE]
traddr:  192.168.51.10
eflags:  none
sectype: none
=====Discovery Log Entry 2======
trtype:  tcp
adrfam:  ipv4
subtype: nvme subsystem
treq:    not specified, sq flow control disable supported
portid:  2
trsvcid: 4420
subnqn:  [FAKE]
traddr:  192.168.50.11
eflags:  none
sectype: none
=====Discovery Log Entry 3======
trtype:  tcp
adrfam:  ipv4
subtype: nvme subsystem
treq:    not specified, sq flow control disable supported
portid:  2
trsvcid: 4420
subnqn:  [FAKE]
traddr:  192.168.51.11
eflags:  none
sectype: none

Targets verbinden

Die in der Discovery zurückgegebenen Subsysteme können entweder einzeln pro Portal oder gesammelt verbunden werden.

Einzelnes Target verbinden:

nvme connect --transport=tcp --traddr=192.168.50.10 --trsvcid=4420 -n <subnqn>

Die <subnqn> entspricht dem Wert aus dem jeweiligen Discovery Log Entry. Der Befehl wird für jedes Portal (jede traddr) wiederholt — erst dadurch entstehen mehrere Pfade, die der native NVMe-Multipath zu einem Subsystem zusammenfasst.

Alle Targets eines Discovery-Portals verbinden:

nvme connect-all --transport=tcp --traddr=192.168.50.10 --trsvcid=4420

connect-all führt die Discovery aus und verbindet automatisch alle zurückgegebenen Einträge. Liefert das SAN im Discovery Log alle Controller-IPs zurück (siehe Discovery oben), genügt ein einziger Aufruf für sämtliche Pfade. Gibt das Target hingegen nur Einträge der angefragten IP zurück, muss connect pro Portal-IP ausgeführt werden.

 

Bereits verbundene Subsysteme werden bei erneutem Aufruf mit einer Fehlermeldung quittiert (unterdrückbar mit --quiet); doppelte Verbindungen entstehen dabei nicht.

Das Ergebnis kann anschließend mit nvme list (Namespaces) und nvme list-subsys (Pfade) kontrolliert werden, siehe Targets kontrollieren.

Hinweis: Auf diese Weise aufgebaute Verbindungen überleben keinen Neustart, siehe Automatisches Setup bei Start. Empfohlene Parameter wie --ctrl-loss-tmo=-1 sollten bereits beim manuellen Verbinden mitgegeben werden, siehe Optimierte Multipathing Einstellungen. 

Targets kontrollieren

Die Targets / Pfade können mit nvme list-subsys -v, samt IO-Policy aufgelistet werden.

Allerdings werden die ANA-States (Vergleichbar mit ALUA) nicht angezeigt.

Diese können mit nvme list-subsys -o json /dev/nvme0n1 eingesehen werden (optimized / non-optimized bspw.).

Automatisches Setup bei Start

Targets verbinden

Mit nvme connect bzw. nvme connect-all aufgebaute Verbindungen überleben keinen Neustart. Für den automatischen Verbindungsaufbau beim Booten werden die Discovery-Parameter in der Datei /etc/nvme/discovery.conf hinterlegt, ein Eintrag pro Discovery-Portal:

--transport=tcp --traddr=192.168.50.10 --trsvcid=4420 [--ctrl-loss-tmo=-1 --keep-alive-tmo=10] 
--transport=tcp --traddr=192.168.51.10 --trsvcid=4420 [--ctrl-loss-tmo=-1 --keep-alive-tmo=10] 
--transport=tcp --traddr=192.168.50.11 --trsvcid=4420 [--ctrl-loss-tmo=-1 --keep-alive-tmo=10] 
--transport=tcp --traddr=192.168.51.11 --trsvcid=4420 [--ctrl-loss-tmo=-1 --keep-alive-tmo=10]

 

Bitte ggf. Konfiguration in [] mit Optimierte Multipathing Einstellungen abgleichen.

Beim Systemstart führt der systemd-Service nvmf-autoconnect.service effektiv ein nvme connect-all gegen alle dort hinterlegten Einträge aus und stellt damit sämtliche Pfade automatisch wieder her.

Der Service muss aktiviert sein:

systemctl enable nvmf-autoconnect.service

Prüfen lässt sich der Status mit:

systemctl is-enabled nvmf-autoconnect.service

I/O Policy umstellen

Standardmäßig befinden sich die NVMe-oF Targets in der io-policy numa, um dies bei Start automatisch zu bspw. Round-Robin zu ändern, bedarf es einer udev-Regel.

Folgende I/O Policies sind verfügbar:

Policy            Beschreibung
numa Standard. Pfad mit geringster NUMA-Distanz zur anfragenden CPU, keine Lastverteilung.
=> Wenig sinnvoll, wenn mehrere optimized Pfade verfügbar sind
   
round-robin Verteilt I/O reihum über alle optimierten Pfade (Bandbreitenaggregation).
   
queue-depth Wählt den Pfad mit der geringsten aktuellen Queue-Tiefe.

 

Zur Laufzeit (nicht reboot-fest):

echo "round-robin" > /sys/class/nvme-subsystem/nvme-subsys0/iopolicy #subsys0 entsprechend anpassen

Damit die Policy beim Start automatisch gesetzt wird, ist die udev-Regel /etc/udev/rules.d/71-nvme-io-policy.rules erforderlich:

ACTION=="add|change", SUBSYSTEM=="nvme-subsystem", ATTR{iopolicy}="round-robin"

 

Aktivieren und prüfen zur Laufzeit:

udevadm control --reload-rules
udevadm trigger --subsystem-match=nvme-subsystem
cat /sys/class/nvme-subsystem/nvme-subsys*/iopolicy

Optional: Eingrenzung auf ein bestimmtes Subsystem

Die obige Regel greift für alle NVMe-Subsysteme, also auch für lokale NVMe-SSDs. Bei Single-Path-Geräten ist das wirkungslos und damit unkritisch. Soll die Policy dennoch gezielt nur für ein bestimmtes Target gesetzt werden, kann die Regel über die Subsystem-NQN oder Modell eingegrenzt werden.

NQN des Subsystems ermitteln:

cat /sys/class/nvme-subsystem/nvme-subsys*/subsysnqn

Regel mit NQN-Match:

ACTION=="add|change", SUBSYSTEM=="nvme-subsystem", ATTR{subsysnqn}=="nqn.2002-10.com.infortrend:raid.sn1234567.001", ATTR{iopolicy}="round-robin"

 

Regel mit Model-Match:

ACTION=="add", SUBSYSTEM=="nvme-subsystem", ATTR{subsystype}=="nvm", ATTR{model}=="GS 4000 Series", ATTR{iopolicy}="round-robin"

 

Mehrere Targets lassen sich über zusätzliche Zeilen oder ein Wildcard-Match (z.B. ATTR{subsysnqn}=="nqn.2002-10.com.infortrend:*") abdecken.
 

Weitere Empfehlungen

Die Verwendung von Jumbo Frames (MTU 9000) wird für einen höheren Durchsatz empfohlen. Sofern dies bei allen Teilnehmern konfiguriert werden kann.

LVM konfigurieren

Nach erfolgreicher Konfiguration von Multipath, müssen wir nun zukünftig die /dev/mapper Zuweisung verwenden.

Beispielsweise für 3600144f028f88a0000005037a95d0001 wäre die WWID /dev/mapper/3600144f028f88a0000005037a95d0001

Sofern Sie wie oben Optionale Alias Zuweisung durchgeführt haben, nehmen Sie diese Zuweisung.

Die folgenden Befehle erstellen ein PV und eine VG auf der LUN (ersetzen Sie DEVICE_NAME durch den Namen des Multipath-Geräts und VG_NAME durch den gewünschten Namen für die VG):

  1. pvcreate /dev/mapper/DEVICE_NAME
  2. vgcreate VG_NAME /dev/mapper/DEVICE_NAME

Sie können dann einen LVM-Speicher für dieses VG in der Proxmox-GUI erstellen.

VG in der Proxmox-GUI2

Zu 5: Vergeben Sie eine gewünschte ID, wie der Storage genannt werden soll.

Zu 6: Wählen Sie Ihre zuvor erstellte VG aus.

Zu 7: Wenn mehrere Proxmox VE Nodes auf die LUN zugreifen können, aktivieren Sie „Shared Storage“.

In einem Proxmox VE-Cluster sind die neuen PV und VG möglicherweise nicht sofort auf allen Knoten sichtbar. Um sie auf allen Knoten sichtbar zu machen, können Sie entweder alle Knoten neu starten oder den folgenden Befehl auf allen Knoten ausführen:

pvscan --cache

Weitere Empfohlene Konfigurationen

Optimierte Multipathing Einstellungen

In der Standard-Konfiguration werden Pfade nach ca. 10 Minuten Downtime gelöscht. Diese werden anschließend auch nicht automatisch wieder hinzugefügt und es bedarf einem manuellen Eingriff.

Um dies zu verhindern, müssen bestimmte Parameter in der discovery.conf zusätzlich gesetzt werden:

--transport=tcp --traddr=192.168.50.10 --trsvcid=4420 --ctrl-loss-tmo=-1 --keep-alive-tmo=10
--transport=tcp --traddr=192.168.51.10 --trsvcid=4420 --ctrl-loss-tmo=-1 --keep-alive-tmo=10

 

Parameter    Standardwert Beschreibung
--ctrl-loss-tmo=-1 600 s Zeit, nach der ein unterbrochener Pfad endgültig entfernt wird. Mit -1 verbleibt der Pfad unbegrenzt im Zustand connecting und stellt die Verbindung nach Behebung der Störung selbstständig wieder her, statt gelöscht zu werden.
     
--keep-alive-tmo=10 30 s Keep-Alive-Timeout (KATO) zur Erkennung stiller Pfadausfälle, bei denen die Verbindung ohne TCP-Fehler verstummt (z. B. Switch-Ausfall im Pfad). Verkürzt die Worst-Case-Erkennungszeit von 30 auf 10 Sekunden. Werte unter 5 Sekunden sind nicht empfohlen (Gefahr unnötiger Verbindungsabrisse unter Last).

Beobachtete Probleme

Fehlende Targets nach Boot

Persistente Konfiguration fehlt

Bitte Automatisches Setup bei Start (siehe oben) berücksichtigen

Netzwerkverbindung zu spät verfügbar

Der nvmf-autoconnect.service startet zwar erst nach network-online.target, dieses Target gilt jedoch bereits als erreicht, sobald ifupdown2 die Interfaces konfiguriert hat und nicht, wenn das Netzwerk tatsächlich Pakete transportiert.

LACP-Negotiation am Bond oder STP-Listening/Learning am Switch-Port (ohne Edge-Port-/PortFast-Konfiguration bis zu 30 Sekunden) können zu diesem Zeitpunkt noch andauern. Der einmalig ausgeführte nvme connect-all läuft dann in dieses Zeitfenster: TCP-Connects zu noch nicht erreichbaren Portalen schlagen fehl und werden nicht wiederholt.

Typisches Symptom: Nach dem Boot fehlen einzelne Pfade, ein manueller Connect funktioniert anschließend jedoch problemlos. --ctrl-loss-tmo=-1 hilft hier nicht, da der Parameter nur bestehende Verbindungen schützt und ein nie zustande gekommener Controller kann nicht reconnecten.

Diagnose

Zeitlichen Zusammenhang zwischen Netzwerk-Start und Connect-Fehlern prüfen:

journalctl -b -u networking.service -u nvmf-autoconnect.service -o short-precise

Liegen die connect failed-Meldungen nur Millisekunden bis wenige Sekunden hinter dem Abschluss von networking.service, ist die Race-Condition bestätigt.

 

Mögliche Lösung (statisch): Startverzögerung per systemd-Override

Statt die Unit-Datei direkt zu bearbeiten (würde bei Paket-Updates überschrieben), wird ein Drop-in angelegt:

systemctl edit nvmf-autoconnect.service

Inhalt:

[Service]
ExecStartPre=/bin/sleep 15

Der Service wartet damit 15 Sekunden, bevor nvme connect-all ausgeführt wird und ausreichend für LACP-Verbindungen; bei STP ohne Edge-Port ggf. auf 30–45 Sekunden erhöhen. (Nachhaltiger lässt sich die Ursache switchseitig beheben, indem die Host-Ports als RSTP-Edge-Ports (PortFast) konfiguriert werden, damit entfällt das Forwarding-Delay-Fenster vollständig.) Das Drop-in liegt anschließend unter /etc/systemd/system/nvmf-autoconnect.service.d/override.conf.

Verifikation

Override prüfen und Reboot-Test durchführen:

systemd-delta --type=extended | grep nvmf
systemctl cat nvmf-autoconnect.service

 

Nach dem Neustart müssen alle Pfade vorhanden sein:

nvme list-subsys

 

Zusätzlich im Journal kontrollieren, dass der Service erst nach der Wartezeit ausgeführt wurde und keine Connect-Fehler mehr auftreten:

journalctl -b -u nvmf-autoconnect.service

Noch Fragen?

starline_computer_gmbh_logo
Kevin Fietz
Technik

Unser Experte für unter anderem Ceph, GRAID, PetaSAN und Proxmox