{"id":2086,"date":"2025-06-07T11:05:47","date_gmt":"2025-06-07T10:05:47","guid":{"rendered":"https:\/\/blog.imagmbh.de\/?p=2086"},"modified":"2025-07-29T13:10:27","modified_gmt":"2025-07-29T12:10:27","slug":"linux-boot-via-nfs-mit-bonding-und-bridge","status":"publish","type":"post","link":"https:\/\/blog.imagmbh.de\/index.php\/linux-boot-via-nfs-mit-bonding-und-bridge\/","title":{"rendered":"Linux: Boot via NFS mit Bonding und Bridge"},"content":{"rendered":"\n<p>Ein etwas technischerer Artikel \u00fcber die Problematik &#8211; und die L\u00f6sung &#8211; beim Betrieb einer Linux-Maschine, die \u00fcber PXE bootet, das Root-System \u00fcber NFS bekommt und dieses Root-System nicht nur \u00fcber ein Bonding-Interface bekommt, sondern dieses zus\u00e4tzlich als Bridge bereitgestellt wird.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Die Problemstellung<\/h2>\n\n\n\n<p>Die Problemstellung kam aus der Praxis: Es ging um den erweiterten Ersatz eines VMware-Clusters durch einen Proxmox-Cluster. Der VMware-Cluster startet die Server von SD-Karten. Eine nur sehr beschr\u00e4nkt zuverl\u00e4ssige L\u00f6sung, zumindest dann, wenn auf die SD-Karten auch geschrieben wird: Die SD-Karten stellen einen single point of failure dar und wenn auf die SD-Karten regelm\u00e4\u00dfig geschrieben wird, steigt auch das Ausfallrisiko.<\/p>\n\n\n\n<p>Zur Verf\u00fcgung standen ein modernes SAN, best\u00fcckt mit NVMe, ein &#8222;altes&#8220; SAN mit drehenden Platten, der Rechencluster mit zwei Nodes und redundante 10G-Verbindungen zwischen den Komponenten.<\/p>\n\n\n\n<p>Das moderne SAN, betrieben unter TrueNAS, sollte die virtuellen Platten f\u00fcr die virtuellen Maschinen \u00fcber iSCSI und die 10G-Verbindung bereitstellen, das alte SAN sollte aussortiert werden. Drehende Systeme sind in der heutigen Zeit langsam.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Die erste L\u00f6sung<\/h2>\n\n\n\n<p>Die erste L\u00f6sung war, das TrueNAS in zwei Funktionen zu nutzen: a) als Datenspeicher f\u00fcr die virtuellen Platten, freigegeben an die Nodes via iSCSI und b) also Root-Dateisysteme f\u00fcr die Nodes, freigegeben via NFS.<\/p>\n\n\n\n<p>Die L\u00f6sung ist zwar nicht banal, aber &#8222;eigentlich&#8220; unkritisch: Grunds\u00e4tzlich wird \u00fcber PXE-Boot der DHCP-Server nach den Boot-Parametern befragt, der Node auf den TFTP-Server umgeleitet, von dort wird der Kernel und die initrd geladen, das System f\u00e4hrt hoch. Es muss lediglich eine individuelle initrd erzeugt werden, die das Bonding bereitstellt, damit das per NFS bereitgestellte Root-Dateisysteme \u00fcber Bonding genutzt wird, falls ein Datenweg wegen eines Hardwareschadens zusammenbricht.<\/p>\n\n\n\n<p>Sinnvollerweise wird das Script \u00fcber die pxelinux.cfg gesteuert, hier werden die Slave-Interfaces als Parameter angegeben, die das Script auswertet und zu einem Bonding-Interface zusammenstellt. Au\u00dferdem wird in der pxelinux.cfg angegeben, die die IP-Konfiguration lautet und wo das NFS-Root-System liegt. Der Aufbau ist z. B. unter <a href=\"https:\/\/www.kernel.org\/doc\/html\/v6.1\/admin-guide\/nfs\/nfsroot.html\">https:\/\/www.kernel.org\/doc\/html\/v6.1\/admin-guide\/nfs\/nfsroot.html<\/a> dokumentiert, bei uns sah der Eintrag so aus:<\/p>\n\n\n\n<p><code>DEFAULT vmlinuz-6.8.12-9-pve<br>LABEL vmlinuz-6.8.12-9-pve<br>KERNEL server2\/vmlinuz-6.8.12-9-pve<br>&nbsp;INITRD server2\/initrd.img-6.8.12-9-pve<br>&nbsp;APPEND root=\/dev\/nfs nfsroot=192.168.3.11:\/mnt\/server2,rw ip=:::::bond0:dhcp bondslaves=eno1np0,eno2np1<\/code><\/p>\n\n\n\n<p>Das Script selbst wurde als \/etc\/initramfs-tools\/scripts\/nfs-top\/00_bonding_init angelegt und hat die folgende Gestalt:<\/p>\n\n\n\n<p><code>PREREQS=\"\"<br><strong>case<\/strong> <strong>$1<\/strong> <strong>in<\/strong><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;prereqs) <strong>echo<\/strong> \"<strong>${PREREQS}<\/strong>\"; <strong>exit<\/strong> 0;;<br><strong>esac<\/strong><br><br><strong>echo<\/strong> \"Network interfaces loaded: \"<br><strong>echo<\/strong> <strong>`<\/strong>ls \/sys\/class\/net<strong>`<\/strong><br><br><strong>for<\/strong> x <strong>in<\/strong> <strong>$cmdline<\/strong>; <strong>do<\/strong><br>&nbsp;&nbsp;&nbsp;<strong>case<\/strong> <strong>$x<\/strong> <strong>in<\/strong><br>&nbsp;&nbsp;&nbsp;bondslaves=*)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;bondslaves=\"<strong>${x#bondslaves=}<\/strong>\"<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;;;<br>&nbsp;&nbsp;&nbsp;<strong>esac<\/strong><br><strong>done<\/strong><br><br>ip link add bond0 <strong>type<\/strong> bond &nbsp;<br><strong>echo<\/strong> active-backup &gt; \/sys\/class\/net\/bond0\/bonding\/mode<br><strong>echo<\/strong> 1 &gt; \/sys\/class\/net\/bond0\/bonding\/miimon<br>IFS=\",\"<br><strong>for<\/strong> x <strong>in<\/strong> <strong>$bondslaves<\/strong>; <strong>do<\/strong><br>&nbsp;&nbsp;&nbsp;<strong>echo<\/strong> \"+<strong>$x<\/strong>\" &gt; \/sys\/class\/net\/bond0\/bonding\/slaves<br><strong>done<\/strong><\/code><\/p>\n\n\n\n<p>Kein Hexenwerk, das System startete und lief. Die Simulation der Leitungsausf\u00e4lle (Ziehen einer Netzwerkverbindung, Auschalten eines Switches) funktionierte, alles wie gew\u00fcnscht.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Der Ehrgeiz des Administrators<\/h2>\n\n\n\n<p>Wir hatten also eine sch\u00f6nes, redundantes und funktionierendes System. Und wir hatten ein &#8222;altes&#8220; SAN mit vielen TB Kapazit\u00e4t. Viel zu schade, um es zu entsorgen. Es w\u00e4re prima geeignet als Datenablage, als Backupplatz etc&#8230;<\/p>\n\n\n\n<p>Die beste Anbindungsm\u00f6glichkeit f\u00fcr das SAN ist iSCSI, also die Bereitstellung von Blockdevices. Nun sollten diese Blockdevices direkt den VMs bereitgestellt werden. Der Virtualisierungshost w\u00fcrde unn\u00f6tig &#8222;aufgeblasen&#8220;, wenn er f\u00fcr diese Blockdevices als Initiator dienen und sie dann an die VMs weiter geben w\u00fcrde. Sinnvoller ist, es dann die VMs selbst Initiator werden. Nur dann k\u00f6nnen die VMs auch zwischen den verschiedenen Nodes verschoben werden.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Die Probleme<\/h2>\n\n\n\n<p>Doch mit diesem guten Gedanken kommen die Probleme:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Damit die VMs auf die iSCSI-Targets zugreifen k\u00f6nnen, m\u00fcssen sie im selben Netzwerk liegen.<\/li>\n\n\n\n<li>Dies bedeutet, dass die Netzwerkkarte, die auf dem Node an dem Netzwerk angebunden ist, eine Bridge bilden muss: Der Node und die VMs m\u00fcssen die Netzwerkkarte nutzen.<\/li>\n<\/ul>\n\n\n\n<p>Unter Proxmox ist die Bildung einer Bridge Standard. Normalerweise ist in der \/etc\/network\/interfaces z.  B. wie folgt konfiguriert:<\/p>\n\n\n\n<p><code>auto lo<br>iface lo inet loopback<br>iface eno1 inet manual<br><br>auto vmbr0<br>iface vmbr0 inet static<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;address 192.168.3.2\/24<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;gateway <code>192.168.3<\/code>.1<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;bridge-ports eno1<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;bridge-stp off<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;bridge-fd 0<\/code><\/p>\n\n\n\n<p>Das System f\u00e4hrt hoch und konfiguriert das Netzwerk.<\/p>\n\n\n\n<p>Das Problem liegt in unserem Fall jedoch darin, dass diese Konfiguration im Root-Dateisystem liegt. Das hei\u00dft, die Netzwerkverbindung, die ge\u00e4ndert werden soll, wurde und wird zu dem Zeitpunkt der \u00c4nderung schon genutzt, um auf das Root-Dateiesystem zuzugreifen. Man z\u00f6ge in diesem Szenario also dem Node das Root-System weg. Die Folge ist ein gnadenloser Absturz.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Der L\u00f6sungsgedanke: Bildung der Bridge in der initrd<\/h2>\n\n\n\n<p>Somit muss die Bridge analog zum Bonding schon in der initrd gebaut werden, dann die IP-Adresse per DHCP \u00fcber das Bridgeinterface geholt werden. Grunds\u00e4tzliche Anpassung an der pxelinux.cfg:<\/p>\n\n\n\n<p><code>ip=:::::vmbrX:dhcp<\/code><\/p>\n\n\n\n<p>Und Anpassung des Scriptes um die Zeilen der Bridgebildung:<\/p>\n\n\n\n<p><code>brctl addbr vmbrX<br>brctl addif vmbrX bond0<\/code><\/p>\n\n\n\n<p>Trivial, oder? Die L\u00f6sung hat nur einen Nachteil: Sie funktioniert nicht. Das Debugging ergab: Es werden keine DHCP-Request abgesetzt. Die Codeanalyse, Funktion configure_networking in der Datei scripts\/functions der initrd f\u00fchrte nicht weiter. Alles wurde korrekt ausgef\u00fchrt, das Programm ipconfig in der initrd machte die korrekten DHCP-Anfragen (ja, in der initrd ist f\u00fcr die DHCP-Anfragen das Programm ipconfig zust\u00e4ndig), doch diese Anfragen tauchten nicht im Netzwerk auf. Was war anders, wo war das Problem?<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Die L\u00f6sung der fehlenden Anfragen<\/h2>\n\n\n\n<p>Die L\u00f6sung ist so banal wie versteckt. Wir arbeiten mit gestapelten Netzwerkinterfaces: Unten die physischen Interfaces, dar\u00fcber das Bonding-Interface und dar\u00fcber die Bridge. Ursache war, dass das o.g. Standardscript, configure_networking, das Bondiginterface zwar konfigurierte jedoch nicht startete. Ist nur das Bondinginterface vorhanden, wird es durch ipconfig bei der DHCP-Anfrage gestartet. Genauso startete ipconfig beim Stack die Bridge. Die unten liegende physischen Interfaces werden bei der Bonding-Konfiguration gestartet. Doch das Bondinginterface wurde beim Stack nicht &#8222;durch eine &#8222;nebenbei&#8220; mitgestartet, so dass es ausdr\u00fccklich gestartet werden muss.<\/p>\n\n\n\n<p>Diesen Start eingebaut und siehe: Alles funktioniert: Der Node startet per PXE und NFS-Root \u00fcber das Bridgeinterface, diese steht dann den VMs zur Verf\u00fcgung, so dass diese iSCSI-Initiatoren sein k\u00f6nnen.<\/p>\n\n\n\n<p>Haben Sie Fragen zur L\u00f6sung, unserem Vorgehen beim Debugging, zum Netzwerkbridgeing und Bonding: Nehmen Sie mit uns, der <a href=\"https:\/\/imagmbh.de\/kontakt\">ima GmbH, Kontakt<\/a> auf!<\/p>\n\n\n\n<p><code><br><\/code><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Ein etwas technischerer Artikel \u00fcber die Problematik &#8211; und die L\u00f6sung &#8211; beim Betrieb einer Linux-Maschine, die \u00fcber PXE bootet, das Root-System \u00fcber NFS bekommt und dieses Root-System nicht nur \u00fcber ein Bonding-Interface bekommt, sondern dieses zus\u00e4tzlich als Bridge bereitgestellt wird. Die Problemstellung Die Problemstellung kam aus der Praxis: Es ging um den erweiterten Ersatz [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":2088,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[5,53,141],"tags":[330,331,332,202,333],"class_list":["post-2086","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-administration","category-aus-dem-leben-eines-administrators","category-linux","tag-bonding","tag-bridges","tag-nfs-root","tag-proxmox","tag-pxe-boot"],"_links":{"self":[{"href":"https:\/\/blog.imagmbh.de\/index.php\/wp-json\/wp\/v2\/posts\/2086","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/blog.imagmbh.de\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blog.imagmbh.de\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blog.imagmbh.de\/index.php\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.imagmbh.de\/index.php\/wp-json\/wp\/v2\/comments?post=2086"}],"version-history":[{"count":6,"href":"https:\/\/blog.imagmbh.de\/index.php\/wp-json\/wp\/v2\/posts\/2086\/revisions"}],"predecessor-version":[{"id":2095,"href":"https:\/\/blog.imagmbh.de\/index.php\/wp-json\/wp\/v2\/posts\/2086\/revisions\/2095"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/blog.imagmbh.de\/index.php\/wp-json\/wp\/v2\/media\/2088"}],"wp:attachment":[{"href":"https:\/\/blog.imagmbh.de\/index.php\/wp-json\/wp\/v2\/media?parent=2086"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.imagmbh.de\/index.php\/wp-json\/wp\/v2\/categories?post=2086"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.imagmbh.de\/index.php\/wp-json\/wp\/v2\/tags?post=2086"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}