Systemd-Targets verstehen: Wichtige Konzepte erklärt

Verstehen Sie Systemd-Targets, Standard-Boot-Targets, Runlevel-Zuordnungen, Isolation, benutzerdefinierte Targets und Fehlerbehebungsbefehle.

Systemd-Targets verstehen: Wichtige Konzepte erklärt

Systemd-Targets sind leichter zu verstehen, wenn Sie aufhören, sie als Dienste zu betrachten. Ein Dienst startet einen Prozess. Ein Target gruppiert Units in einen benannten Systemzustand. Wenn ein Rechner zu multi-user.target bootet, startet systemd kein Programm namens "multi-user". Es versucht, einen Zustand zu erreichen, in dem die von diesem Target gewünschten Units gestartet wurden oder zumindest deren Start-Jobs versucht wurden.

Diese Unterscheidung hilft bei der Fehlersuche bei Boot-Problemen. Wenn graphical.target langsam ist, ist das Target selbst selten das Problem. Eine der Display-, Login-, Netzwerk-, Mount- oder Anwendungs-Units, die in dieses Target eingebunden sind, ist langsam oder schlägt fehl. Targets geben Ihnen die Karte.

Was sind Systemd-Targets?

Im systemd-Ökosystem ist ein Target ein spezieller Unit-Dateityp (wie .service- oder .socket-Dateien), der einem kritischen organisatorischen Zweck dient. Im Gegensatz zu Service-Units, die definieren, wie ein bestimmter Prozess gestartet oder gestoppt wird, definieren Target-Units einen Systemzustand oder eine Sammlung von Units, die gemeinsam aktiv sein sollen. Sie fungieren als logische Gruppierungspunkte und Synchronisationspunkte für andere systemd-Units.

Betrachten Sie Targets als Meilensteine auf der Betriebsreise des Systems. Wenn systemd bootet, startet es nicht einfach willkürlich eine Liste von Diensten; es arbeitet darauf hin, ein bestimmtes Target zu erreichen. Dieses Target wiederum zieht alle notwendigen Dienste, Sockets, Mountpunkte und anderen Targets hinein, die für diesen Zustand erforderlich sind. Dieser abhängigkeitsgesteuerte Ansatz gewährleistet einen vorhersagbaren und effizienten Bootvorgang.

Für diejenigen, die mit älteren Linux-Init-Systemen wie SysVinit vertraut sind, sind systemd-Targets das moderne Äquivalent zu Runleveln. Während SysVinit einen festen Satz von Runleveln hatte (z. B. Runlevel 3 für den Mehrbenutzer-Textmodus, Runlevel 5 für den Mehrbenutzer-Grafikmodus), sind systemd-Targets flexibler. Sie werden benannt, nicht nummeriert, und Sie können benutzerdefinierte Targets definieren, was eine größere Granularität und Erweiterbarkeit bietet.

Wie Targets funktionieren: Gruppierung und Abhängigkeiten

Targets erreichen ihre Gruppierungs- und Zustandsdefinitionsfähigkeiten durch explizite Abhängigkeiten, die in ihren Unit-Dateien definiert sind. Die primären Direktiven, die dafür verwendet werden, sind Wants=, Requires=, After= und Before=.

  • Wants=: Gibt "schwache" Abhängigkeiten an. Wenn Target A Wants= Unit B, wird systemd versuchen, Unit B zu starten, wenn Target A aktiviert wird. Allerdings wird Target A trotzdem starten, selbst wenn Unit B nicht startet. Dies wird häufig verwendet, um verwandte Dienste zu gruppieren, die wünschenswert, aber nicht unbedingt erforderlich sind.
  • Requires=: Gibt "starke" Abhängigkeiten an. Wenn Target A Requires= Unit B, muss Unit B erfolgreich gestartet werden, damit Target A aktiviert wird. Wenn Unit B fehlschlägt, wird auch Target A fehlschlagen oder nicht starten. Dies wird für kritische Abhängigkeiten verwendet.
  • After=: Definiert eine Reihenfolgeabhängigkeit. Wenn Target A After= Unit B hat, wird Target A erst nach dem Start von Unit B starten. Dies impliziert keine Abhängigkeit vom Erfolg, sondern nur die Reihenfolge.
  • Before=: Das Gegenteil von After=. Wenn Target A Before= Unit B hat, wird Unit B erst nach dem Start von Target A starten.
  • Conflicts=: Stellt sicher, dass bestimmte Units nicht gleichzeitig aktiv sind. Wenn Target A Conflicts= Unit B hat, wird die Aktivierung von Target A Unit B stoppen, falls es läuft, und umgekehrt.

Diese Direktiven ermöglichen es Targets, als robuste Orchestratoren zu fungieren, die Dienste und andere Targets nach Bedarf einbinden und die Reihenfolge definieren, in der sie starten sollen. Beispielsweise hat multi-user.target typischerweise Wants= network.target und verschiedene andere Dienste, um sicherzustellen, dass sie aktiv sind, wenn das System einen Mehrbenutzerzustand erreicht.

Sie können den Inhalt einer Target-Unit-Datei einsehen, um ihre Abhängigkeiten zu sehen:

systemctl cat multi-user.target

Dieser Befehl gibt den Inhalt der multi-user.target-Unit-Datei aus und zeigt deren Description, Documentation und entscheidend ihre Wants=-, Requires=-, After=- und andere Direktiven, die definieren, was den Mehrbenutzerzustand ausmacht.

Häufige Systemd-Targets erklärt

Systemd bietet eine Vielzahl vordefinierter Targets, die jeweils einem bestimmten Systemzustand oder einer bestimmten Funktionalität entsprechen. Das Verständnis dieser ist für die Systemadministration entscheidend:

  • default.target: Dies ist das wichtigste Target, da es den Standardzustand definiert, in den Ihr System booten wird. Es ist normalerweise ein Symlink entweder auf graphical.target (für Desktops) oder multi-user.target (für Server).
  • graphical.target: Dieses Target wird typischerweise für Systeme mit einer grafischen Desktop-Umgebung verwendet. Es bindet multi-user.target ein und fügt dann Dienste hinzu, die für den grafischen Login-Manager und den Display-Server erforderlich sind (z. B. GDM, LightDM, Xorg, Wayland).
  • multi-user.target: Dies ist der Standardzustand für Mehrbenutzersysteme ohne grafische Oberfläche. Es ist üblich für Server und stellt alle notwendigen Dienste für den Kommandozeilenzugriff, Netzwerk und die meisten Daemon-Operationen bereit.
  • basic.target: Ein minimaler Zustand, der grundlegende Systemdienste für fundamentale Operationen umfasst, aber vor multi-user.target. Es bindet typischerweise sysinit.target und andere wesentliche Dienste ein.
  • sysinit.target: Dieses Target wird sehr früh im Bootvorgang erreicht. Es ist verantwortlich für Kern-Systeminitialisierungsaufgaben wie das Mounten von /etc/fstab-Dateisystemen (außer entfernten), das Einrichten von Swap und andere hardwarebezogene Initialisierungen.
  • local-fs.target: Stellt sicher, dass alle lokalen Dateisysteme, die in /etc/fstab angegeben sind, gemountet werden.
  • remote-fs.target: Stellt sicher, dass alle entfernten Dateisysteme (z. B. NFS, CIFS), die in /etc/fstab angegeben sind, gemountet werden.
  • network.target: Zeigt an, dass grundlegende Netzwerkkonnektivität verfügbar ist (z. B. Netzwerkschnittstellen sind aktiv). Es garantiert keine vollständige Internetverbindung oder IP-Adresszuweisung.
  • network-online.target: Ein Synchronisationspunkt für Dienste, die warten möchten, bis der Netzwerkmanager das Netzwerk als online betrachtet. Es beweist nicht, dass das Internet, DNS oder eine entfernte API erreichbar ist, und funktioniert nur wie erwartet, wenn der entsprechende Wait-Online-Dienst aktiviert ist.
  • rescue.target: Bietet eine Einzelbenutzer-Shell mit minimal laufenden Diensten und gemounteten lokalen Dateisystemen. Nützlich für Systemwiederherstellung und Fehlerbehebung.
  • emergency.target: Eine noch minimalere Umgebung als rescue.target. Es bietet eine Shell auf dem Root-Dateisystem, das typischerweise schreibgeschützt gemountet ist. Es werden keine anderen Dienste gestartet. Für kritische Notfallsituationen.
  • poweroff.target, reboot.target, halt.target: Diese Targets werden verwendet, um das System herunterzufahren, neu zu starten oder anzuhalten. Bei Aktivierung stoppen sie die meisten Dienste und bereiten das System auf den gewünschten Energiezustand vor.

Verwalten von Systemd-Targets

Die Interaktion mit systemd-Targets erfolgt hauptsächlich über das Kommandozeilenprogramm systemctl.

Anzeigen aktiver und Standard-Targets

Um zu sehen, in welchem Target Ihr System derzeit läuft:

systemctl get-default

Um alle derzeit geladenen Target-Units aufzulisten:

systemctl list-units --type=target

Dieser Befehl zeigt aktive, geladene und statische Targets zusammen mit ihren Beschreibungen an.

Ändern des Standard-Boot-Targets

Sie können das Target ändern, in das Ihr System standardmäßig bootet. Um beispielsweise multi-user.target als Standard festzulegen:

sudo systemctl set-default multi-user.target

Um zu graphical.target zurückzukehren:

sudo systemctl set-default graphical.target

Dieser Befehl erstellt einen symbolischen Link von /etc/systemd/system/default.target zur gewünschten Target-Datei.

Temporär in ein anderes Target booten

Manchmal müssen Sie nur einmal in ein bestimmtes Target booten (z. B. zur Fehlerbehebung). Sie können dies erreichen, indem Sie während des Bootvorgangs einen Kernel-Parameter anhängen. Wenn das GRUB-Bootmenü erscheint, bearbeiten Sie den Booteintrag (normalerweise durch Drücken von e) und fügen Sie systemd.unit=target_name.target zur Kernel-Befehlszeile hinzu.

Um beispielsweise in den Rettungsmodus zu booten:

systemd.unit=rescue.target

Wechseln von Targets während der Laufzeit

Sie können während des laufenden Systems mit dem Befehl systemctl isolate zu einem anderen Target wechseln. Dieser Befehl stoppt alle Dienste, die nicht vom neuen Target benötigt werden, und startet alle davon benötigten Dienste.

Warnung: Die Verwendung von systemctl isolate kann den Betrieb Ihres Systems stören, insbesondere wenn Sie auf einem Desktop-Rechner von graphical.target zu einem viel niedrigeren Target wie multi-user.target wechseln. Mit Vorsicht verwenden.

Um von graphical.target zu multi-user.target zu wechseln:

sudo systemctl isolate multi-user.target

Um zurück zu graphical.target zu wechseln (vorausgesetzt, es war der vorherige Zustand):

sudo systemctl isolate graphical.target

Erstellen benutzerdefinierter Targets

Obwohl systemd viele nützliche Targets bereitstellt, gibt es Situationen, in denen die Erstellung eines benutzerdefinierten Targets vorteilhaft ist. Dies gilt insbesondere für komplexe Anwendungsbereitstellungen, bei denen Sie mehrere Dienste gruppieren müssen, die immer zusammen starten und stoppen sollen, oder um eine bestimmte Umgebung für Ihre Anwendung zu definieren.

Um ein benutzerdefiniertes Target zu erstellen:

  1. Erstellen Sie eine .target-Datei: Platzieren Sie sie in /etc/systemd/system/. Zum Beispiel my-application.target.
    # /etc/systemd/system/my-application.target
    [Unit]
    Description=Mein benutzerdefiniertes Anwendungs-Target
    Wants=my-database.service my-webserver.service
    After=my-database.service my-webserver.service
    
    • Description: Eine menschenlesbare Beschreibung.
    • Wants=: Listen Sie die Dienste oder anderen Targets auf, die dieses Target einbinden soll.
    • After=: Definieren Sie die Reihenfolge. Das Target startet nach diesen Units.
  2. Erstellen Sie die Dienste: Stellen Sie sicher, dass my-database.service und my-webserver.service (oder welche Dienste Sie auch auflisten) existieren und ordnungsgemäß konfiguriert sind.
  3. Laden Sie systemd neu: Informieren Sie systemd über die neue Unit-Datei.
    
    

sudo systemctl daemon-reload 4. **Aktivieren und Starten**: Sie können jetzt Ihr benutzerdefiniertes Target aktivieren und starten, was wiederum seine gewünschten Dienste startet. bash sudo systemctl enable my-application.target sudo systemctl start my-application.target ```

Dies ermöglicht es Ihnen, eine Gruppe verwandter Dienste als eine einzige logische Einheit zu verwalten, was komplexe Anwendungsbereitstellungen vereinfacht.

Runlevel und Targets ohne die Nebelkerzen

Wenn Sie von SysVinit kommen, ist die grobe Zuordnung:

Alte Runlevel-Idee Häufiges systemd-Target
Einzelbenutzer-Reparaturmodus rescue.target
Mehrbenutzer-Textmodus multi-user.target
Mehrbenutzer-Grafikmodus graphical.target
Neustart reboot.target
Herunterfahren poweroff.target

Behandeln Sie dies als Übersetzungshilfe, nicht als perfektes Modell. SysV-Runlevel waren ein kleiner fester Satz nummerierter Zustände. Systemd-Targets sind benannte Units mit Abhängigkeiten, und es kann viele davon geben. Ein Paket kann sein eigenes Target installieren. Sie können eines für einen Bereitstellungsworkflow erstellen. Einige Targets sind für die Isolation gedacht; andere sind nur Gruppierungspunkte, die während des Bootvorgangs verwendet werden.

Sie können sehen, welche Targets eine Isolation erlauben mit:

systemctl show multi-user.target -p AllowIsolate
systemctl show basic.target -p AllowIsolate

Dies ist wichtig, weil systemctl isolate kein harmloser "Ansicht wechseln"-Befehl ist. Es stoppt Units, die nicht Teil der neuen Target-Transaktion sind. Auf einem Desktop wird das Isolieren von multi-user.target normalerweise die grafische Sitzung beenden. Auf einem entfernten Server kann das Isolieren des falschen Targets Netzwerk- oder Login-Dienste stoppen und Sie aussperren.

Wie Dienste Teil eines Targets werden

Die meisten alltäglichen Target-Mitgliedschaften stammen aus dem [Install]-Abschnitt einer Service-Datei:

[Install]
WantedBy=multi-user.target

Wenn Sie ausführen:

sudo systemctl enable myapp.service

erstellt systemd einen Symlink unter einem Verzeichnis wie:

/etc/systemd/system/multi-user.target.wants/myapp.service

Dieser Symlink bewirkt, dass multi-user.target den Dienst während des Bootvorgangs haben möchte. Die Service-Datei kann existieren und vollkommen gültig sein, ohne aktiviert zu sein. In diesem Fall wird das Starten von multi-user.target sie nicht automatisch einbinden.

Aus diesem Grund lösen systemctl start myapp.service und systemctl enable myapp.service unterschiedliche Probleme. start führt es jetzt aus. enable verdrahtet es in ein zukünftiges Boot-Target. enable --now macht beides.

Um zu überprüfen, ob ein Dienst für ein Target aktiviert ist:

systemctl is-enabled myapp.service
systemctl list-dependencies multi-user.target | grep myapp

Wenn ein Dienst manuell startet, aber nicht beim Booten, ist dies eines der ersten Dinge, die Sie überprüfen sollten.

Ein kleines benutzerdefiniertes Target, das tatsächlich nützlich ist

Benutzerdefinierte Targets sind am nützlichsten, wenn sie Operatoren einen einzigen Befehl für eine Gruppe verwandter Units geben. Stellen Sie sich einen einfachen Anwendungsstack vor:

app-api.service
app-worker.service
app-scheduler.service

Sie können erstellen:

# /etc/systemd/system/app-stack.target
[Unit]
Description=Anwendungsstack
Wants=app-api.service app-worker.service app-scheduler.service
After=network-online.target
Wants=network-online.target
AllowIsolate=no

Fügen Sie dann jeden Dienst zum Target hinzu:

[Install]
WantedBy=app-stack.target

Nach daemon-reload aktivieren Sie die Dienste oder das Target, je nachdem, welches Verhalten Sie wünschen:

sudo systemctl daemon-reload
sudo systemctl enable app-api.service app-worker.service app-scheduler.service
sudo systemctl start app-stack.target

Dies gibt Ihnen eine lesbare Gruppierung, ohne so zu tun, als sei das Target ein Prozess-Supervisor. Wenn app-worker.service fehlschlägt, überprüfen Sie diesen Dienst. Das Target ist nur der Gruppierungspunkt.

Wenn Sie möchten, dass das Stoppen des Targets alle Stack-Dienste stoppt, fügen Sie PartOf=app-stack.target zu jedem Dienst hinzu:

[Unit]
PartOf=app-stack.target

Jetzt propagiert systemctl stop app-stack.target zu den Mitgliedsdiensten. Das ist oft das fehlende Stück in Beispielen für benutzerdefinierte Targets.

Fehlerbehebung mit Targets

Targets sind auch für die Fehlerbehebung bei Boot-Problemen oder Dienstausfällen von unschätzbarem Wert:

  • Identifizieren von Abhängigkeiten: Wenn ein Dienst nicht startet, kann die Überprüfung des Targets, zu dem er gehört, fehlende oder fehlschlagende Abhängigkeiten aufdecken. Verwenden Sie systemctl status <dienst_name> und systemctl list-dependencies <target_name>.
  • Booten in minimale Targets: Wenn Ihr System nicht in graphical.target oder multi-user.target bootet, versuchen Sie, mit der Kernel-Parameter-Methode in rescue.target oder emergency.target zu booten. Dies bietet eine minimale Umgebung, in der Sie Probleme diagnostizieren können, ohne die Komplexität vieler laufender Dienste.
  • Protokolle prüfen: Überprüfen Sie nach dem Versuch, ein Target oder einen Dienst zu starten, immer die journalctl-Protokolle auf Fehler:
    journalctl -b -u <target_oder_dienst_name>
    

Best Practices und Tipps

  • Verwenden Sie network-online.target mit Bedacht: Wenn Ihr Dienst vor dem Start eine Netzwerkkonfiguration benötigt, kombinieren Sie After=network-online.target mit Wants=network-online.target und bestätigen Sie, dass die entsprechende Wait-Online-Unit aktiviert ist. Behalten Sie dennoch Wiederholungslogiken in der Anwendung für entfernte Abhängigkeiten bei.
  • Verstehen Sie die Boot-Reihenfolge: Machen Sie sich mit dem allgemeinen Ablauf von sysinit.target über basic.target zu multi-user.target/graphical.target vertraut. Dies hilft bei der Fehlersuche bei Diensten, die früh im Bootvorgang fehlschlagen.
  • Seien Sie vorsichtig mit default.target: Das Ändern von default.target kann das Bootverhalten Ihres Systems erheblich verändern. Testen Sie benutzerdefinierte Konfigurationen immer zuerst in einer Nicht-Produktionsumgebung.
  • Verwenden Sie Wants= für nicht-kritische Abhängigkeiten: Für Dienste, die nützlich, aber nicht unbedingt erforderlich sind, damit ein Target als "aktiv" gilt, verwenden Sie Wants= anstelle von Requires=. Dies verhindert, dass ein einzelner optionaler Dienstausfall kaskadiert und die Aktivierung des gesamten Targets verhindert.

Das mentale Modell, das Sie behalten sollten

Ein Target ist ein benannter Zustand, kein Daemon. default.target bestimmt das normale Boot-Ziel. multi-user.target ist der übliche Serverzustand. graphical.target fügt den Display-Stack hinzu. rescue.target und emergency.target sind Reparaturwerkzeuge. Benutzerdefinierte Targets sind Gruppierungswerkzeuge, wenn sie Operationen klarer machen.

Wenn etwas Target-bezogenes kaputt geht, vermeiden Sie es, zuerst dem Target die Schuld zu geben. Fragen Sie, welche Unit eingebunden wurde, welche Reihenfolgeregel sie verzögert hat und welche Abhängigkeit fehlgeschlagen ist. systemctl cat, systemctl list-dependencies, systemctl show und journalctl -b werden diese Fragen normalerweise schneller beantworten als das Lesen generischer Boot-Diagramme.