TODO --ommit npd
TODO Testmenue PW: t
h1. Evaluation, dissection and modification of Linux remote boot
h2. Inhalt
{{toc}}
h2. Begriffe
* qcow - qemu copy-on-write
* stage3.1 initramfs
* stage4 finales System
h2. Aufgabe
Es wird ein Skript bzw. Dracut-Modul benötigt, dass ein initramfs basierend auf
systemd baut. Das resultierende initramfs muss Netzwerk-Support bereitstellen,
ein dnbd3 Blockdevice mounten können und einen "switch_root" auf das zuvor
gemountete Dateisystem umsetzen. Das Framework sollte möglichst
Distributionsunabhängig konstruiert sein. Es soll bereits vor dem
"switch_root", also bevor das eigentliche Zielsystem im Root-Verzeichnis
eingebunden werden systemd als init-System zum Einsatz kommen. Die Kernaufgabe
eine initramfs ist es alle nötigen Anwendungen bereitzustellen, die benötigt
werden, um dass finale Zielsystem einzubinden. In dieser konkreten
Aufgabenstellung muss, dass initramfs ein nicht schreibbares Blockgerät
eingebunden werden und eine schreibbare Zwischenshicht (Overlayfilesystem)
zusätzlich eingebunden werden.
h2. Möglicher Technologien für das Overlaykonzept
- Dateibasierte Overlay-FS (Union-FS, Alternat-Union-FS, Overlay-FS)
- Funktioniert derzeit nicht auf jedem Zielsystem (Kernel)
- Nicht für den Linux-Kernel zertifiziert oder lässt sich nicht über das
Root-System legen.
- Bei wenigen Änderungen in einer großen Datei muss komplette Datei in
der schreibbaren Schicht gespeichert werden.
- Blockorientierte Overlay-FS (Network-Block-Device, DNBD3, Qemu-Copy-On-Write-Image)
- NBD ist für den Linux-Kernel zertifiziert
- Weniger Netzwerkverkehr nötig, da nur geänderte Blöcke übertragen werden
müssen, statt ganze Dateien zu kopieren.
- DNBD3 hat Failover-Strategien, verzichtet auf komplexe Strategien zum
Schreiben in geänderte Blöcke über das Netzwerk
- Das verfügbare qcow2-Format bietet eine Technologie, um blockorientiert
Änderungen in einer zusätzlichen Dateisystemschicht zu speichern.
h2. Zielablauf
Der generelle Ablauf vor bzw. während des Ladens des initramfs und deren
Minilinux-System:
Boot PXE
Laden des initramfs images
Laden des Kernels
Ausführen des iniramfs
Ausführen von Systemd
Bereitstellen aller benötigten Dienste und Hardware (Netzwerk hochbringen)
Mounten des finalen Dateisystems als Wurzel
Wechsel (switch_root) in die finale Distribution
Starten / Weiterausführen von Systemd als Init-System
h2. Benötigte Pakete zum bauen des initramfs
TODO
h2. Benötigte Pakete innerhalb des resultierenden initramfs
- systemd
- quemu-img
- quemu-nbd
- nbd-client
- dnbd3-client
h2. Aufsetzen einer Test-Arbeitsumgebung für CentOS
h3. CentOS7/ArchLinux/RedHat/Ubuntu + VirtualBox + VirtualBoxGuestAdditions
Aufsetzen des Dynamic Kernel Module Support, um einfach neue VBox-Kernel-Module zu aktualisieren:
Aktualisiere Paketdatenbank: @yum update@
Intalliere C-Compiler: @yum install gcc@
Lade erweitertes rpmforfe Repository: @wget http://pkgs.repoforge.org/rpmforge-release/rpmforge-release-0.5.3-1.el7.rf.x86_64.rpm@
Installiere Repository: @rpm -Uvh rpmforge-release-0.5.3-1.el7.rf.x86_64.rpm@
Lade das DKMS-Paket: @wget ftp://rpmfind.net/linux/epel/5/x86_64/dkms-2.2.0.3-29.el5.noarch.rpm@
Installiere DKMS-Paket: @yum localinstall dkms-2.2.0.3-25.el7.noarch.rpm --nogpgcheck@
Aktiviere rpmforge Repository: @yum --enablerepo rpmforge install dkms@
Installiere Entwicklertools zum bauen von Paketen: @yum groupinstall "Development Tools"@
Installiere Metainformation zum Kernel: @yum install kernel-devel@
Installieren der VirtualBox-GuestAddtion:
Lege die VirtualBox-GuestAddition-CD ein.
Mounte CD: @mount /dev/sr0 /mnt/ && cd /mnt/ && ./VBoxLinuxAdditions.run && reboot@
Erstellen eines Testboot Eintrags für Grub2:
- Füge in ??/etc/grub.d/40_custom?? den folgenden Inhalt hinzu:
menuentry 'test' --class centos --class gnu-linux --class gnu --class os --unrestricted $menuentry_id_option 'gnulinux-3.10.0-123.el7.x86_64-advanced-6c06919a-389a-4a50-8c6b-b086e65db9b0' {
load_video
set gfxpayload=keep
insmod gzio
insmod part_msdos
insmod xfs
set root='hd0,msdos1'
if [ x$feature_platform_search_hint = xy ]; then
search --no-floppy --fs-uuid --set=root --hint-bios=hd0,msdos1 --hint-efi=hd0,msdos1 --hint-baremetal=ahci0,msdos1 --hint='hd0,msdos1' 4236333a-a808-4f6b-b4a6-d963f4a69a25
else
search --no-floppy --fs-uuid --set=root 4236333a-a808-4f6b-b4a6-d963f4a69a25
fi
linux16 /vmlinuz-3.10.0-123.el7.x86_64 root=UUID=6c06919a-389a-4a50-8c6b-b086e65db9b0 ro rd.lvm.lv=centos/swap crashkernel=auto rd.lvm.lv=centos/root vconsole.font=latarcyrheb-sun16 vconsole.keymap=de rhgb quiet
initrd16 /initramfs-test.img
}
- Füge neuen Menüeintrag in die automatisch generierte Grub2 Konfigurations2-Datei hinzu: @grub2-mkconfig -o /boot/grub2/grub.cfg@
h2. Bauen eines Test-Initramfs
Mache ein Backup vom aktuellen initamfs:
@cp -p /boot/initramfs-$(uname -r).img /boot/initramfs-$(uname -r).img.BACKUP@
Der folgende Befehl ersetzt das aktuelle Standart Initramfs mit dem neu
gebauten und berücksichtigt dabei alle bisher editierten Dracut-Module in
??/usr/lib/dracut/modules.d??. Die durchschnittliche Größe des resultierenden
initramfs beträgt komprimiert: zwischen 11 und 16 MB.
dracut --verbose --force /boot/initramfs-3.10.0-123.el7.x86_64.test.img \
3.10.0-123.el7.x86_64
h3. Konfiguration
TODO
Configure "cmdline" from "Chapter 8. DRACUT.CMDLINE(7)" in virtualbox in "/boot/startup.sh" for uefi or in "/boot/grub2/grub.cfg" for grub2
h2. Bauen eines minimalen individuellen Test-Initramfs
dracut --verbose --hostonly --force
/boot/initramfs-3.10.0-123.el7.x86_64.test.img \
3.10.0-123.el7.x86_64
Die Option "hostonly" veranlasst Dracut dazu nur alle nötigen Abhängigkeiten
für das aktuelle System in das resultierende Initramfs zu installieren.
Andernfalls fügt dracut viele zusätzliche Treiber hinzu, die die Größe der
resultierenden Datei erheblich vergrößern und damit größer wird als nötig.
Die durchschnittliche Größe des resultierenden initramfs beträgt
komprimiert: zwischen 11 und 16 MB.
h2. Erstellen eines eigenen Dracut-Moduls
Alle vorhanden Module befinden sich in ??/usr/lib/dracut/modules.d??.
Erstelle ein neues Modul: @mkdir /usr/lib/dracut/modules.d/91test@
Baue neues initramfs und achte darauf, dass ??**Including module: test**?? mit der Command-Line-Option ??--verbose?? ausgegeben wird.
Alle Modul-Installations-Informationen sind in der Datei ??module-setup.sh??: @touch /usr/lib/dracut/modules.d/91test/module-setup.sh@
Konfiguriere Modul:
Als erstes erstellt man eine ??check??-Funktion, die lediglich ??0??
zurückgibt. Diese Funktion wird aufgerufen, wenn entschieden wird, welche
Dracutmodule geladen werden sollen. Durch zurückgeben der ??0?? wird das
Modul beim nächsten bauen eines Initramfs automatisch hinzugefügt ohne
das man es etwas in der ??/etc/dracut.conf?? oder per Command-Line-Option
"--add" angeben muss. Wenn die @$hostonly@ Variable gesetzt ist, dann
wird das Modul auch im "hostonly" Modus geladen. In diesem Fall sollte
die Funktion nur dann ??0?? zurückgeben, wenn das Modul auch wircklich
für den aktuellen Host benötigt wird. Wenn 255 zurückgegeben wird, wird
das Modul nur dann geladen, wenn es von einem andren Modul als
Abhängigkeit deklariert wurde.
check() {
return 0
}
Als nächstes wird eine ??install??-Funktion erstellt. Die ??install??-Funktion
wird aufgerufen, wenn alle nicht Kernel spezifischen Ressourcen installiert
werden sollen. Es können Binärdateien, Skripte und andere statischen Dateien
installiert werden. Um einen Datei im aktuellen Modul-Ordner zu addressieren
sollte die Variable "$moddir" als Prefix eingesetzt werden.
Eine solche Funktion kann beispielsweise einen ??Command-Line-Hook?? triggern,
der modulespezifische ??Kernel-Command-Line-Optionen?? verarbeitet während das
initiale Minilinux bootet. Im folgenden Beispiel werden ??Command-Line-Optionen
mit Priorität 20 vom Shell-Skript ??parse-insmodpost.sh?? gelesen und
ausgewertet. Dadurch muss natürlich auch das entsprechende Skript in das
initramfs kopiert werden. Dies wird durch den Aufruf der Funktion
??inst_simple?? erreicht.
install() {
inst_hook cmdline 20 "$moddir/parse-cmdline.sh"
inst_simple "$moddir/parse-cmdline.sh" /sbin/insmodpost.sh
}
Die ??parse-cmdline.sh?? parst die Kernel-Command-Line für die Argumente
??rd.driver.post??, verhindert, dass die Module automatisch geladen werden und
installiert den Hook ??hook.sh?? in der ??initqueue/settled??. Der Inhalt von
??parse-cmdline.sh?? könnte wie folgt aussehen:
for p in $(getargs rd.driver.post=); do
echo "blacklist $p" >> /etc/modprobe.d/initramfsblacklist.conf
done
In einer ??depends??-Funktion können andere Dracut-Module als Abhängigkeit
deklariert werden. Diese müssen einfach per "echo" als String Leerzeichen
getrennt ausgegeben werden.
depends() {
echo 'debug virtfs'
}
Mit dieser Funktion können zusätzliche benötigte Kernel-Command-Line-Argumente
ausgegeben werden, die benötigt werden um die aktuelle Maschine zu booten.
Die Ausgabe sollte mit einem Leerzeichen beginnen und keine neuen Zeilen
ausgeben.
cmdline() {
echo 'TODO'
}
Mit der Funktion ??installkernel?? sollen alle kernelspezifischen Dateien
installiert werden. Siehe hierzu auch den Abschnitt
??Hilfsfunktionen zur Installation??
installkernel() {
TODO
}
h2. Hilfsfunktionen zur Installation
??inst_multiple?? installiert mehrere Binärdateien. Sollten ausführbare Dateien
ohne entsprechendem Pfad ausgewählt werden, wird dracut folgende die Pfade
??/usr/sbin??, ??/sbin??, ??/usr/bin??, ??/bin?? durchsuchen, um den Pfad der
zugehörigen ausführbaren Datei zu ermitteln. Bei dem Kommando-Zeilen-Argument
??-o?? als erster Parameter werden Fehler bei nicht auffindbaren Dateien
unterdrückt.
??inst_multiple [-o] [ …]??
??inst?? installiert eine referenzierte Datei an den korrespondierenden Ort im
??initramfs??. Die Datei wird innerhalb des ??initramfs?? am gleichen Ort zu
finden sein wie auf der Referenzmaschine. Optional kann als zweites Argument
ein anderer Ort für das temporäre Dateisystem angegeben werden.
??inst []??
??inst_hook?? installiert eine ausführbare Datei im Pfad ???? im
Dracut-hook-Ordner ????. Der Einstiegspunkt wird mit Priorität
???? zur Laufzeit des initialen Mini-Linux-Systems ausgeführt.
??inst_hook ??
??inst_rules?? installiert einen oder mehrere udev-Regeln. Nicht-existente
udev-Regeln werden beim bauen des initramfs gemeldet, führen aber nicht zum
Abbruch.
??inst_rules [ …]??
??instmods?? installiert einen oder mehrere Kernel-Module in das initramfs.
???? kann auch ein komplettes Subsystem darstellen, wenn es mit
dem Prefiy "=" beginnt (z.B. "=drivers/net/team"). ??instmods?? sollte nur
innerhalb der ??installkernel()??-Funktion verwendet werden. Ist ??$hostonly??
gesetzt und das aktuelle Modul nicht im Referenzsystem geladen und wird
demnach nicht in ??/sys/…/uevent MODALIAS?? verwendet, wird dieses nicht in
das initramfs integriert. Soll das Modul in jedem Fall geladen werden, kann
folgende Syntax verwendet werden:
installkernel() {
hostonly='' instmods
}
??instmods [ … ]??
h3. Konfiguration
TODO
h3. Debugging
TODO
h2. Build kernel specific dnbd3 kernel module
Installiere Metainformation zum Kernel: @yum install kernel-devel@
Installiere cmake zum Bauen von dnbd3: @yum install cmake@
Installiere zlib-devel zum Bauen von dnbd3: @yum install zlib-devel@
Die kernel header Dateien liegen in:
/usr/lib/modules/3.10.0-229.1.2.el7.x86_64
TOOD
dnbd3-client -h 132.230.4.1 -i stage4/torben/test -r 1
Installiere qemu-img: @yum install qemu-img@
Installiere nbd: @wget http://dl.fedoraproject.org/pub/epel/6/x86_64/nbd-2.9.20-7.el6.x86_64.rpm && rpm -Uvh nbd-2.9.20-7.el6.x86_64.rpm@
NOTE: Disable NetworkManager to avoid reloading network on boot: systemctl disable NetworkManager
h2. CentOS7 @rpmbuild@
First "Set up RPM build env":http://wiki.centos.org/HowTos/SetupRpmBuildEnvironment
Now in that user's home, e.g. @/home/builder@:
# install yumdownloader
yum install yum-utils
# download source in /home/builder/
yumdownloader --source systemd
# should have now have a file ~/systemd-208-20.el7_1.2.src.rpm
# "install" it in ~/rpmbuild
rpm -ivh systemd-208-20.el7_1.2.src.rpm
# install building deps
yum-builddep ~/rpmbuild/SPECS/systemd.spec
# now check if everything is working, by running the simple %prep% phase
# (unpacks source & applies patches)
rpmbuild -bp ~/rpmbuild/SPECS/systemd.spec
# if it worked, we can probably compile
# this runs %prep% and %build%
rpmbuild -bp ~/rpmbuild/SPECS/systemd.spec
dmesg
998 ping 8.8.8.8
999 shutdown .h now
1000 shutdown -h now
1001 y search yumdownloader
1002 y install yum-utils
1003 yumdownloader --help
1004 yumdownloader --source glib2 qemu
1005 yumdownloader --source qemu-img
1006 ls
1007 mkdir glib2_source
1008 cd glib2
1009 cd glib2_source/
1010 rpm2cpio ../glib2-2.40.0-4.el7.src.rpm | cpio -idmv
1011 ls
1012 tar xf glib-2.40.0.tar.xz
1013 ls
1014 cd glib-2.40.0
1015 ls
1016 ./configure --enable-static
1017 make
1018 ls
1019 make
1020 y search zlib
1021 y search zlib-static
1022 y install zlib-static
1023 ./configure --enable-static
1024 y search libffi
1025 y install libffi
1026 y install libffi-devel
1027 ./configure --enable-static
1028 make
1029 ls
1030 cd build/
1031 ls
1032 ..
1033 l
1034 ls
1035 make install
1036 ..
1037 l
1038 ..
1039 l
1040 mkdir qemu-kvm
1041 cd qemu-kvm
1042 ls
1043 rpm2cpio ../qemu-kvm-1.5.3-86.el7_1.1.src.rpm | cpio -idmv
1044 l
1045 pwd
1046 ls
1047 l
1048 ls
1049 ..
1050 l
1051 git clone git://git.qemu.org/qemu.git qemu
1052 ls
1053 rm qemu-kvm -rf
1054 rm qemu-kvm-1.5.3-86.el7_1.1.src.rpm
1055 l
1056 cd qemu/
1057 l
1058 ./configure --static --target-list=x86_64-linux-user
1059 y install zlib
1060 y install zlib-devel
1061 y install zlib2
1062 y search zlib
1063 y install zlib-static
1064 y install zlib
1065 ll /lib64/libz.a
1066 ./configure --static --target-list=x86_64-linux-user
1067 make clean
1068 ./configure --static
1069 y search zlib
1070 y search zlib-static..x86_64
1071 y search zlib-static.x86_64
1072 y install zlib-static.x86_64
1073 ldconfig
1074 ./configure --static
1075 ./configure --help
1076 ./configure --help | grep zlib
1077 y search zlib
1078 y install zlib-devel zlib-static zlib
1079 y deinstall zlib
1080 y remove zlib
1081 y search libz
1082 ls
1083 git submodule update --init dtc
1084 ./configure --static --target-list=x86_64-linux-user
1085 find / -name zlib
1086 find / -name libz
1087 find / -name libz
1088 find / -name zlib
1089 ls
1090 ./configure --disable-zlib-test --static --target-list=x86_64-linux-user
1091 y search base-devel
1092 y search devel
1093 yum groupinstall "Development Tools"
1094 yum groups mark install
1095 yum group mark install
1096 yum groupinstall "Development Tools"
1097 yum groups mark install
1098 yum grouplist
1099 y search zlibrary
1100 y search glibc
1101 y install glibc-static
1102 ls
1103 ./configure --static --target-list=x86_64-linux-user
1104 y search glib
1105 y search glib-2
1106 y search glib2-devel
1107 y install glib2-devel
1108 ./configure --static --target-list=x86_64-linux-user
1109 git submodule update --init pixman
1110 ./configure --static --target-list=x86_64-linux-user
1111 ls
1112 ll
1113 make -j3
1114 l
1115 ldd qemu-nbd
1116 history
h2. Quellen
- "Main Page Dracut on kerne.org":https://dracut.wiki.kernel.org/index.php/Main_Page
- "Documentation on kernel.org":https://www.kernel.org/pub/linux/utils/boot/dracut/dracut.html
- "Enable addional repository":http://www.tecmint.com/enable-rpmforge-repository
- "Getting Dynamic Kernel Module Support":http://rpmfind.net/linux/rpm2html/search.php?query=dkms