Zum Inhalt springen

Bootvorgang und systemd

Zwischen dem Einschalten und dem Login-Prompt passieren ein paar Dinge in fester Reihenfolge. Wer diese Kette kennt, versteht, warum ein Dienst «beim Booten» startet, was multi-user.target bedeutet und wo man ansetzt, wenn ein System nicht hochkommt.

flowchart TD
    FW["Firmware (UEFI)<br/>Hardware initialisieren, Bootloader von der Disk laden"]
    GRUB["Bootloader (GRUB)<br/>Kernel und initramfs in den Speicher laden"]
    K["Linux-Kernel<br/>CPU, Speicher, Treiber"]
    IR["initramfs<br/>Mini-Dateisystem im RAM: Root-Dateisystem finden und einhängen"]
    SD["systemd (PID 1)<br/>erster Prozess, startet alles Weitere"]
    T["Target<br/>z.B. multi-user.target"]
    S1["ssh.service"]
    S2["cron.service"]
    S3["nginx.service"]
    FW --> GRUB --> K --> IR --> SD --> T
    T --> S1
    T --> S2
    T --> S3
  1. Die Firmware (heute UEFI, früher BIOS) prüft die Hardware und lädt den Bootloader von der EFI-Partition.
  2. GRUB zeigt allenfalls ein Menü, lädt den Kernel (/boot/vmlinuz-...) und das initramfs (/boot/initrd.img-...).
  3. Der Kernel übernimmt die Hardware. Das initramfs enthält die Treiber und Werkzeuge, um das eigentliche Root-Dateisystem zu finden (auch verschlüsselt oder auf LVM) und einzuhängen.
  4. Danach startet der Kernel genau ein Programm: /sbin/init, auf Ubuntu ein Link auf systemd. Es bekommt die Prozess-ID 1 und ist der Vorfahre aller anderen Prozesse.
  5. systemd startet die Dienste, die zum Ziel (Target) gehören, und zwar parallel, soweit es die Abhängigkeiten erlauben.

Hands-on: Schau dir die Beteiligten an.

Terminal-Fenster
ls /boot
ls -l /sbin/init
ps -p 1 -o pid,comm
pstree -p | head -n 15

Bis etwa 2015 startete Linux mit SysVinit: ein Skript pro Dienst in /etc/init.d/, nacheinander abgearbeitet, und der Systemzustand hiess Runlevel (0 bis 6). Du begegnest den Begriffen noch in alten Anleitungen und Forenbeiträgen, darum hier die Übersetzung:

Runlevel Bedeutung systemd-Target
0 Ausschalten poweroff.target
1 Single-User, Wartung, kein Netz rescue.target
2, 3, 4 Multi-User mit Netz, ohne GUI multi-user.target
5 Multi-User mit grafischer Oberfläche graphical.target
6 Neustart reboot.target

Der Befehl runlevel existiert aus Kompatibilität noch, aber er sagt dir weniger als:

Terminal-Fenster
systemctl get-default

Auf Ubuntu Server ist das multi-user.target, auf dem Desktop graphical.target. Mit sudo systemctl set-default multi-user.target könntest du einen Desktop dauerhaft ohne GUI booten lassen.

systemd ist das Init-System und gleichzeitig der Dienstmanager: Es startet Dienste, überwacht sie, startet sie bei Absturz neu, löst Abhängigkeiten auf und sammelt ihre Ausgaben im Journal. Alles, was systemd verwaltet, ist eine Unit. Der Typ steht in der Dateiendung:

Unit-Typ Beispiel Beschreibt
.service ssh.service Ein Programm, das als Dienst läuft
.timer logrotate.timer Einen Zeitplan, der eine Service-Unit auslöst
.socket ssh.socket Einen Port, bei dessen erstem Zugriff der Dienst gestartet wird
.mount home.mount Ein eingehängtes Dateisystem
.target multi-user.target Eine Gruppe von Units, ein Ziel, kein Programm

Hands-on: Units ansehen.

Terminal-Fenster
systemctl list-units --type=service
systemctl list-units --type=service --state=running
systemctl list-units --type=target
systemctl list-unit-files --type=service | head -n 30

list-units zeigt, was gerade geladen ist und in welchem Zustand (active, failed, inactive). list-unit-files zeigt alle installierten Unit-Dateien und ob sie beim Booten aktiviert werden (enabled, disabled, static, masked). Was bedeutet wohl static? Schau in man systemctl unter list-unit-files nach.

Terminal-Fenster
systemctl --failed

Diese Zeile gehört zu den ersten, die du nach dem Login auf einem fremden Server tippst. Im Idealfall: 0 loaded units listed.

Verzeichnis Inhalt Wer schreibt hier
/usr/lib/systemd/system/ Units aus Paketen (apt install nginx legt nginx.service hier ab) Der Paketmanager. Nicht von Hand ändern, ein Update überschreibt es.
/etc/systemd/system/ Eigene Units, Anpassungen, und die Links, die enable erzeugt Du als Admin. Hat Vorrang vor /usr/lib.
/run/systemd/system/ Zur Laufzeit erzeugte Units, weg nach dem Neustart systemd selbst
Terminal-Fenster
ls /usr/lib/systemd/system | wc -l
ls /etc/systemd/system
ls -l /etc/systemd/system/multi-user.target.wants/

Im letzten Verzeichnis siehst du Symlinks. Genau das tut systemctl enable: Es legt einen Link vom Target auf die Unit. Mehr dazu auf der nächsten Seite.

Weil systemd jeden Schritt mit Zeitstempel protokolliert, kannst du nachsehen, wie lange der Boot gedauert hat und wer die Zeit gebraucht hat:

Terminal-Fenster
systemd-analyze
systemd-analyze blame | head -n 15
systemd-analyze critical-chain

blame sortiert die Units nach ihrer Startdauer. Oft steht ganz oben etwas, das auf das Netzwerk oder eine Cloud-Initialisierung wartet. critical-chain zeigt den längsten Pfad von Abhängigkeiten bis zum Standard-Target. Wichtig beim Lesen: Die Units starten parallel, die Zeiten in blame addieren sich darum nicht zur Gesamtzeit.

Lösung anzeigen
Terminal-Fenster
script labs/linux/09-dienste/boot.txt
systemctl get-default
ps -p 1 -o pid,comm
systemctl list-units --type=service --state=running --no-legend | wc -l
systemctl list-unit-files --no-legend | wc -l
systemd-analyze
systemd-analyze blame | head -n 3
# Antwort 4: Am langsamsten war cloud-init, weil es beim Start auf Netzwerk und Metadaten wartet.
# Eigene Units gehören nach /etc/systemd/system, weil /usr/lib/systemd/system dem Paketmanager gehört und bei Updates überschrieben wird.
exit

Selbstcheck · 5 Fragen

1. Welche Reihenfolge ist richtig?
2. Welche PID hat systemd?
3. Was ist ein Target?
4. Wo legst du eine selbst geschriebene Unit-Datei ab?
5. Was zeigt `systemd-analyze blame`?