Heimserver & Self-Hosting

Netzwerkbereitschaft mit systemd - Was network-online.target wirklich zusichert

Netzwerkbereitschaft mit systemd - Was network-online.target wirklich zusichert

Ein Dienst startet beim Booten, versucht einen entfernten Endpunkt zu erreichen und scheitert, weil der Rechner noch keine Adresse erhalten hat. After=network.target hinzuzufügen wirkt wie die naheliegende Lösung. Doch bei der nächsten langsamen DHCP-Antwort tritt derselbe Fehler erneut auf. Was hat diese Abhängigkeit tatsächlich zugesichert?

Auf einem von systemd verwalteten Debian-Server ist „das Netzwerk ist verfügbar“ kein universeller Zustand. Es kann bedeuten, dass der Netzwerkmanager gestartet wurde, eine Schnittstelle eine Adresse besitzt, eine Route existiert, DNS funktioniert oder ein bestimmter entfernter Dienst antwortet. Diese Bedingungen können zu unterschiedlichen Zeitpunkten eintreten, und die Verbindung kann nach dem Booten wieder verschwinden. Die sinnvolle Aufgabe besteht daher nicht darin, ein magisches Target zu finden. Stattdessen sollte die kleinste tatsächlich benötigte Bedingung benannt und entschieden werden, ob der Bootvorgang darauf warten muss.

Drei Targets beschreiben drei verschiedene Zeitpunkte

systemd stellt network-pre.target, network.target und network-online.target bereit, doch ihre Namen lassen sich leicht wie eine Fortschrittsanzeige lesen. Die Upstream-Dokumentation zur Netzwerksynchronisierung gibt ihnen engere Bedeutungen.

network-pre.target: bevor die Konfiguration beginnt

Dieses passive Target ist hauptsächlich für Software vorgesehen, die vor der Konfiguration von Schnittstellen laufen muss, etwa für die Einrichtung einer Firewall. Ein Dienst, der diese Reihenfolge benötigt, zieht das Target in die Transaktion und ordnet sich davor ein. Gewöhnliche Netzwerk-Clients und -Server haben meist keinen Grund, es zu verwenden.

network.target: Der Verwaltungs-Stack wurde gestartet

network.target verspricht weder, dass eine physische Schnittstelle erschienen ist, noch dass DHCP abgeschlossen oder eine IP-Adresse nutzbar ist. Das Debian-Handbuch systemd.special(7) bezeichnet seine Bedeutung beim Start als nur schwach definiert. Sein klarerer Nutzen zeigt sich beim Herunterfahren: Ein danach angeordneter Dienst wird beendet, bevor der Netzwerk-Stack heruntergefahren wird, sodass bestehende Verbindungen geordneter geschlossen werden können.

Dieses Fragment drückt daher eine Reihenfolge relativ zum Netzwerk-Stack aus, nicht die Bereitschaft einer Adresse:

[Unit]
After=network.target

Wenn ein Client ohne anfängliche Netzwerkkonfiguration überhaupt nicht starten kann, reicht dies nicht aus.

network-online.target: Die konfigurierte Startschwelle wurde erreicht

network-online.target ist ein aktives Target für Units, die beim Start zwingend ein konfiguriertes Netzwerk benötigen. Es kann einen Wartedienst in die Boottransaktion ziehen und abhängige Arbeit verzögern, bis dieser Dienst beendet ist. Die genaue Schwelle wird absichtlich dem Netzwerkmanager und der lokalen Konfiguration überlassen. Das Target ist deshalb ein Synchronisationspunkt und keine herstellerunabhängige Definition von Internetzugang.

Es ist außerdem ein einmaliges Bootkonzept. Das Debian-Handbuch stellt ausdrücklich fest, dass es den Onlinezustand des Systems nach dem Booten nicht weiter verfolgt. Ein Kabel kann entfernt werden, eine Route kann verschwinden oder eine entfernte API kann ausfallen, nachdem das Target aktiv geworden ist. Jeder Dienst, der solche Ereignisse überstehen muss, benötigt weiterhin Fehlerbehandlung zur Laufzeit.

Wants= und After= lösen unterschiedliche Probleme

Für einen Dienst, der die Schwelle beim Booten tatsächlich benötigt, lautet das dokumentierte systemd-Muster:

[Unit]
Wants=network-online.target
After=network-online.target

Die beiden Zeilen sind nicht redundant. Laut systemd.unit(5) zieht Wants= die genannte Unit als schwache Anforderung in dieselbe Transaktion. Es legt keine Reihenfolge fest. After= legt die Reihenfolge fest, wenn beide Units gestartet werden, zieht die andere Unit aber nicht hinein. Nur After= kann einen Dienst hinter einem Target einordnen, das niemand angefordert hat; nur Wants= lässt beide Jobs ohne die gewünschte Reihenfolge ablaufen.

Requires=network-online.target ist nicht einfach eine „sicherere“ Schreibweise. Requires= erzeugt eine stärkere Kopplung der Lebenszyklen, obwohl das Online-Target die Konnektivität weiterhin nicht dauerhaft abbildet. Das übliche Wants=-Muster lässt den Dienst auch dann starten, wenn die Wait-Unit scheitert oder ihr Timeout erreicht, sodass die Anwendung ihren tatsächlichen Vorgang melden oder erneut versuchen kann. Eine bestimmte Anwendung kann strengeres Verhalten benötigen, doch diese Entscheidung sollte aus ihrem Fehlervertrag folgen und nicht aus dem Wort „online“.

Die Wait-Implementierung definiert „online“

Das Target selbst prüft keine Schnittstellen. Davor läuft ein für den Netzwerkmanager spezifischer Dienst. Auf üblichen Debian-Installationen kann dies NetworkManager-wait-online.service oder systemd-networkd-wait-online.service sein. Den falschen Dienst zu aktivieren lässt den jeweils anderen Netzwerkmanager nicht schneller fertig werden.

Bei systemd-networkd wartet der standardmäßige Wait-Dienst darauf, dass verwaltete Links fertig konfiguriert sind oder fehlschlagen und mindestens ein Link online ist. Das Debian-Handbuch systemd-networkd-wait-online(8) definiert die standardmäßige Online-Schwelle als einen Betriebszustand von mindestens degraded. Schnittstellenspezifische Instanzen und Optionen wie --any, --ipv4 und --ipv6 können die Bedingung verändern. Auch Netzwerkdateien können beeinflussen, ob ein Link für den Onlinestatus erforderlich ist.

NetworkManager verwendet ein anderes Modell. Seine Wait-online-Dokumentation erklärt, dass das Target verzögert wird, bis NetworkManager über D-Bus meldet, dass der Start abgeschlossen ist. Verbindungsprofile, Einstellungen zu Adressfamilien, Aktivierungswiederholungen, WLAN-Scans und das Warten auf Ethernet-Carrier beeinflussen diesen Zeitpunkt. Bei einem Profil mit aktiviertem IPv4 und IPv6 kann die Standardeinstellung das Gerät bereits als aktiviert betrachten, wenn eine der Familien bereit ist. Dies sind NetworkManager-Semantiken, keine Regeln für Betriebszustände von systemd-networkd.

Keine der beiden Implementierungen kann den Vertrag jeder Anwendung ableiten. Eine konfigurierte Route beweist nicht, dass sync.example.net aufgelöst werden kann oder antwortet. Umgekehrt bedeutet ein vorübergehender Ausfall dieses Endpunkts nicht zwangsläufig, dass die lokale Schnittstelle falsch konfiguriert ist.

Vor dem Hinzufügen einer Abhängigkeit prüfen

Zunächst sollten der Netzwerkmanager und die bereits vorhandene Wait-Unit ermittelt werden. Diese Befehle sind schreibgeschützt:

systemctl is-active NetworkManager.service systemd-networkd.service
systemctl is-enabled NetworkManager-wait-online.service \
  systemd-networkd-wait-online.service
systemctl status network-online.target
systemctl list-dependencies --reverse network-online.target

Ein aktivierter Wait-Dienst ist nur ein Indiz. Er zeigt weder, dass eine bestimmte Boottransaktion network-online.target einbezogen hat, noch dass dessen Definition zur Anwendung passt. Auch der Verbraucher und der Wait-Dienst sollten geprüft werden:

systemctl cat example-sync.service
systemctl cat NetworkManager-wait-online.service
systemd-analyze critical-chain network-online.target
journalctl --boot --unit=NetworkManager-wait-online.service

example-sync.service ist ein Platzhalter. Er ist durch die tatsächliche Unit und den auf diesem Host verwendeten Wait-Dienst zu ersetzen. Die Critical Chain und das Journal können zeigen, wo der Bootvorgang gewartet hat, beweisen aber keine Bereitschaft von DNS oder einer entfernten Anwendung.

Nur bei wirklich strikter Arbeit auf das Netzwerk warten

Angenommen, ein einmaliger Synchronisationsjob ist ohne anfängliche Netzwerkkonfiguration nutzlos und kann sicher einen Fehler melden, falls sein entfernter Vorgang weiterhin nicht funktioniert. Ein lokales Drop-in kann die Startabhängigkeit ausdrücken, ohne die gesamte Unit des Pakets zu kopieren:

sudo systemctl edit example-sync.service
[Unit]
Wants=network-online.target
After=network-online.target

Nach dem Speichern sollten die zusammengeführte Unit geprüft und ihre Syntax verifiziert werden, bevor ein echter Test geplant wird:

systemctl cat example-sync.service
systemd-analyze verify example-sync.service

Ein Test des Startpfads kann Arbeit unterbrechen oder wiederholen und sollte deshalb entsprechend den Nebenwirkungen der Anwendung geplant werden. Ein erfolgreicher Start beweist nur, dass dieser Versuch gemäß dem eigenen Exit-Verhalten der Unit abgeschlossen wurde. Er macht das Target nicht zu einem dauerhaften Konnektivitätsmonitor.

Readiness nicht durch eine feste Pause ersetzen

ExecStartPre=/usr/bin/sleep 30 hinzuzufügen kann bei einem Bootvorgang einen Wettlauf verbergen und bei einem anderen 30 Sekunden verschwenden. Es beobachtet vergangene Zeit statt der erforderlichen Bedingung. Eine Schleife, die eine öffentliche Adresse anpingt, weist denselben Widerspruch auf: ICMP-Erreichbarkeit dieses Hosts beweist weder DNS, TLS und Zugangsdaten noch die Funktion der vorgesehenen API. Manche Netzwerke blockieren zudem ICMP, obwohl nützliche Dienste erreichbar bleiben.

Wenn ein einzelner Endpunkt die tatsächliche Voraussetzung ist, kann meist die Anwendung selbst ihre Fehler am besten interpretieren. Sie kann zwischen Fehlern bei der Namensauflösung, abgelehnten Verbindungen, fehlgeschlagener Authentifizierung und ungültigen Antworten unterscheiden. Ein Service Manager kann Wiederholungen planen oder einen fehlgeschlagenen Client neu starten, doch Begrenzung, Verzögerung, Idempotenz und Alarmierung müssen weiterhin bewusst gestaltet werden. Unbegrenzt zu warten verschiebt einen Ausfall lediglich in den Bootablauf.

Das Verhalten nach dem Workload wählen

  • Ein Netzwerkserver, der auf Wildcard- oder lokalen Adressen lauscht: Er sollte üblicherweise starten, ohne network-online.target einzubeziehen. Die Upstream-Anleitung von systemd rät ausdrücklich von einer breiten Nutzung des Targets für Serversoftware ab, die lokale Verbindungen annehmen kann, bevor eine routbare Schnittstelle verfügbar ist.
  • Ein langlebiger Client oder Worker: Er sollte starten und vorübergehende Fehler mit begrenzten Wiederholungen oder dynamischer Behandlung von Netzwerkänderungen verarbeiten. Dies deckt auch Ausfälle Stunden nach dem Booten ab.
  • Ein strikter One-shot-Client: Wants= und After=network-online.target können einen unmittelbaren, vorhersehbaren Wettlauf beim Booten vermeiden. Der Vorgang benötigt dennoch ein Timeout und ein ehrliches Fehlerergebnis.
  • Ein entferntes Dateisystem: Die Mount-Werkzeuge sollten ihre Netzwerkabhängigkeit selbst ausdrücken. systemd richtet für entfernte Mounts bereits Abhängigkeiten zum Online-Target ein, sodass ein unabhängiger Anwendungsdienst sie nicht neu erfinden muss.

Es gibt Ausnahmen. Ein Server, der nur an eine einzelne spät erscheinende Adresse gebunden ist, kann scheitern, während ein Wildcard-Listener funktionieren würde. Ein Laptop mit optionalem WLAN sollte nicht den gesamten Bootpfad wegen einer unwichtigen Hintergrundsynchronisierung anhalten. Bei einem Server mit mehreren Schnittstellen kann nur ein Management-Link wichtig sein, nicht aber ein nicht angeschlossener zweiter Port. Solche Fälle sind Gründe, den Readiness-Vertrag zu präzisieren, statt den ganzen Rechner lediglich als online oder offline zu bezeichnen.

Fazit

network.target markiert das Vorhandensein des Netzwerkverwaltungs-Stacks, während network-online.target auf eine konfigurierte, vom aktiven Netzwerkmanager definierte Startschwelle warten kann. Die Kombination von Wants= und After= fordert diese Schwelle an und ordnet einen Verbraucher danach ein. Keine dieser Aussagen beweist, dass DNS, das Internet oder ein bestimmter Dienst dauerhaft erreichbar bleiben.

Der robusteste Dienst kann meist vor perfekter Konnektivität starten, einen fehlgeschlagenen Vorgang erklären und sich erholen, wenn sich das Netzwerk ändert. Das Warten beim Booten hat für strikte Clients und entfernte Ressourcen weiterhin eine berechtigte Rolle, sollte aber ein eng begrenztes Synchronisationswerkzeug bleiben. Vor dem Hinzufügen lohnt sich eine präzisere Frage als „Ist das Netzwerk verfügbar?“: Welche konkrete Bedingung benötigt dieser Workload, und was soll geschehen, wenn sie später verschwindet?

References