Boot

Siehe auch

Was passiert zwischen dem Einschalten der Maschine bis zum Erscheinen des Login-Prompts? Das Verständnis des Boot-Prozesses hilft beim Troubleshooting sowie bei der Performance-Optimierung des Systems.

Ein x86-basierter Rechner prüft und initialisiert mit Hilfe seines BIOS zunächst seine Hardware im sogenannten POST (Power On Self Test). Die BIOS-Software findet sich in einem ROM-Chip auf dem (virtuellen) Motherboard. Der Rest des Boot-Prozesses liegt in der Hand von Linux, hier RHEL.

Nach dem POST startet der Boot Loader und liest aktuelle Zeit- und Hardware-Informationen aus dem batteriegepufferten CMOS. Der Boot Loader ist in der Regel auf einer Festplatte des Rechners gespeichert, entweder im Boot-Sektor (bei klassischen BIOS/MBR-Systemen) oder auf einer EFI-Partition (für aktuelle (Unified) Extensible Firmware Interface oder EFI/UEFI-Systeme). Bis dahin greift die Maschine nicht auf vorhandene Massenspeicher zu.

Für Linux existieren eine ganze Reihe an Boot-Loadern; RHEL verwendet GRUB2 (den GRand Unified Boot loader), andere sind beispielsweise ISOLINUX, um von CD zu booten. GRUB2 präsentiert eine Benutzeroberfläche, um den Bootvorgang von RHEL kontrollieren oder andere parallel installierte Betriebssysteme starten zu können. Der Boot-Loader ist für das Laden des Kernel-Images und der Initial RAM Disk (die einige wichtige Dateien und Gerätetreiber enthält, ohne die das System nicht staren kann) in den Hauptspeicher verantwortlich.

Der Boot-Loader ist in zwei unterschiedliche Teile gegliedert.

Erster Teil

Auf BIOS-Systemen ist der Boot-Loader im MBR (Master Boot Record), dem ersten Sektor der Festplatte, abgelegt, der genau 512 Bytes gross ist. Der Boot-Loader sucht nach dem Start in der Partitionstabelle nach einer bootfähigen Partition - ist diese gefunden, sucht er den zweiten Teil des Boot-Loaders (in unserem Fall GRUB2) und lädt diesen in den Hauptspeicher.

Auf EFI/UEFI-Maschinen liest die UEFI-Firmware ihre Boot-Einträge aus ihrem Boot-Manager, um zu ermitteln, welche UEFI-Applikation von wo geladen werden soll (sprich, auf welcher Festplatte und Partition die EFI-Partition gefunden werden kann). Daraufhin lädt die Firmware die UEFI-Applikation (GRUB2). Klingt kompliziert, ist aber zuverlässiger als die alte MBR-Methode.

Zweiter Teil

Der zweite Teil des Boot-Loaders liegt unter /boot. Ein Auswahlmenü hilft, den Boot-Prozess detailliert zu kontrollieren oder ein parallel installiertes Betriebssystem zu starten. Ist das Betriebssystem ausgewählt, lädt der Boot-Loader im Fall von Linux dessen Kernel in den Hauptspeicher und gibt die Kontrolle an diesen ab.

Parallel lädt der Boot-Loader das Initial RAM–based Filesystem (initramfs) in den Hauptspeicher. Kernel sind meistens komprimiert abgelegt, daher dekomprimiert der Kernel sich zunächst selbst. Anschliessend prüft und initialisiert er die Hardware des Systems mit Hilfe der eingebauten Gerätetreiber aus dem virtuellen Dateisystem und konfiguriert den Hauptspeicher. Zur initialisierten Hardware gehören die Prozessoren, I/O-Subsysteme, Speichersysteme usw. Der Kernel lädt jetzt auch die ersten Anwendungen aus dem User-Space.

Das initramfs Dateisystem-Image enthält alle für das Mounting des root-Dateisystems notwendigen Treiber, Programme und Binärdateien. Eines davon ist udev (userspace /dev), welches für die Ermittlung aktiver Massenspeicher, das Laden der entsprechenden Kernelmodule und die Zuordnung der notwendigen Treiber verantwortlich ist. Ist das root-Dateisystem gefunden, wird es auf Fehler geprüft und gemountet. mount teilt dem Betriebssystem mit, dass ein Dateisystem zur Verfügung steht und hängt es in den globalen Verzeichnisbaum ein (der mount point). Ist hier alles erfolgreich verlaufen, wird initramfs beendet und der User Space startet - bis RHEL 6 mit init („upstart“), ab RHEL 7 mit systemd.

Der User Space startet; systemd ist der erste darin ausgeführte Prozess. systemd startet alle System-Dienste (Daemons) massiv parallel auf Basis von einheitlichen Konfigurationsdateien, die deklarative Initialisierungs-Anweisungen enthalten. Eine Menge an Systemdiensten, ihre Abhängigkeiten und Startreihenfolge untereinander definiert ein Target - beispielsweise das Multi-User-Target (bis zum Erscheinen des Bash-Prompts) oder das Graphical-Target (bis zum Start des GNOME- oder KDE-Desktops).

Shutdown und Neustart

systemctl poweroff
systemctl reboot

Die altbekannten Befehle poweroff, halt und reboot sind als „Legacy“ klassifiziert, und werden seit RHEL 7 auf Systemd umgeleitet.

Um einen Server zu einer festen Uhrzeit herunterzufahren oder neu zu starten, verwendet man:

# Halt at 12:30
shutdown -h 12:30
# Poweroff now
shutdown -P now
# Reboot in 5 minutes
shutdown -r +5

Bemerkung

Es kann vorkommen, dass shutdown, poweroff und restart nicht funktionieren, beispielsweise wenn das Dateisystem nicht verfügbar ist. In diesem Fall muss man den Kernel direkt anweisen, den Neustart wie folgt durchzuführen:

    echo 1 > /proc/sys/kernel/sysrq; echo b > /proc/sysrq-trigger

Dieser Neustart ist hart, das heisst es werden keine Prozesse heruntergefahren oder Dateisysteme ausgehängt.

Runlevel vs. Systemd-Targets

RHEL bis Version 6 kennt verschiedene Runlevel - das sind Systemzustände, die beim Boot-Vorgang durchlaufen werden und diverse Dienste in einer wohldefinierten Reihenfolge starten (z.B. wird erst im höchsten Runlevel die grafische Benutzeroberfläche gestartet). Beim Shutdown werden die Runlevel in umgekehrter Reihenfolge durchlaufen. Sie bedeuteten im Detail:

Runlevel 0

Herunterfahren.

Runlevel 1

Einzelnutzer-Modus, Single User Mode. Nur die wichtigsten Services werden gestartet, das System startet also z.B. ohne Netzwerk; damit sind nur lokale Ressourcen verfügbar. Wird vornehmlich für Wartungsarbeiten verwendet. Das System loggt sich automatisch mit dem root-Account ohne Passwort-Angabe ein. Bootet man in den Runlevel 1, lässt sich so auch ein verlorengegangenes root-Passwort zurücksetzen. Das ist kein Sicherheitsloch, da hier eh schon ein physischer Zugriff auf die Maschine besteht.

Runlevel 2

Mehrbenutzer-Modus ohne Netzwerk, nur lokale Ressourcen verfügbar.

Runlevel 3

Mehrbenutzer mit Netzwerk und allen Diensten, jedoch ohne grafische Benutzeroberfläche. Die Standard-Kommandozeile.

Runlevel 4

Nicht definiert.

Runlevel 5

Runlevel 3, zusätzlich mit grafischer Oberfläche (z.B. GNOME).

Runlevel 6

Neu booten.

Um z.B. in den Runlevel 1 zu wechseln, verwendet man bis RHEL-Version 6 das Kommando

init 1

Damit werden die meisten Daemons ohne Neustart abgeschaltet.

Durch die Einführung von systemd sind die bis RHEL 6 bekannten Runlevel verschwunden. Der Runlevel 3 heisst in RHEL 7 nun multi-user.target, Runlevel 5 wird graphical.target genannt.

Man erreicht diese Targets beim Boot mit der Kernel-Parameter-Angabe systemd.unit=.

rescue.target

Single-User Mode Umgebung ohne Netzwerk, aber mit lokalen Dateisystemen; wird zur Reparatur von Systemen verwendet, die nicht mehr sauber booten können. Erfordert das root-Passwort.

emergency.target

Minimalste Umgebung, die dann verwendet wird, wenn man nicht mehr in den Rescue-Modus starten kann. Hier wird das root-Dateisystem read-only gemountet.

multi-user.target

Entspricht ungefähr Runlevel 3.

graphical.target

Entspricht ungefähr Runlevel 5.

Systemd

Systemd-Targets

Auf einem Minimal-System:

basic.target         Basic System
cryptsetup.target    Encrypted Volumes
getty.target         Login Prompts
local-fs-pre.target  Local File Systems (Pre)
local-fs.target      Local File Systems
multi-user.target    Multi-User System
network.target       Network
paths.target         Paths
remote-fs.target     Remote File Systems
slices.target        Slices
sockets.target       Sockets
swap.target          Swap
sysinit.target       System Initialization
timers.target        Timers

Wichtig: default.target gibt es auch noch, ist aber auf den meisten Servern gleich dem basic.target.

Das „höchste“ Target ist das graphical.target, welches von einem laufenden multi-user.target abhängt - ohne dieses gibt es keine grafische Oberfläche. Die folgende Skizze zeigt die Abhängigkeiten der Targets untereinander:

graphical.target (früher: Runlevel 5)
└─multi-user.target (früher: Runlevel 3)
 ├─basic.target
 │ ├─paths.target
 │ ├─slices.target
 │ ├─sockets.target
 │ ├─sysinit.target
 │ │ ├─cryptsetup.target
 │ │ ├─local-fs.target
 │ │ └─swap.target
 │ └─timers.target
 ├─getty.target
 └─remote-fs.target

Obiges Bild erhält man per systemctl list-dependencies | grep target

Spezifisches Target booten

Beispiel: zur Installation eines Grafikkarten-Treibers muss in den Multi-User-Target gebootet werden. Nach dem Neustart das Boot-Menü anhalten, gewünschte Kernel-Version wählen und e für „edit“ drücken. Nach der Zeile beginnend mit linux /vmlinuz..., linux16 /vmlinuz... oder linuxefi /vmlinuz... suchen und ergänzen:

systemd.unit=multi-user.target

Targets zur Laufzeit wechseln

Wer z.B. in einer laufenden Kommandozeile die graphische Oberfläche starten, etwas umkonfigurieren und danach beenden möchte, führt das hier aus:

systemctl isolate graphical.target
...
systemctl isolate multi-user.target

Default-Target setzen

Damit RHEL beispielsweise immer in die graphische Oberfläche bootet, führt man aus:

systemctl set-default graphical.target
# or
ln -s /usr/lib/systemd/system/graphical.target /etc/systemd/system/default.target

Boot unterbrechen, Maschine reparieren

Level

Boot-Parameter

root-Passwort nötig

FS-Status

Bemerkung

0

rd.break

nein

ro

direkt nach initramfs, daher Chroot nötig; mount -o remount,rw /sysroot; chroot /sysroot; ...; touch ./autorelabel; exit; exit

1

systemd-unit=emergency.target

ja

ro

kein Netz, keine Mounts etc.; mount -o remount,rw /; ...; exit

2

systemd-unit=rescue.target

ja

rw

kein Netz, keine Mounts etc.

Siehe auch man kernel-command-line.

/boot

Das /boot-Verzeichnis enthält die wenigen notwendigen Dateien, um das System zu starten. Für jede installierte Kernel-Version werden vier Dateien vorgehalten:

  • config: die Kernel-Konfiguration zu Debug-Zwecken

  • initramfs: das initiale RAM-Dateisystem

  • System.map: Kernel-Symboltabelle, ebenfalls zu Debug-Zwecken

  • vmlinuz: das komprimierte Image des Linux-Kernels. Während des Boot-Vorgangs wird er entpackt, ins RAM geladen und ausgeführt.

Während des Boot-Vorgangs ist auch von Interesse:

  • initrd: die initial ramdisk ist ein temporäres Dateisystem, das vom Linux-Kernel während des Bootvorgangs verwendet wird.

Eine automatisierte Installation muss richtig booten können. Dafür müssen folgende Parameter vorhanden, gesetzt oder bekannt sein:

  • Pfad zu einer initrd: /path/to/CentOS-7-x86_64-Minimal-1810-initrd.img

  • Pfad zum Kernel: /path/to/CentOS-7-x86_64-Minimal-1810-vmlinuz

  • Evtl. Kickstart-Parameter: ks=/path/to/ks.cfg ip={{ IP }}::{{ Gateway }}:{{ Netmask }}:{{ FQDN }}:eth0:none nameserver={{ DNS1 }} nameserver={{ DNS2 }}"

Unter /boot findet sich auch der Grand Unified Bootloader (GRUB).

GRUB

Boot-Menü anpassen

Ein Beispiel: um den Timeout für die Wahl des zu startenden Kernels von standardmässig 5 Sekunden auf eine Sekunde runterzusetzen, geht man ab RHEL 7 wie folgt vor:

/etc/default/grub
GRUB_TIMEOUT=1

Um einen anderen Default-Kernel beim Start zu setzen, übergibt man der Direktive GRUB_DEFAULT den passenden, internen Kernel-Namen. Diese lassen sich wie folgt ermitteln:

awk -F\' '$1=="menuentry " {print $4}' /etc/grub2.cfg

Anschliessend (Beispiel):

/etc/default/grub
GRUB_DEFAULT="gnulinux-3.10.0-514.el7.x86_64-advanced-58a2508a-6e91-4d9a-85ee-c7143675cf27"

Tipp

GRUB2-Konfiguration für Maschinen mit Standard-BIOS neu bauen:

grub2-mkconfig --output=/boot/grub2/grub.cfg

Für Maschinen mit UEFI-Boot lautet der Befehl:

grub2-mkconfig --output=/boot/efi/EFI/centos/grub.cfg
grub2-mkconfig --output=/boot/efi/EFI/fedora/grub.cfg
grub2-mkconfig --output=/boot/efi/EFI/redhat/grub.cfg
grub2-mkconfig --output=/boot/efi/EFI/rocky/grub.cfg

Hier schaut grub2-mkconfig nach, wenn es eine neue GRUB-Konfiguration erstellt:

/boot/grub2/grub.cfg
           |
           |__________________
           |                  |
     /etc/default/grub     /etc/grub.d/*

GRUB Bootloader reparieren

Mit CentOS-CD in den Troubleshooting-Modus / Rescue-Mode booten. Dann:

chroot /mnt/sysimage
grub2-install /dev/vda
grub2-mkconfig --output=/boot/grub2/grub.cfg

GRUB Boot-Loader wiederherstellen (BIOS)

Fehlerhafte /etc/default/grub; auch im Rescue-Modus bootet die Maschine nicht richtig oder endlos?

  • System von einem Installationsmedium booten, z.B. einem CentOS 7 Minimal-ISO.

  • Im Boot-Screen Esc drücken und als Kommando linux rescue eingeben.

  • Root-Umgebung auf die Systemumgebung legen: chroot /mnt/sysimage

  • Anschliessend kann man mittels Vim, nano & Co. der /etc/default/grub zu Leibe rücken, mit lvm vgdisplay LVMs untersuchen und grub2-mkconfig neu anwenden.

Boot-Loader neu installieren?

  • Wie oben in den Rescue Modus booten, aber als letzter Schritt /sbin/grub-install /dev/sda1 (angenommen, sda1 ist die zerstörte Boot-Partition)

  • cat /etc/default/grub usw.

GRUB Boot-Loader wiederherstellen (UEFI)

Aus Versehen Windows neu installiert, und das vorher per Dual-Boot vorhandene Fedora wird nicht mehr zum Starten angeboten?

Mit Fedora Live booten, dann im Terminal:

su -
mount /dev/fedora_markus/root /mnt
mount /dev/sda7 /mnt/boot

mount --bind /dev /mnt/dev
mount --bind /proc /mnt/proc
mount --bind /sys /mnt/sys
chroot /mnt

dnf reinstall grub2-efi
grub2-mkconfig --output=/boot/efi/EFI/fedora/grub.cfg

root-Passwort zurücksetzen

Reset password, reset root password? So geht’s:

  • Maschine (neu) starten.

  • Boot-Menü anhalten, gewünschte Kernel-Version wählen und e für „edit“ drücken.

  • Nach der Zeile beginnend mit linux /vmlinuz..., linux16 /vmlinuz... oder linuxefi /vmlinuz... suchen.

  • Zeile mit rw init=/sysroot/bin/sh ergänzen.

  • Anschliessend Ctrl`+ :kbd:`x drücken.

  • Arbeitsverzeichnis wechseln: chroot /sysroot

  • Passwort ändern: passwd

  • SELinux-Kontexte für die geänderten Dateien beim nächsten Start reparieren lassen: touch /.autorelabel

  • 2x exit oder Ctrl`+ :kbd:`d

Das Relabeling kann einige Zeit in Anspruch nehmen und darf auf keinen Fall abgebrochen werden.

EFI-Shell

Am Beispiel von BIOS-Updates für Supermicro-Server, per UEFI-Shell durchgeführt. Die EFI-Shell ist DOS-orientiert. Mit „fs0:“ wechselt man Laufwerke, der Backslash trennt Verzeichnisangaben.

  • Beim Hochfahren des Servers mit F11 in die „Boot Options > UEFI Shell“ wechseln.

  • map zeigt alle verfügbaren Devices (HDD, SSD, USB-Sticks) an.

  • fs0: wechselt auf ein Laufwerk.

  • cd bios wechselt in das BIOS-Update-Verzeichnis, z.B. eines USB-Sticks.

  • flash.nsh X11DPU7.218 als Beispiel für die Ausführung eines EFI-Shell-Programms.

Troubleshooting

end_request: I/O error, dev fd0, sector 0

In einer VM, nachdem ein Diskettenlaufwerk entfernt wurde? Die Meldung sieht nicht nur unschön aus, sie verzögert auch noch den Boot-Vorgang.

Abhilfe: das entfernte Diskettenlaufwerk muss im BIOS der virtuellen Maschine deaktiviert werden. Unter VMware gelangt man beim Neustart mit F2 in das BIOS des Gastes.

Warum dauert der Bootvorgang so lange? Welche Komponenten brauchen besonders lange beim Starten?
systemd-analyze blame
Abhängigkeiten der Services anzeigen
systemctl list-dependencies
Welche Daemons sind blockierend voneinander abhängig?
systemd-analyze critical-chain
GRUB2-Config zerstört, Root-Partition wird nicht mehr gefunden?

Beim Boot ergänzen:

linux16 ... rd.shell

Built on 2022-06-03