Debian-Live Netzbootsystem: Unterschied zwischen den Versionen
PoC (Diskussion | Beiträge) K (→DHCP-Konfiguration: Typo) |
PoC (Diskussion | Beiträge) 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- | 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 | * ''DHCP-Server'' für die Zuweisung grundlegender Netzwerkparameter, | ||
* TFTP-Server | * ''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 == | |||
<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 | |||
== 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>. | |||
=== | 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 <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 | |||
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 | |||
* <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) | |||
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''. | |||
<syntaxhighlight lang="shell"> | |||
#!/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 | |||
</syntaxhighlight> | |||
* 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 | 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 | In ''/var/log/daemon.log'' finden sich Meldungen vom TFTP-Server, was hilfreich bei der Fehlersuche sein kann. | ||
== Weblinks == | == Weblinks == | ||
* [ | * [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, 14: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
.
- Löschen von
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 derip=
-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
- Where to find ISC DHCP documentation?, ISC.org
- Doku zur live-initramfs (Manpage im HTML-Format, englisch.)
Fußnoten
- ↑ Ist kein Muss, aber in dieser Anleitung wird dieser Pfad vorausgesetzt.
- ↑ Dies ist notwendig, damit die später angelegten Symlinks auch aufgelöst werden.
- ↑ Früher hat die Autokonfiguration bei mehreren vorhandenen Netzwerkschnittstellen nicht zuverlässig funktioniert, deswegen der gezeigte Workaround.