Eine Einführung in den Linux-Boot- und -Startvorgang
Das Verständnis des Linux-Boot- und -Startvorgangs ist wichtig, um Linux zu konfigurieren und Startprobleme zu beheben. Dieser Artikel gibt einen Überblick über die Bootsequenz unter Verwendung des GRUB2-Bootloaders und die Startsequenz, wie sie vom systemd-Initialisierungssystem ausgeführt wird.
In Wirklichkeit gibt es zwei Sequenzen von Ereignissen, die erforderlich sind, um einen Linux-Computer zu booten und nutzbar zu machen: Boot und Startup. Die Boot-Sequenz beginnt, wenn der Computer eingeschaltet wird, und wird abgeschlossen, wenn der Kernel initialisiert und systemd gestartet wird. Der Startvorgang übernimmt dann die Aufgabe, den Linux-Computer in einen betriebsbereiten Zustand zu versetzen.
Gesamt ist der Linux-Boot- und Startvorgang recht einfach zu verstehen. Er besteht aus den folgenden Schritten, die in den folgenden Abschnitten genauer beschrieben werden.
- BIOS POST
- Bootloader (GRUB2)
- Kernel-Initialisierung
- Start von systemd, dem Parent aller Prozesse.
In diesem Artikel werden GRUB2 und systemd behandelt, weil sie die aktuelle Bootloader- und Initialisierungssoftware für die meisten großen Distributionen sind. Andere Softwareoptionen wurden in der Vergangenheit verwendet und sind immer noch in einigen Distributionen zu finden.
Der Bootvorgang
Der Bootvorgang kann auf verschiedene Arten eingeleitet werden. Wenn der Computer ausgeschaltet ist, wird der Bootvorgang durch Einschalten der Stromversorgung gestartet. Wenn auf dem Computer bereits ein lokaler Benutzer, einschließlich Root oder ein unprivilegierter Benutzer, läuft, kann der Benutzer die Boot-Sequenz programmatisch einleiten, indem er die grafische Benutzeroberfläche oder die Befehlszeile verwendet, um einen Neustart zu initiieren. Bei einem Neustart wird der Computer zunächst heruntergefahren und dann neu gestartet.
BIOS POST
Der erste Schritt des Linux-Bootprozesses hat eigentlich nichts mit Linux zu tun. Es handelt sich um den Hardwareteil des Bootvorgangs, der für jedes Betriebssystem gleich ist. Wenn der Computer zum ersten Mal mit Strom versorgt wird, läuft der POST (Power On Self Test), der Teil des BIOS (Basic I/O System) ist.
Als IBM 1981 den ersten PC entwarf, wurde das BIOS für die Initialisierung der Hardwarekomponenten entwickelt. POST ist der Teil des BIOS, dessen Aufgabe es ist, sicherzustellen, dass die Computerhardware korrekt funktioniert. Wenn der POST fehlschlägt, ist der Computer möglicherweise nicht benutzbar und der Bootvorgang wird nicht fortgesetzt.
Der BIOS-POST prüft die grundsätzliche Funktionsfähigkeit der Hardware und gibt dann einen BIOS-Interrupt, INT 13H, aus, der die Bootsektoren auf allen angeschlossenen bootfähigen Geräten sucht. Der erste gefundene Bootsektor, der einen gültigen Boot-Datensatz enthält, wird in den Arbeitsspeicher geladen und die Kontrolle wird dann an den Code übertragen, der aus dem Bootsektor geladen wurde.
Der Bootsektor ist eigentlich die erste Stufe des Bootloaders. Es gibt drei Bootloader, die von den meisten Linux-Distributionen verwendet werden, GRUB, GRUB2 und LILO. GRUB2 ist der neueste und wird heutzutage viel häufiger verwendet als die anderen älteren Optionen.
GRUB2
GRUB2 steht für „GRand Unified Bootloader, Version 2“ und ist heute der primäre Bootloader für die meisten aktuellen Linux-Distributionen. GRUB2 ist das Programm, das den Computer gerade schlau genug macht, den Betriebssystemkern zu finden und in den Speicher zu laden. Da es einfacher ist, GRUB zu schreiben und auszusprechen als GRUB2, verwende ich in diesem Dokument zwar den Begriff GRUB, beziehe mich aber auf GRUB2, sofern nicht anders angegeben.
GRUB wurde so entwickelt, dass es mit der Multiboot-Spezifikation kompatibel ist, die es GRUB ermöglicht, viele Versionen von Linux und anderen freien Betriebssystemen zu booten; es kann auch den Boot-Record von proprietären Betriebssystemen in Kettenschaltung laden.
GRUB kann es dem Benutzer auch ermöglichen, zwischen mehreren verschiedenen Kerneln für eine bestimmte Linux-Distribution zu wählen. Dies bietet die Möglichkeit, von einer früheren Kernelversion zu booten, wenn ein aktueller Kernel irgendwie ausfällt oder mit einer wichtigen Software inkompatibel ist. GRUB kann über die Datei /boot/grub/grub.conf konfiguriert werden.
GRUB1 gilt inzwischen als veraltet und wurde in den meisten modernen Distributionen durch GRUB2 ersetzt, das eine Neufassung von GRUB1 ist. Red Hat-basierte Distributionen haben um Fedora 15 und CentOS/RHEL 7 herum auf GRUB2 aktualisiert. GRUB2 bietet die gleiche Boot-Funktionalität wie GRUB1, ist aber auch eine Mainframe-ähnliche, befehlsbasierte Pre-OS-Umgebung und ermöglicht mehr Flexibilität während der Pre-boot-Phase. GRUB2 wird mit /boot/grub2/grub.cfg konfiguriert.
Die Hauptfunktion beider GRUB-Versionen besteht darin, den Linux-Kernel in den Speicher zu laden und zum Laufen zu bringen. Beide Versionen von GRUB arbeiten im Wesentlichen auf die gleiche Weise und haben die gleichen drei Stufen, aber ich werde GRUB2 für diese Diskussion darüber verwenden, wie GRUB seine Arbeit erledigt. Die Konfiguration von GRUB oder GRUB2 und die Verwendung von GRUB2-Befehlen liegen außerhalb des Rahmens dieses Artikels.
Obwohl GRUB2 nicht offiziell die Stufennotation für die drei Stufen von GRUB2 verwendet, ist es bequem, sich auf diese Weise auf sie zu beziehen, weshalb ich dies in diesem Artikel tun werde.
Stufe 1
Wie bereits im Abschnitt BIOS POST erwähnt, durchsucht das BIOS am Ende des POST die angeschlossenen Festplatten nach einem Boot-Record, der sich normalerweise im Master Boot Record (MBR) befindet, lädt den ersten, den es findet, in den Speicher und startet dann die Ausführung des Boot-Records. Der Bootstrap-Code, d. h. GRUB2 Stufe 1, ist sehr klein, da er zusammen mit der Partitionstabelle in den ersten 512-Byte-Sektor auf der Festplatte passen muss. Der gesamte für den eigentlichen Bootstrap-Code zugewiesene Platz in einem klassischen generischen MBR beträgt 446 Byte. Die 446 Byte große Datei für Stufe 1 heißt boot.img und enthält nicht die Partitionstabelle, die dem Boot-Record separat hinzugefügt wird.
Da der Boot-Record so klein sein muss, ist er auch nicht sehr intelligent und versteht keine Dateisystemstrukturen. Daher besteht der einzige Zweck von Stufe 1 darin, die Stufe 1.5 zu finden und zu laden. Um dies zu erreichen, muss sich die GRUB-Stufe 1.5 in dem Bereich zwischen dem eigentlichen Boot-Record und der ersten Partition des Laufwerks befinden. Nach dem Laden von GRUB Stufe 1.5 in den Arbeitsspeicher übergibt Stufe 1 die Kontrolle an Stufe 1.5.
Stufe 1.5
Wie bereits erwähnt, muss sich Stufe 1.5 von GRUB im Bereich zwischen dem Boot Record selbst und der ersten Partition auf der Festplatte befinden. Dieser Bereich wurde früher aus technischen Gründen ungenutzt gelassen. Die erste Partition auf der Festplatte beginnt im Sektor 63, und mit dem MBR im Sektor 0 bleiben 62 512-Byte-Sektoren übrig – 31.744 Byte -, in denen die Datei core.img gespeichert werden kann, die die Stufe 1.5 von GRUB darstellt. Die Datei core.img ist 25.389 Byte groß, so dass zwischen dem MBR und der ersten Festplattenpartition reichlich Platz vorhanden ist, um sie zu speichern.
Aufgrund der größeren Menge an Code, die für Stufe 1.5 untergebracht werden kann, kann sie genügend Code enthalten, um einige gängige Dateisystemtreiber wie das Standard-EXT- und andere Linux-Dateisysteme, FAT und NTFS zu enthalten. Die GRUB2 core.img ist viel komplexer und leistungsfähiger als die ältere GRUB1 stage 1.5. Das bedeutet, dass die Stufe 2 von GRUB2 auf einem Standard-EXT-Dateisystem gespeichert werden kann, aber nicht auf einem logischen Volume. Der Standardspeicherort für die Dateien der Stufe 2 befindet sich daher im Dateisystem /boot, genauer gesagt in /boot/grub2.
Beachten Sie, dass sich das Verzeichnis /boot auf einem Dateisystem befinden muss, das von GRUB unterstützt wird. Das ist nicht bei allen Dateisystemen der Fall. Die Funktion von Stufe 1.5 besteht darin, die Ausführung mit den Dateisystemtreibern zu beginnen, die erforderlich sind, um die Dateien der Stufe 2 im /boot-Dateisystem zu finden und die benötigten Treiber zu laden.
Stufe 2
Alle Dateien für GRUB Stufe 2 befinden sich im Verzeichnis /boot/grub2 und mehreren Unterverzeichnissen. GRUB2 hat keine Image-Datei wie die Stufen 1 und 2. Stattdessen besteht es hauptsächlich aus Laufzeit-Kernelmodulen, die bei Bedarf aus dem Verzeichnis /boot/grub2/i386-pc geladen werden.
Die Aufgabe von GRUB2 Stufe 2 ist es, einen Linux-Kernel zu finden und in den Arbeitsspeicher zu laden und die Kontrolle über den Computer an den Kernel zu übergeben. Der Kernel und seine zugehörigen Dateien befinden sich im Verzeichnis /boot. Die Kerneldateien sind identifizierbar, da ihre Namen alle mit vmlinuz beginnen. Sie können den Inhalt des /boot-Verzeichnisses auflisten, um die derzeit installierten Kernel auf Ihrem System zu sehen.
GRUB2 unterstützt wie GRUB1 das Booten von einem der ausgewählten Linux-Kernel. Der Red Hat-Paketmanager DNF unterstützt das Vorhalten mehrerer Kernelversionen, so dass im Falle eines Problems mit dem neuesten Kernel eine ältere Version des Kernels gebootet werden kann. Standardmäßig bietet GRUB ein Pre-Boot-Menü der installierten Kernel, einschließlich einer Rettungsoption und, falls konfiguriert, einer Wiederherstellungsoption.
Stufe 2 von GRUB2 lädt den ausgewählten Kernel in den Speicher und übergibt die Kontrolle über den Computer an den Kernel.
Kernel
Alle Kernel liegen in einem selbstextrahierenden, komprimierten Format vor, um Platz zu sparen. Die Kernel befinden sich im Verzeichnis /boot, zusammen mit einem anfänglichen RAM-Disk-Image und Gerätekarten der Festplatten.
Nachdem der ausgewählte Kernel in den Speicher geladen wurde und mit der Ausführung beginnt, muss er sich zunächst aus der komprimierten Version der Datei entpacken, bevor er irgendeine nützliche Arbeit verrichten kann. Sobald sich der Kernel entpackt hat, lädt er systemd, den Ersatz für das alte SysV-Init-Programm, und übergibt ihm die Kontrolle.
Damit ist der Boot-Prozess beendet. Zu diesem Zeitpunkt laufen der Linux-Kernel und systemd, sind aber nicht in der Lage, produktive Aufgaben für den Endbenutzer auszuführen, da nichts anderes läuft.
Der Startvorgang
Der Startvorgang folgt auf den Bootvorgang und bringt den Linux-Rechner in einen Betriebszustand, in dem er für produktives Arbeiten nutzbar ist.
systemd
systemd ist die Mutter aller Prozesse und dafür verantwortlich, den Linux-Host in einen Zustand zu bringen, in dem produktives Arbeiten möglich ist. Einige seiner Funktionen, die viel umfangreicher sind als die des alten init-Programms, bestehen darin, viele Aspekte eines laufenden Linux-Hosts zu verwalten, einschließlich des Einhängens von Dateisystemen und des Startens und Verwaltens von Systemdiensten, die für einen produktiven Linux-Host erforderlich sind. Alle Aufgaben von systemd, die nicht mit der Startsequenz zusammenhängen, sind nicht Gegenstand dieses Artikels.
Zunächst hängt systemd die Dateisysteme ein, wie sie in /etc/fstab definiert sind, einschließlich aller Auslagerungsdateien oder Partitionen. Dann kann er auf die Konfigurationsdateien in /etc zugreifen, einschließlich seiner eigenen. Er verwendet seine Konfigurationsdatei /etc/systemd/system/default.target, um zu bestimmen, in welchen Zustand oder in welches Ziel er den Rechner booten soll. Die Datei default.target ist nur ein symbolischer Link auf die eigentliche Zieldatei. Bei einer Desktop-Workstation ist dies in der Regel das graphical.target, das dem Runlevel 5 im alten SystemV-Init entspricht. Für einen Server ist die Vorgabe eher das multi-user.target, das dem Runlevel 3 in SystemV entspricht. Das emergency.target entspricht dem Einzelbenutzermodus.
Beachten Sie, dass es sich bei den Targets und Services um systemd-Einheiten handelt.
Tabelle 1 unten zeigt einen Vergleich der systemd-Targets mit den alten SystemV-Startlaufebenen. Die systemd-Target-Aliase werden von systemd aus Gründen der Abwärtskompatibilität bereitgestellt. Die Target-Aliase ermöglichen es Skripten – und vielen Sysadmins wie mir -, SystemV-Befehle wie init 3 zu verwenden, um Runlevels zu ändern. Of course, the SystemV commands are forwarded to systemd for interpretation and execution.
SystemV Runlevel | systemd target | systemd target aliases | Description |
halt.target | Halts the system without powering it down. | ||
0 | poweroff.target | runlevel0.target | Halts the system and turns the power off. |
S | emergency.target | Single user mode. No services are running; filesystems are not mounted. This is the most basic level of operation with only an emergency shell running on the main console for the user to interact with the system. | |
1 | rescue.target | runlevel1.target | A base system including mounting the filesystems with only the most basic services running and a rescue shell on the main console. |
2 | runlevel2.target | Multiuser, without NFS but all other non-GUI services running. | |
3 | multi-user.target | runlevel3.target | All services running but command line interface (CLI) only. |
4 | runlevel4.target | Unused. | |
5 | graphical.target | runlevel5.target | multi-user with a GUI. |
6 | reboot.target | runlevel6.target | Reboot |
default.target | This target is always aliased with a symbolic link to either multi-user.target or graphical.target. systemd always uses the default.target to start the system. Das default.target sollte niemals mit halt.target, poweroff.target oder reboot.target verknüpft werden. |
Tabelle 1: Vergleich der SystemV-Runlevels mit systemd-Targets und einigen Target-Aliases.
Jedes Target hat einen Satz von Abhängigkeiten, die in seiner Konfigurationsdatei beschrieben sind. systemd startet die erforderlichen Abhängigkeiten. Diese Abhängigkeiten sind die Dienste, die erforderlich sind, um den Linux-Host auf einem bestimmten Funktionsniveau zu betreiben. Wenn alle in den Zielkonfigurationsdateien aufgeführten Abhängigkeiten geladen sind und laufen, läuft das System auf dieser Zielebene.
systemd schaut auch in den alten SystemV-Initialisierungsverzeichnissen nach, ob dort Startdateien vorhanden sind. Wenn ja, verwendet systemd diese als Konfigurationsdateien, um die von den Dateien beschriebenen Dienste zu starten. Der veraltete Netzwerkdienst ist ein gutes Beispiel für einen der Dienste, die in Fedora noch SystemV-Startdateien verwenden.
Die folgende Abbildung 1 wurde direkt aus der Bootup-Manualseite kopiert. Sie zeigt die allgemeine Abfolge der Ereignisse während des systemd-Starts und die grundlegenden Anforderungen an die Reihenfolge, um einen erfolgreichen Start zu gewährleisten.
Die Ziele sysinit.target und basic.target können als Kontrollpunkte im Startprozess betrachtet werden. Obwohl eines der Designziele von systemd der parallele Start von Systemdiensten ist, gibt es dennoch bestimmte Dienste und funktionale Ziele, die gestartet werden müssen, bevor andere Dienste und Ziele gestartet werden können. Diese Prüfpunkte können nicht überschritten werden, bevor nicht alle für diesen Prüfpunkt erforderlichen Dienste und Ziele erfüllt sind.
Das Ziel sysinit.target ist also erreicht, wenn alle Einheiten, von denen es abhängt, abgeschlossen sind. Alle diese Einheiten, das Mounten von Dateisystemen, das Einrichten von Auslagerungsdateien, das Starten von udev, das Setzen des Zufallsgenerators, das Starten von Low-Level-Diensten und das Einrichten von kryptographischen Diensten, wenn ein oder mehrere Dateisysteme verschlüsselt sind, müssen abgeschlossen sein, aber innerhalb des sysinit.target können diese Aufgaben parallel ausgeführt werden.
Das sysinit.target startet alle Low-Level-Dienste und -Units, die erforderlich sind, um das System einigermaßen funktionsfähig zu machen und den Übergang zum basic.target zu ermöglichen.
local-fs-pre.target
|
v
(various mounts and (various swap (various cryptsetup
fsck services...) devices...) devices...) (various low-level (various low-level
| | | services: udevd, API VFS mounts:
v v v tmpfiles, random mqueue, configfs,
local-fs.target swap.target cryptsetup.target seed, sysctl, ...) debugfs, ...)
| | | | |
\__________________|_________________ | ___________________|____________________/
\|/
v
sysinit.target
|
____________________________________/|\________________________________________
/ | | | \
| | | | |
v v | v v
(various (various | (various rescue.service
timers...) paths...) | sockets...) |
| | | | v
v v | v rescue.target
timers.target paths.target | sockets.target
| | | |
v \_________________ | ___________________/
\|/
v
basic.target
|
____________________________________/| emergency.service
/ | | |
| | | v
v v v emergency.target
display- (various system (various system
manager.service services services)
| required for |
| graphical UIs) v
| | multi-user.target
| | |
\_________________ | _________________/
\|/
v
graphical.target
Abbildung 1: Die systemd-Startkarte.
Nachdem das sysinit.target erfüllt ist, startet systemd als nächstes das basic.target, wobei alle Units gestartet werden, die zur Erfüllung dieses Ziels erforderlich sind. Das grundlegende Ziel bietet einige zusätzliche Funktionen, indem es Einheiten startet, die für das nächste Ziel benötigt werden. Dazu gehört das Einrichten von Dingen wie Pfaden zu verschiedenen ausführbaren Verzeichnissen, Kommunikationssockets und Timern.
Schließlich können die Ziele auf Benutzerebene, multi-user.target oder graphical.target, initialisiert werden. Beachten Sie, dass das Multi-User.target erreicht werden muss, bevor die Abhängigkeiten der grafischen Ziele erfüllt werden können.
Die unterstrichenen Ziele in Abbildung 1 sind die üblichen Startziele. Wenn eines dieser Ziele erreicht ist, ist der Startvorgang abgeschlossen. Wenn das Multi-User-Ziel die Standardeinstellung ist, sollten Sie auf der Konsole eine Anmeldung im Textmodus sehen. Wenn graphical.target die Voreinstellung ist, sollten Sie eine grafische Anmeldung sehen; der spezifische GUI-Anmeldebildschirm, den Sie sehen, hängt von dem Standard-Anzeigemanager ab, den Sie verwenden.
Probleme
Ich musste kürzlich den Standard-Boot-Kernel auf einem Linux-Computer ändern, der GRUB2 verwendete. Ich stellte fest, dass einige der Befehle bei mir nicht richtig zu funktionieren schienen, oder dass ich sie nicht richtig verwendete. Ich bin mir noch nicht sicher, was der Fall war, und muss noch einige Nachforschungen anstellen.
Der Befehl grub2-set-default setzte den Standard-Kernelindex in der Datei /etc/default/grub nicht richtig, so dass der gewünschte alternative Kernel nicht gebootet wurde. Also änderte ich /etc/default/grub GRUB_DEFAULT=saved manuell in GRUB_DEFAULT=2, wobei 2 der Index des installierten Kernels ist, den ich booten wollte. Dann führte ich den Befehl grub2-mkconfig > /boot/grub2/grub.cfg aus, um die neue grub-Konfigurationsdatei zu erstellen. Diese Umgehung funktionierte wie erwartet und startete den alternativen Kernel.
Schlussfolgerungen
GRUB2 und das systemd-Init-System sind die Schlüsselkomponenten in den Boot- und Startphasen der meisten modernen Linux-Distributionen. Trotz der Tatsache, dass vor allem systemd umstritten ist, arbeiten diese beiden Komponenten reibungslos zusammen, um zunächst den Kernel zu laden und dann alle Systemdienste zu starten, die für ein funktionierendes Linux-System erforderlich sind.
Obwohl ich sowohl GRUB2 als auch systemd komplexer finde als ihre Vorgänger, sind sie ebenso einfach zu erlernen und zu verwalten. Die Manpages enthalten viele Informationen über systemd, und freedesktop.org hat den kompletten Satz der systemd-Manpages online. Weitere Links finden Sie in den unten stehenden Ressourcen.