Debian-Live Netzbootsystem: Unterschied zwischen den Versionen

Aus Knowledgebase
Zur Navigation springen Zur Suche springen
 
K (→‎TFTP-Server: Hinweis verschoben.)
 
(3 dazwischenliegende Versionen desselben Benutzers werden nicht angezeigt)
Zeile 1: Zeile 1:
Das '''Debian-Live'''-Projekt hat für Wiederherstellungszwecke eine Live-Bootcd-Serie bereitgestellt. Diese gibt es als ISO-Datei als auch in Archivform zum Aufsetzen eines Netzbootsystems. Der Artikel beschreibt die notwendigen Schritte, dieses Netzbootsystem unter Debian Linux aufzusetzen. Dabei kann zum Bootzeitpunkt ausgewählt werden, ob ein 32- oder ein 64-Bit-System gestartet werden soll.
Die Möglichkeit, hinreichend aktuelle Maschinen (allgemein, also VMs oder auch Blech) über das LAN zu booten ist eine feine Sache. Bare Metal Restore, oder auch die Offline-Korrektur von Fehlern wie z. B. zu kleinen Partitionen, etc. wird damit zum Kinderspiel.
 
Das '''Debian-Live'''-Projekt hat für Wiederherstellungszwecke eine Live-Boot CD-Serie bereitgestellt. Allerdings haben diese Images ein paar (teils subjektive) Nachteile:
* Gewohnte Konfigurationstools wurden durch modernere Varianten mit eigener Syntax abgelöst; ein Paradebeispiel ist das Fehlen von <code>ifconfig</code>.
* Hardware welche proprietäre Firmware-Binärdateien benötigt ist — vor allem wenn es um Netzwerkkarten geht — außen vor; ein Booten vom Netz geht spätestens nach dem Starten des Kernels schief.
* Viele weitere Pakete mit fast immer benötigten Tools fehlen und müssen immer und immer wieder per Hand nachinstalliert werden.
 
Der Artikel beschreibt die notwendigen Schritte, dieses Netzbootsystem auf einem existierenden Debian Linux 12 (Bookworm) aufzusetzen. Ob die zu startende Maschine ein älteres BIOS-basiertes System ist oder ein neueres EFI-System, ist egal: Beides wird dynamisch anhand von DHCP-Optionen passend konfiguriert. Dabei kann zum Bootzeitpunkt ausgewählt werden, ob ein 32- oder ein 64-Bit-System gestartet werden soll.
 
Es ist selbstverständlich möglich, weitere via PXE zu startende Betriebssysteme einzubinden. Wichtig ist zu beachten, dass die via TFTP bereitgestellten Dateien in den entsprechenden Unterverzeichnissen für die verschiedenen Architekturen zu hinterlegen sind (bios, efi32, efi64).
 
<blockquote>'''Hinweis''': Das von mir benutzte System ist traditionell mit ''SysV-init'' ausgerüstet. ''Systemd'' wird nicht benutzt. Die hier aufgeführten Schritte sind ansonsten so generisch wie möglich gehalten.</blockquote>


== Benötigte Komponenten ==
== Benötigte Komponenten ==
* DHCP-Server (für die Zuweisung grundlegender Netzwerkparameter),
* ''DHCP-Server'' für die Zuweisung grundlegender Netzwerkparameter,
* TFTP-Server (für den initialen Zugriff auf Kernel und Initrd),
* ''TFTP-Server'' für den initialen Download von Bootloader, Menü und anschließend Kernel und Initrd,
* FTP/HTTP-Server (für den Zugriff auf das komprimierte Root-Dateisystem),
* ''NFS-Server'' für den Zugriff auf das komprimierte Root-Dateisystem,
* Die Archivdatei von [http://cdimage.debian.org/cdimage/release/current-live/ http://live.debian.net/] aus dem ''net''-Unterverzeichnis (mit den benötigten Komponenten).
* ''Scripte'' zur Erstellung des übers Netz geladenen Root-Dateisystems.
 
Installation:
apt-get install openbsd-inetd isc-dhcp-server tftp-hpa tftpd-hpa nfs-kernel-server pxelinux syslinux-common syslinux-efi debootstrap squashfs-tools
 
== DHCP-Konfiguration ==
<blockquote>'''Hinweis''': Im lokalen Netzwerksegment soll nur '''ein''' DHCP-Server aktiv sein. Sind es mehrere, ist es mehr oder weniger Zufall, welches Antwortpaket der anfragende Client zuerst bearbeitet. Sollte also schon ein DHCP-Server existieren, muss die gezeigte Konfiguration in die bestehende Konfiguration eingebaut werden. Durch die Benutzung von DHCP-Klassen ("class") ist dies im Regelfall aber sehr einfach möglich.</blockquote>
 
Der erste Start des noch nicht unkonfigurierten DHCP-Servers geht erfahrungsgemäß schief, dies kann ignoriert werden.
 
Weil hier nur IPv4 berücksichtigt wird, muss in ''/etc/default/isc-dhcp-server die Zeile ''INTERFACESv6'' gelöscht werden. Ebenso muss in ''INTERFACESv4'' das für DHCP zu verwendenden Netzwerkinterface eingetragen werden. Beispiel:
INTERFACESv4="eth0"
 
Dies ist ein '''Beispiel''' für eine DHCP-Konfiguration! Insbesondere der ''group''-Abschnitt muss auf die lokalen Gegebenheiten angepasst werden!
<syntaxhighlight lang="shell">
authoritative;
ddns-updates off;
default-lease-time 3600;
log-facility daemon;
max-lease-time 86400;
min-lease-time 300;
min-secs 0;
 
option architecture-type code 93 = unsigned integer 16; # RFC4578
 
# Route different kinds of requesting clients to distinct PXE bootloaders.
class "pxeclients" {
    match if substring (option vendor-class-identifier, 0, 9) = "PXEClient";
 
    if option architecture-type = 00:00 {
        filename "/var/tftpboot/bios/lpxelinux.0";
    } elsif option architecture-type = 00:06 {
        filename "/var/tftpboot/efi32/syslinux.efi";
    } elsif option architecture-type = 00:07 {
        filename "/var/tftpboot/efi64/syslinux.efi";
    } elsif option architecture-type = 00:09 {
        filename "/var/tftpboot/efi64/syslinux.efi";
    }
 
    # This is the TFTP server's IP address.
    next-server 192.168.111.10;
}
 
# Ethernet
group {
    option broadcast-address 192.168.111.0;
    option domain-name "pocnet.net";
    option domain-name-servers 192.168.111.10;
    option ntp-servers 192.168.111.10;
    option routers 192.168.111.1;
    option subnet-mask 255.255.255.0;
 
    subnet 192.168.111.0 netmask 255.255.255.0 {
        range 192.168.111.120 192.168.111.126;
    }
}
</syntaxhighlight>
 
Nun kann der DHCP-Server gestartet werden:
service isc-dhcp-server start


Ein PXE-Daemon wird nicht benötigt, während NFS optional ist.
== TFTP-Server ==
Die Konfiguration des Servers findet sich in ''/etc/default/tftpd-hpa''. Dort müssen folgende Änderungen durchgeführt werden:
* Ändern des Pfades ''/srv/tftp'' nach ''/var/tftpboot'',<ref>Ist kein Muss, aber in dieser Anleitung wird dieser Pfad vorausgesetzt.</ref>
* Ändern der ''TFTP_OPTIONS'':<ref>Dies ist notwendig, damit die später angelegten Symlinks auch aufgelöst werden.</ref>
** Löschen von <code>--secure</code>,
** Hinzufügen von <code>--permissive -v</code>.


=== DHCP-Konfiguration ===
Nun kann der alte Pfad gelöscht werden und der neue angelegt:
In der DHCP-Konfigurationsdatei exemplarisch:
rmdir /srv/tftp
  subnet 192.168.59.0 netmask 255.255.255.192 {
mkdir /var/tftpboot
        range 192.168.59.30 192.168.59.39;
 
        next-server 192.168.59.10;
Als letztes sollte der TFTP-Server neu gestartet werden:
        option subnet-mask 255.255.255.192;
service tftpd-hpa restart
        option broadcast-address 192.168.59.63;
 
        option routers 192.168.59.1;
=== Inhalte für <code>/var/tftpboot</code> ===
Zuerst werden ein paar grundlegende Verzeichnisse für die benötigten Dateien angelegt:
  cd /var/tftpboot
mkdir -p deb-live/amd64 deb-live/i686 bios efi32 efi64 pxelinux.cfg
 
Für die einzelnen Architekturen werden nun die benötigten Bootdateien über Symlinks bereit gestellt. Symlinks brauchen weniger Speicher und wenn das Original (wegen Aktualisierungen) ausgetauscht wird, braucht man nicht mehr manuell nachbessern.
 
<syntaxhighlight lang="shell">
# BIOS-Loaders
cd bios
ln -s ../deb-live .
ln -s ../pxelinux.cfg .
ln -s ../../../usr/lib/syslinux/modules/bios/ldlinux.c32 .
ln -s ../../../usr/lib/syslinux/modules/bios/libcom32.c32 .
ln -s ../../../usr/lib/syslinux/modules/bios/libutil.c32 .
ln -s ../../../usr/lib/syslinux/modules/bios/mboot.c32 .
ln -s ../../../usr/lib/syslinux/modules/bios/menu.c32 .
ln -s ../../../usr/lib/syslinux/modules/bios/pxechn.c32 .
ln -s ../../../usr/lib/syslinux/modules/bios/vesamenu.c32 .
ln -s ../../../usr/lib/PXELINUX/lpxelinux.0 .
 
# EFI32-Loaders
cd ../efi32
ln -s ../deb-live .
ln -s ../pxelinux.cfg .
ln -s ../../../usr/lib/syslinux/modules/efi32/ldlinux.e32 .
ln -s ../../../usr/lib/syslinux/modules/efi32/libcom32.c32 .
ln -s ../../../usr/lib/syslinux/modules/efi32/libutil.c32 .
ln -s ../../../usr/lib/syslinux/modules/efi32/mboot.c32 .
ln -s ../../../usr/lib/syslinux/modules/efi32/menu.c32 .
ln -s ../../../usr/lib/syslinux/modules/efi32/vesamenu.c32 .
ln -s ../../../usr/lib/SYSLINUX.EFI/efi32/syslinux.efi .
 
# EFI64-Loaders
cd ../efi64
ln -s ../deb-live .
ln -s ../pxelinux.cfg .
ln -s ../../../usr/lib/syslinux/modules/efi64/ldlinux.e64 .
ln -s ../../../usr/lib/syslinux/modules/efi64/libcom32.c32 .
ln -s ../../../usr/lib/syslinux/modules/efi64/libutil.c32 .
ln -s ../../../usr/lib/syslinux/modules/efi64/mboot.c32 .
ln -s ../../../usr/lib/syslinux/modules/efi64/menu.c32 .
ln -s ../../../usr/lib/syslinux/modules/efi64/vesamenu.c32 .
ln -s ../../../usr/lib/SYSLINUX.EFI/efi64/syslinux.efi .
</syntaxhighlight>
 
Um die Pflege des PXE-Bootmenüs zu vereinfachen, wird eine "globale" Konfiguration in ''/var/tftpboot/pxelinux.cfg'' (der Standardname, mit dem die PXE-Loader nach der Konfiguration suchen) für alle Architekturen via Symlinks zugänglich gemacht.
 
Die eigentliche Konfiguration für das Bootmenü findet sich in der Datei ''/var/tftpboot/pxelinux.cfg/default'':
menu title Boot menu
menu tabmsg Press ENTER to boot or TAB to edit a menu entry
prompt 0
timeout 600
   
   
        if substring( option vendor-class-identifier, 0, 9 ) = "PXEClient" {
label deblive64
                filename "pxelinux.0";
    menu label Debian Live ^amd64
        } else {
    kernel deb-live/amd64/vmlinuz
                filename "";
    append initrd=deb-live/amd64/initrd.img net.ifnames=0 biosdevname=0 ip=:::::eth0:dhcp boot=live netboot=nfs root=/dev/nfs nfsroot=192.168.1.10:/var/nfsboot/deb-live/amd64 live-media-path=/ consoleblank=0 nfsrootdebug
                option root-path "192.168.59.10:/var/nfsroot";
        }
label deblive32
  }
    menu label Debian Live ^i686
    kernel deb-live/i686/vmlinuz
    append initrd=deb-live/i686/initrd.img net.ifnames=0 biosdevname=0 ip=:::::eth0:dhcp boot=live netboot=nfs root=/dev/nfs nfsroot=192.168.1.10:/var/nfsboot/deb-live/amd64 live-media-path=/ consoleblank=0 nfsrootdebug
label bootlocal
    menu label Boot ^local disk
    menu default
    localboot 0
ui menu.c32
 
* <code>net.ifnames=0 biosdevname=0</code> stellt die ursprüngliche, aufsteigende Nummerierung vom Kernel wieder her, damit die Netzwerkschnittstelle überall wieder ''eth0''heißt und diese wiederum in der <code>ip=</code>-Konfigurationszeile statisch referenziert werden kann.<ref>Früher hat die Autokonfiguration bei mehreren vorhandenen Netzwerkschnittstellen nicht zuverlässig funktioniert, deswegen der gezeigte Workaround.</ref>
* Das Zirkumflex (<code>^</code>) dient als Hervorhebung für einen Buchstaben im Menü. Dieser Buchstabe auf der Tastatur eingegeben aktiviert diesen Menüeintrag.
 
== NFS-Server ==
In der Datei ''/etc/exports'' wird definiert, welche Hosts auf welche Verzeichnisse Zugriff haben:
  /var/nfsboot    192.168.1.0/24(ro,no_root_squash,insecure,no_subtree_check)


=== TFTP-Server ===
Nun müssen die Verzeichnisse für das Rootdateisystem noch angelegt werden:
Ich empfehle das Paket ''atftpd'', allerdings im ''Inetd''-Modus:
  mkdir -p /var/nfsboot/deb-live/amd64 /var/nfsboot/deb-live/i686
  tftp            dgram  udp    wait    nobody.nogroup  /usr/sbin/atftpd        atftpd /var/tftpboot


=== FTP/HTTP-Server ===
Damit die Änderungen ziehen, einmal den (mangels gültiger Einträge in ''exports'' sowieso nicht gestarteten) NFS-Server starten:
Meist ist auf den Maschinen sowieso ein Apache installiert, oft auch ein FTP-Server (wie z.&thinsp;B. ''vsftpd''). Auf die Konfiguration gehe ich hier nicht weiter ein.
service nfs-kernel-server start


== Einrichtung ==
== Root-Dateisystem ==
Durch Auspacken des oben genannten Archives werden die Verzeichnisse ''debian-live/'' und ''tftpboot/'' erzeugt.
Dies wird über eine "frische" Installation von Debian von Grund auf neu erzeugt:
* Debootstrap,
* Konfigurationsanpassungen,
* Squashfs-Build.


Die Datei ''debian-live/live/filesystem.squashfs'' wird in einem Verzeichnis abgelegt, auf welches der FTP- und/oder HTTP-Server Zugriff besitzen. Wenn der Dateiname eindeutig behandelt wird, können im gleichen Verzeichnis unterschiedliche Architekturen abgelegt werden (z.&thinsp;B. ''debian-live-6.0.1-amd64.squashfs'' und ''debian-live-6.0.1-i386.squashfs''). Der Name wird später in der PXE-Konfiguration referenziert und ist daher frei wählbar.
Das folgende Script kann mit den Parametern ''amd64'' oder ''i686'' aufgerufen werden und erzeugt jeweils ein Squashfs in den zuvor angelegten Verzeichnissen in ''/var/nfsboot''.


Im Unterverzeichnis ''tftpboot/'' finden sich die für den TFTP-Server notwendigen Dateien, die der PXE-Loader der Clientnetzwerkkarte benötigt. Das Verzeichnis ''tftpboot/debian-install/'' wird nicht benötigt und kann gelöscht werden. Der Inhalt von ''tftpboot/debian-live/i386/'' (und/oder amd64) kann direkt nach ''/var/tftpboot/debian-live/'' verschoben werden. Die einzige architekturabhängige Datei mit gleichem Namen ist ''memtest''. Diese kann ebenfalls umbenannt werden (z.&thinsp;B. ''memtest-i386'' und ''memtest-i686''). Nicht benötigte Kernel z.&thinsp;B. für 486-Prozessoren können gelöscht werden.
<syntaxhighlight lang="shell">
#!/bin/bash


Die Datei ''pxelinux.0'' sowie das Verzeicnhnis ''pxelinux.cfg'' müssen direkt nach ''/var/tftpboot/'' verschoben werden und die Include-Zeile in ''pxelinux.cfg/default'' auf den nun neuen, relativen Pfad angepasst werden:
# Must run as root.
include debian-live/boot-screens/menu.cfg
if ! id |grep -Fq 'uid=0(root) gid=0(root) groups=0(root)'; then
    echo "Must run as root."
    exit 1
fi


Die folgenden Dateien in ''boot-screens/'' müssen angepasst werden:
# Must supply what to build.
* ''live.cfg'': Hier werden die Kernel mit den notwendigen Aufrufparametern hinterlegt.
if [ -z "${1}" ]; then
** Die ''label''s müssen eindeutig sein,
    echo "Give arch as argument: amd64 or i686."
** die ''menu label''s werden dem Anwender beim Starten präsentiert,
    exit 0
** der ''fetch''-Parameter zeigt auf eine FTP- oder HTTP-URL zum Download des Squashfs-Images.
fi
** Beispiel:
 
label livei386
# Check what to build.
  menu label Live i386
if [ "${1}" == "amd64" ]; then
  kernel debian-live/vmlinuz-2.6.32-5-686
    DST_ARCH="amd64"
  append initrd=debian-live/initrd.img-2.6.32-5-686 boot=live config fetch=<nowiki>ftp://192.168.59.10/pub/linux/debian-live-6.0.1-i386.squashfs</nowiki> quiet vga=normal
elif [ "${1}" == "i686" ] || [ "${1}" == "i386" ]; then
    DST_ARCH="i686"
  label liveamd64
else
  menu label Live AMD64
    echo "Give arch as argument: amd64 or i686."
  kernel debian-live/vmlinuz-2.6.32-5-amd64
    exit 0
  initrd=debian-live/initrd.img-2.6.32-5-amd64 boot=live config fetch=<nowiki>ftp://192.168.59.10/pub/linux/debian-live-6.0.1-amd64.squashfs</nowiki> quiet vga=normal
fi
 
# Automatically clean up when we terminate.
trap '{ umount ${TMPMNT} && rmdir ${TMPMNT}; rm -f ${TMPIMG}; }' EXIT
 
# Terminate on error.
set -e
 
 
# Temporary image file and mount point to work within.
TMPIMG=$(mktemp --tmpdir=/var/tmp live-image.XXXXXXXXXX)
TMPMNT=$(mktemp -d --tmpdir=/var/tmp live-root.XXXXXXXXXX)
 
 
# Prepare image file and mount.
fallocate -v -l 4GiB "${TMPIMG}"
mke2fs -t ext4 -E lazy_itable_init=0 -O ^has_journal -i 16384 -L live-build -F "${TMPIMG}"
tune2fs -r0 -c0 -i12m -o '^acl,nobarrier' -e remount-ro -f "${TMPIMG}"
mount -o loop "${TMPIMG}" "${TMPMNT}"
 
# Install system.
if [ "${DST_ARCH}" == "amd64" ]; then
    ARCH_ARG="--arch=amd64"
    PKGLIST="console-setup, \
        dosfstools, \
        dump, \
        firmware-amd-graphics, \
        firmware-bnx2, \
        firmware-bnx2x, \
        firmware-linux-free, \
        firmware-misc-nonfree, \
        gdisk, \
        ifupdown, \
        isc-dhcp-client, \
        kbd, \
        keyboard-configuration, \
        linux-image-amd64, \
        live-boot, \
        locales, \
        lsscsi, \
        lvm2, \
        mdadm, \
        mt-st, \
        net-tools, \
        nfs-common, \
        openssh-client, \
        openssh-server, \
        orphan-sysvinit-scripts, \
        pciutils, \
        pv, \
        sg3-utils, \
        sysvinit-core"
elif [ "${DST_ARCH}" == "i686" ]; then
    ARCH_ARG="--arch=i386"
    PKGLIST="console-setup, \
        dump, \
        firmware-linux-free, \
        ifupdown, \
        isc-dhcp-client, \
        kbd, \
        keyboard-configuration, \
        linux-image-686-pae, \
        live-boot, \
        locales, \
        lsscsi, \
        lvm2, \
        mdadm, \
        mt-st, \
        net-tools, \
        nfs-common, \
        openssh-client, \
        openssh-server, \
        orphan-sysvinit-scripts, \
        pciutils, \
        pv, \
        sg3-utils, \
        sysvinit-core"
fi
 
# Parameter strings for debootstrap must not include blanks.
PKGLIST_CLEAN="$(echo "${PKGLIST}" |tr -d ' ')"
debootstrap "${ARCH_ARG}" --components=main,non-free,non-free-firmware,contrib \
    --include "${PKGLIST_CLEAN}" \
    --exclude nano,systemd-sysv,tasksel,tasksel-data \
    stable "${TMPMNT}" https://debian.inf.tu-dresden.de/debian/
 
# Prepare system.
echo "debian-live" > "${TMPMNT}"/etc/hostname
cat > "${TMPMNT}"/etc/default/keyboard <<-EOF
# Check /usr/share/doc/keyboard-configuration/README.Debian for
# documentation on what to do after having modified this file.
 
# The following variables describe your keyboard and can have the same
# values as the XkbModel, XkbLayout, XkbVariant and XkbOptions options
# in /etc/X11/xorg.conf.
 
XKBMODEL="pc105"
XKBLAYOUT="de"
XKBVARIANT=""
XKBOPTIONS=""
 
# If you don't want to use the XKB layout on the console, you can
# specify an alternative keymap. Make sure it will be accessible
# before /usr is mounted.
# KMAP=/etc/console-setup/defkeymap.kmap.gz
BACKSPACE="guess"
EOF
 
# Clean apt lists to save space. They might be outdated anyway and need to be retransferred.
rm -f "${TMPMNT}"/var/lib/apt/lists/* 2>/dev/null || true
 
# Set default locale.
echo "LANG=en_US.UTF-8" > "${TMPMNT}"/etc/environment
 
# Add default password entry.
sed '/^root:/ d' "${TMPMNT}"/etc/shadow > "${TMPMNT}"/etc/shadow~
echo 'root::17852:0:99999:7:::' > "${TMPMNT}"/etc/shadow
cat "${TMPMNT}"/etc/shadow~ >> "${TMPMNT}"/etc/shadow
 
# Help with ssh-remote-logins.
echo "PermitRootLogin yes" >> "${TMPMNT}"/etc/ssh/sshd_config
echo "PermitEmptyPasswords yes" >> "${TMPMNT}"/etc/ssh/sshd_config
 
# Switch initrd to gzip.
sed -Ei 's/^COMPRESS=zstd$/COMPRESS=gzip/' "${TMPMNT}"/etc/initramfs-tools/initramfs.conf
 
# Prepare system to rebuild initramfs
mount -o bind /dev "${TMPMNT}"/dev
mount -o bind /dev/pts "${TMPMNT}"/dev/pts
mount -t proc none "${TMPMNT}"/proc
mount -t sysfs none "${TMPMNT}"/sys
echo "Please run these commands:"
# FIXME: How to automate this manual process?
echo ' echo "locales locales/default_environment_locale select en_US.UTF-8" |debconf-set-selections'
echo ' echo "locales locales/locales_to_be_generated multiselect en_US.UTF-8 UTF-8" |debconf-set-selections'
echo " dpkg-reconfigure locales"
echo " update-initramfs -u"
echo "then exit chroot."
chroot "${TMPMNT}"
 
# Script resumes after chroot exit.
umount "${TMPMNT}"/dev/pts "${TMPMNT}"/dev "${TMPMNT}"/proc "${TMPMNT}"/sys


* ''stdmenu.cfg'', ''menu.cfg'', ''exithelp.cfg'', ''prompt.cfg'': Pfade zu den Dateien anpassen.
# Copy Kernel and initramfs for TFTP
cp -v "${TMPMNT}"/vmlinuz "${TMPMNT}"/initrd.img /var/tftpboot/deb-live/"${DST_ARCH}"


=== Booten mit wenig Speicher ===
# Compress into a file for NFS serving
Mit der oben beschriebenen Methode brauchen die Maschinen genug Speicher, um das Root-Dateisystem zu laden und die Programme auch auszuführen. Da das derzeitige Rescue-Image über 500&thinsp;MB groß ist, braucht die Hardware 0,75 - 1&thinsp;GB RAM zum Starten.
mksquashfs "${TMPMNT}" /var/nfsboot/deb-live/"${DST_ARCH}"/filesystem.squashfs -noappend


Soll darauf verzichtet werden, so sind folgende Änderungen notwendig:
# vim: tabstop=4 shiftwidth=4 autoindent expandtab
* Die Squashfs-Images müssen ''filesystem.squashfs'' heißen und in einem Unterverzeichnis ''/live/'' des per NFS exportieren Verzeichnisses liegen. Beispielsweise:
</syntaxhighlight>
/var/nfsboot/debian-live/amd64/live/filesystem.squashfs
/var/nfsboot/debian-live/i386/live/filesystem.squashfs
* In der ''/etc/exports wird dann ein NFS-Export konfiguriert:
/var/nfsboot  192.168.59.0/24(ro,nohide,no_root_squash,no_subtree_check,insecure)
* In ''boot-screens/live.cfg'' muss Kernelkommandozeile entsprechend angepasst werden:
append initrd=debian-live/initrd.img-2.6.32-5-686 config boot=live netboot=nfs nfsroot=192.168.59.10:/var/nfsboot/debian-live/i386 quiet vga=normal


Mit entsprechend vielen Menüeinträgen in der ''live.cfg'' können beide Varianten koexistieren. Die Verfügbarkeit der Images per FTP kann z.&thinsp;B. mit Hardlinks erreicht werden.
* Die Paketliste in ''$PKGLIST'' ist darauf zugeschnitten, die für eine schnelle Wiederherstellung notwendigen Komponenten zu beinhalten.


== Test ==
== Test ==
Wenn nichts falsch gemacht wurde, so bezieht der Client nun beim Netzboot eine IP-Adresse vom DHCP-Server und lädt die PXE-Dateien, um ein Menü anzuzeigen, was gestartet werden soll. Nach der Auswahl eines Punktes werden Kernel und Initrd per TFTP übermittelt und der Kernel gestartet. Per erneuter DHCP-Anfrage erhält der Kernel gültige Netzparameter und kann nun die in der ''fetch''-URL angegebene Datei nachladen, bzw, das per NFS zugängliche Squashfs mounten und als Root verwenden. Ab dann ist das Debian-Live-System aktiv.
Wenn nichts falsch gemacht wurde, so bezieht der Client nun beim Netzboot eine IP-Adresse vom DHCP-Server und lädt die PXE-Dateien, um im Anschluss ein Menü anzuzeigen, was denn nun gestartet werden soll. Nach der Auswahl eines Punktes werden Kernel und Initrd per TFTP übermittelt und der Kernel gestartet. Per erneuter DHCP-Anfrage erhält der Kernel gültige Netzparameter und mountet nun das per NFS zugängliche Squashfs als ''root''. Ab dann ist das Debian-Live-System aktiv.


In ''/var/log/daemon.log'' finden sich Meldungen vom TFTP-Server, was sehr hilfreich bei der Fehlersuche ist.
In ''/var/log/daemon.log'' finden sich Meldungen vom TFTP-Server, was hilfreich bei der Fehlersuche sein kann.


== Weblinks ==
== Weblinks ==
* [http://live.debian.net/ Debian-Live Projektseite]
* [https://kb.isc.org/docs/aa-00333 Where to find ISC DHCP documentation?], ISC.org
* [http://grml.org/online-docs/live-initramfs.en.7.html Doku zur live-initramfs] (Manpage im HTML-Format, englisch.)
* [http://grml.org/online-docs/live-initramfs.en.7.html Doku zur live-initramfs] (Manpage im HTML-Format, englisch.)
== Fußnoten ==
<references />


[[Kategorie:Linux]]
[[Kategorie:Linux]]

Aktuelle Version vom 12. Mai 2024, 15:33 Uhr

Die Möglichkeit, hinreichend aktuelle Maschinen (allgemein, also VMs oder auch Blech) über das LAN zu booten ist eine feine Sache. Bare Metal Restore, oder auch die Offline-Korrektur von Fehlern wie z. B. zu kleinen Partitionen, etc. wird damit zum Kinderspiel.

Das Debian-Live-Projekt hat für Wiederherstellungszwecke eine Live-Boot CD-Serie bereitgestellt. Allerdings haben diese Images ein paar (teils subjektive) Nachteile:

  • Gewohnte Konfigurationstools wurden durch modernere Varianten mit eigener Syntax abgelöst; ein Paradebeispiel ist das Fehlen von ifconfig.
  • Hardware welche proprietäre Firmware-Binärdateien benötigt ist — vor allem wenn es um Netzwerkkarten geht — außen vor; ein Booten vom Netz geht spätestens nach dem Starten des Kernels schief.
  • Viele weitere Pakete mit fast immer benötigten Tools fehlen und müssen immer und immer wieder per Hand nachinstalliert werden.

Der Artikel beschreibt die notwendigen Schritte, dieses Netzbootsystem auf einem existierenden Debian Linux 12 (Bookworm) aufzusetzen. Ob die zu startende Maschine ein älteres BIOS-basiertes System ist oder ein neueres EFI-System, ist egal: Beides wird dynamisch anhand von DHCP-Optionen passend konfiguriert. Dabei kann zum Bootzeitpunkt ausgewählt werden, ob ein 32- oder ein 64-Bit-System gestartet werden soll.

Es ist selbstverständlich möglich, weitere via PXE zu startende Betriebssysteme einzubinden. Wichtig ist zu beachten, dass die via TFTP bereitgestellten Dateien in den entsprechenden Unterverzeichnissen für die verschiedenen Architekturen zu hinterlegen sind (bios, efi32, efi64).

Hinweis: Das von mir benutzte System ist traditionell mit SysV-init ausgerüstet. Systemd wird nicht benutzt. Die hier aufgeführten Schritte sind ansonsten so generisch wie möglich gehalten.

Benötigte Komponenten

  • DHCP-Server für die Zuweisung grundlegender Netzwerkparameter,
  • TFTP-Server für den initialen Download von Bootloader, Menü und anschließend Kernel und Initrd,
  • NFS-Server für den Zugriff auf das komprimierte Root-Dateisystem,
  • Scripte zur Erstellung des übers Netz geladenen Root-Dateisystems.

Installation:

apt-get install openbsd-inetd isc-dhcp-server tftp-hpa tftpd-hpa nfs-kernel-server pxelinux syslinux-common syslinux-efi debootstrap squashfs-tools

DHCP-Konfiguration

Hinweis: Im lokalen Netzwerksegment soll nur ein DHCP-Server aktiv sein. Sind es mehrere, ist es mehr oder weniger Zufall, welches Antwortpaket der anfragende Client zuerst bearbeitet. Sollte also schon ein DHCP-Server existieren, muss die gezeigte Konfiguration in die bestehende Konfiguration eingebaut werden. Durch die Benutzung von DHCP-Klassen ("class") ist dies im Regelfall aber sehr einfach möglich.

Der erste Start des noch nicht unkonfigurierten DHCP-Servers geht erfahrungsgemäß schief, dies kann ignoriert werden.

Weil hier nur IPv4 berücksichtigt wird, muss in /etc/default/isc-dhcp-server die Zeile INTERFACESv6 gelöscht werden. Ebenso muss in INTERFACESv4 das für DHCP zu verwendenden Netzwerkinterface eingetragen werden. Beispiel:

INTERFACESv4="eth0"

Dies ist ein Beispiel für eine DHCP-Konfiguration! Insbesondere der group-Abschnitt muss auf die lokalen Gegebenheiten angepasst werden!

authoritative;
ddns-updates off;
default-lease-time 3600;
log-facility daemon;
max-lease-time 86400;
min-lease-time 300;
min-secs 0;

option architecture-type code 93 = unsigned integer 16; # RFC4578

# Route different kinds of requesting clients to distinct PXE bootloaders.
class "pxeclients" {
    match if substring (option vendor-class-identifier, 0, 9) = "PXEClient";

    if option architecture-type = 00:00 {
        filename "/var/tftpboot/bios/lpxelinux.0";
    } elsif option architecture-type = 00:06 {
        filename "/var/tftpboot/efi32/syslinux.efi";
    } elsif option architecture-type = 00:07 {
        filename "/var/tftpboot/efi64/syslinux.efi";
    } elsif option architecture-type = 00:09 {
        filename "/var/tftpboot/efi64/syslinux.efi";
    }

    # This is the TFTP server's IP address.
    next-server 192.168.111.10;
}

# Ethernet
group {
    option broadcast-address 192.168.111.0;
    option domain-name "pocnet.net";
    option domain-name-servers 192.168.111.10;
    option ntp-servers 192.168.111.10;
    option routers 192.168.111.1;
    option subnet-mask 255.255.255.0;

    subnet 192.168.111.0 netmask 255.255.255.0 {
        range 192.168.111.120 192.168.111.126;
    }
}

Nun kann der DHCP-Server gestartet werden:

service isc-dhcp-server start

TFTP-Server

Die Konfiguration des Servers findet sich in /etc/default/tftpd-hpa. Dort müssen folgende Änderungen durchgeführt werden:

  • Ändern des Pfades /srv/tftp nach /var/tftpboot,[1]
  • Ändern der TFTP_OPTIONS:[2]
    • Löschen von --secure,
    • Hinzufügen von --permissive -v.

Nun kann der alte Pfad gelöscht werden und der neue angelegt:

rmdir /srv/tftp
mkdir /var/tftpboot

Als letztes sollte der TFTP-Server neu gestartet werden:

service tftpd-hpa restart

Inhalte für /var/tftpboot

Zuerst werden ein paar grundlegende Verzeichnisse für die benötigten Dateien angelegt:

cd /var/tftpboot
mkdir -p deb-live/amd64 deb-live/i686 bios efi32 efi64 pxelinux.cfg

Für die einzelnen Architekturen werden nun die benötigten Bootdateien über Symlinks bereit gestellt. Symlinks brauchen weniger Speicher und wenn das Original (wegen Aktualisierungen) ausgetauscht wird, braucht man nicht mehr manuell nachbessern.

# BIOS-Loaders
cd bios
ln -s ../deb-live .
ln -s ../pxelinux.cfg .
ln -s ../../../usr/lib/syslinux/modules/bios/ldlinux.c32 .
ln -s ../../../usr/lib/syslinux/modules/bios/libcom32.c32 .
ln -s ../../../usr/lib/syslinux/modules/bios/libutil.c32 .
ln -s ../../../usr/lib/syslinux/modules/bios/mboot.c32 .
ln -s ../../../usr/lib/syslinux/modules/bios/menu.c32 .
ln -s ../../../usr/lib/syslinux/modules/bios/pxechn.c32 .
ln -s ../../../usr/lib/syslinux/modules/bios/vesamenu.c32 .
ln -s ../../../usr/lib/PXELINUX/lpxelinux.0 .

# EFI32-Loaders
cd ../efi32
ln -s ../deb-live .
ln -s ../pxelinux.cfg .
ln -s ../../../usr/lib/syslinux/modules/efi32/ldlinux.e32 .
ln -s ../../../usr/lib/syslinux/modules/efi32/libcom32.c32 .
ln -s ../../../usr/lib/syslinux/modules/efi32/libutil.c32 .
ln -s ../../../usr/lib/syslinux/modules/efi32/mboot.c32 .
ln -s ../../../usr/lib/syslinux/modules/efi32/menu.c32 .
ln -s ../../../usr/lib/syslinux/modules/efi32/vesamenu.c32 .
ln -s ../../../usr/lib/SYSLINUX.EFI/efi32/syslinux.efi .

# EFI64-Loaders
cd ../efi64
ln -s ../deb-live .
ln -s ../pxelinux.cfg .
ln -s ../../../usr/lib/syslinux/modules/efi64/ldlinux.e64 .
ln -s ../../../usr/lib/syslinux/modules/efi64/libcom32.c32 .
ln -s ../../../usr/lib/syslinux/modules/efi64/libutil.c32 .
ln -s ../../../usr/lib/syslinux/modules/efi64/mboot.c32 .
ln -s ../../../usr/lib/syslinux/modules/efi64/menu.c32 .
ln -s ../../../usr/lib/syslinux/modules/efi64/vesamenu.c32 .
ln -s ../../../usr/lib/SYSLINUX.EFI/efi64/syslinux.efi .

Um die Pflege des PXE-Bootmenüs zu vereinfachen, wird eine "globale" Konfiguration in /var/tftpboot/pxelinux.cfg (der Standardname, mit dem die PXE-Loader nach der Konfiguration suchen) für alle Architekturen via Symlinks zugänglich gemacht.

Die eigentliche Konfiguration für das Bootmenü findet sich in der Datei /var/tftpboot/pxelinux.cfg/default:

menu title Boot menu
menu tabmsg Press ENTER to boot or TAB to edit a menu entry
prompt 0
timeout 600

label deblive64
    menu label Debian Live ^amd64
    kernel deb-live/amd64/vmlinuz
    append initrd=deb-live/amd64/initrd.img net.ifnames=0 biosdevname=0 ip=:::::eth0:dhcp boot=live netboot=nfs root=/dev/nfs nfsroot=192.168.1.10:/var/nfsboot/deb-live/amd64 live-media-path=/ consoleblank=0 nfsrootdebug

label deblive32
    menu label Debian Live ^i686
    kernel deb-live/i686/vmlinuz
    append initrd=deb-live/i686/initrd.img net.ifnames=0 biosdevname=0 ip=:::::eth0:dhcp boot=live netboot=nfs root=/dev/nfs nfsroot=192.168.1.10:/var/nfsboot/deb-live/amd64 live-media-path=/ consoleblank=0 nfsrootdebug

label bootlocal
    menu label Boot ^local disk
    menu default
    localboot 0

ui menu.c32
  • net.ifnames=0 biosdevname=0 stellt die ursprüngliche, aufsteigende Nummerierung vom Kernel wieder her, damit die Netzwerkschnittstelle überall wieder eth0heißt und diese wiederum in der ip=-Konfigurationszeile statisch referenziert werden kann.[3]
  • Das Zirkumflex (^) dient als Hervorhebung für einen Buchstaben im Menü. Dieser Buchstabe auf der Tastatur eingegeben aktiviert diesen Menüeintrag.

NFS-Server

In der Datei /etc/exports wird definiert, welche Hosts auf welche Verzeichnisse Zugriff haben:

/var/nfsboot    192.168.1.0/24(ro,no_root_squash,insecure,no_subtree_check)

Nun müssen die Verzeichnisse für das Rootdateisystem noch angelegt werden:

mkdir -p /var/nfsboot/deb-live/amd64 /var/nfsboot/deb-live/i686

Damit die Änderungen ziehen, einmal den (mangels gültiger Einträge in exports sowieso nicht gestarteten) NFS-Server starten:

service nfs-kernel-server start

Root-Dateisystem

Dies wird über eine "frische" Installation von Debian von Grund auf neu erzeugt:

  • Debootstrap,
  • Konfigurationsanpassungen,
  • Squashfs-Build.

Das folgende Script kann mit den Parametern amd64 oder i686 aufgerufen werden und erzeugt jeweils ein Squashfs in den zuvor angelegten Verzeichnissen in /var/nfsboot.

#!/bin/bash

# Must run as root.
if ! id |grep -Fq 'uid=0(root) gid=0(root) groups=0(root)'; then
    echo "Must run as root."
    exit 1
fi

# Must supply what to build.
if [ -z "${1}" ]; then
    echo "Give arch as argument: amd64 or i686."
    exit 0
fi

# Check what to build.
if [ "${1}" == "amd64" ]; then
    DST_ARCH="amd64"
elif [ "${1}" == "i686" ] || [ "${1}" == "i386" ]; then
    DST_ARCH="i686"
else
    echo "Give arch as argument: amd64 or i686."
    exit 0
fi

# Automatically clean up when we terminate.
trap '{ umount ${TMPMNT} && rmdir ${TMPMNT}; rm -f ${TMPIMG}; }' EXIT

# Terminate on error.
set -e


# Temporary image file and mount point to work within.
TMPIMG=$(mktemp --tmpdir=/var/tmp live-image.XXXXXXXXXX)
TMPMNT=$(mktemp -d --tmpdir=/var/tmp live-root.XXXXXXXXXX)


# Prepare image file and mount.
fallocate -v -l 4GiB "${TMPIMG}"
mke2fs -t ext4 -E lazy_itable_init=0 -O ^has_journal -i 16384 -L live-build -F "${TMPIMG}"
tune2fs -r0 -c0 -i12m -o '^acl,nobarrier' -e remount-ro -f "${TMPIMG}"
mount -o loop "${TMPIMG}" "${TMPMNT}"

# Install system.
if [ "${DST_ARCH}" == "amd64" ]; then
    ARCH_ARG="--arch=amd64"
    PKGLIST="console-setup, \
        dosfstools, \
        dump, \
        firmware-amd-graphics, \
        firmware-bnx2, \
        firmware-bnx2x, \
        firmware-linux-free, \
        firmware-misc-nonfree, \
        gdisk, \
        ifupdown, \
        isc-dhcp-client, \
        kbd, \
        keyboard-configuration, \
        linux-image-amd64, \
        live-boot, \
        locales, \
        lsscsi, \
        lvm2, \
        mdadm, \
        mt-st, \
        net-tools, \
        nfs-common, \
        openssh-client, \
        openssh-server, \
        orphan-sysvinit-scripts, \
        pciutils, \
        pv, \
        sg3-utils, \
        sysvinit-core"
elif [ "${DST_ARCH}" == "i686" ]; then
    ARCH_ARG="--arch=i386"
    PKGLIST="console-setup, \
        dump, \
        firmware-linux-free, \
        ifupdown, \
        isc-dhcp-client, \
        kbd, \
        keyboard-configuration, \
        linux-image-686-pae, \
        live-boot, \
        locales, \
        lsscsi, \
        lvm2, \
        mdadm, \
        mt-st, \
        net-tools, \
        nfs-common, \
        openssh-client, \
        openssh-server, \
        orphan-sysvinit-scripts, \
        pciutils, \
        pv, \
        sg3-utils, \
        sysvinit-core"
fi

# Parameter strings for debootstrap must not include blanks.
PKGLIST_CLEAN="$(echo "${PKGLIST}" |tr -d ' ')"
debootstrap "${ARCH_ARG}" --components=main,non-free,non-free-firmware,contrib \
    --include "${PKGLIST_CLEAN}" \
    --exclude nano,systemd-sysv,tasksel,tasksel-data \
    stable "${TMPMNT}" https://debian.inf.tu-dresden.de/debian/

# Prepare system.
echo "debian-live" > "${TMPMNT}"/etc/hostname
cat > "${TMPMNT}"/etc/default/keyboard <<-EOF
# Check /usr/share/doc/keyboard-configuration/README.Debian for
# documentation on what to do after having modified this file.

# The following variables describe your keyboard and can have the same
# values as the XkbModel, XkbLayout, XkbVariant and XkbOptions options
# in /etc/X11/xorg.conf.

XKBMODEL="pc105"
XKBLAYOUT="de"
XKBVARIANT=""
XKBOPTIONS=""

# If you don't want to use the XKB layout on the console, you can
# specify an alternative keymap.  Make sure it will be accessible
# before /usr is mounted.
# KMAP=/etc/console-setup/defkeymap.kmap.gz
BACKSPACE="guess"
EOF

# Clean apt lists to save space. They might be outdated anyway and need to be retransferred.
rm -f "${TMPMNT}"/var/lib/apt/lists/* 2>/dev/null || true

# Set default locale.
echo "LANG=en_US.UTF-8" > "${TMPMNT}"/etc/environment

# Add default password entry.
sed '/^root:/ d' "${TMPMNT}"/etc/shadow > "${TMPMNT}"/etc/shadow~
echo 'root::17852:0:99999:7:::' > "${TMPMNT}"/etc/shadow
cat "${TMPMNT}"/etc/shadow~ >> "${TMPMNT}"/etc/shadow

# Help with ssh-remote-logins.
echo "PermitRootLogin yes" >> "${TMPMNT}"/etc/ssh/sshd_config
echo "PermitEmptyPasswords yes" >> "${TMPMNT}"/etc/ssh/sshd_config

# Switch initrd to gzip.
sed -Ei 's/^COMPRESS=zstd$/COMPRESS=gzip/' "${TMPMNT}"/etc/initramfs-tools/initramfs.conf

# Prepare system to rebuild initramfs
mount -o bind /dev "${TMPMNT}"/dev
mount -o bind /dev/pts "${TMPMNT}"/dev/pts
mount -t proc none "${TMPMNT}"/proc
mount -t sysfs none "${TMPMNT}"/sys
echo "Please run these commands:"
# FIXME: How to automate this manual process?
echo ' echo "locales	locales/default_environment_locale	select	en_US.UTF-8" |debconf-set-selections'
echo ' echo "locales	locales/locales_to_be_generated	multiselect	en_US.UTF-8 UTF-8" |debconf-set-selections'
echo " dpkg-reconfigure locales"
echo " update-initramfs -u"
echo "then exit chroot."
chroot "${TMPMNT}"

# Script resumes after chroot exit.
umount "${TMPMNT}"/dev/pts "${TMPMNT}"/dev "${TMPMNT}"/proc "${TMPMNT}"/sys

# Copy Kernel and initramfs for TFTP
cp -v "${TMPMNT}"/vmlinuz "${TMPMNT}"/initrd.img /var/tftpboot/deb-live/"${DST_ARCH}"

# Compress into a file for NFS serving
mksquashfs "${TMPMNT}" /var/nfsboot/deb-live/"${DST_ARCH}"/filesystem.squashfs -noappend

# vim: tabstop=4 shiftwidth=4 autoindent expandtab
  • Die Paketliste in $PKGLIST ist darauf zugeschnitten, die für eine schnelle Wiederherstellung notwendigen Komponenten zu beinhalten.

Test

Wenn nichts falsch gemacht wurde, so bezieht der Client nun beim Netzboot eine IP-Adresse vom DHCP-Server und lädt die PXE-Dateien, um im Anschluss ein Menü anzuzeigen, was denn nun gestartet werden soll. Nach der Auswahl eines Punktes werden Kernel und Initrd per TFTP übermittelt und der Kernel gestartet. Per erneuter DHCP-Anfrage erhält der Kernel gültige Netzparameter und mountet nun das per NFS zugängliche Squashfs als root. Ab dann ist das Debian-Live-System aktiv.

In /var/log/daemon.log finden sich Meldungen vom TFTP-Server, was hilfreich bei der Fehlersuche sein kann.

Weblinks

Fußnoten

  1. Ist kein Muss, aber in dieser Anleitung wird dieser Pfad vorausgesetzt.
  2. Dies ist notwendig, damit die später angelegten Symlinks auch aufgelöst werden.
  3. Früher hat die Autokonfiguration bei mehreren vorhandenen Netzwerkschnittstellen nicht zuverlässig funktioniert, deswegen der gezeigte Workaround.