Zyklische Abhängigkeiten in Systemd
Das Problem
Vor kurzem machte mich ein Kollege auf eine VM mit Linux aufmerksam,
die nicht erreichbar war.
Die VM selbst war scheinbar normal gestartet,
von der Konsole aus war nichts Auffälliges zu sehen,
also schaute ich mir die die Logs mit sudo journalctl --yesterday an.
Ich suchte nach der letzten Zeile die mit -- Boot begann
und schaute mir die nachfolgenden Zeilen an.
Nach einigem hin und her,
wobei ich zunächst Problem mit systemd-resolv vermutete,
fiel mir die folgende Meldung auf:
systemd-networkd-wait-online.service: Job systemd-networkd.service/start deleted to break ordering cycle ...
Die Zeilen darüber verrieten noch mehr:
systemd-networkd-wait-online.service: Found ordering cycle on systemd-networkd.service/start
systemd-networkd-wait-online.service: Found dependency on network-pre.target/start
systemd-networkd-wait-online.service: Found dependency on firewalld.service/start
systemd-networkd-wait-online.service: Found dependency on dbus.service/start
systemd-networkd-wait-online.service: Found dependency on basic.target/start
systemd-networkd-wait-online.service: Found dependency on paths.target/start
systemd-networkd-wait-online.service: Found dependency on apport-autoreport.path/start
systemd-networkd-wait-online.service: Found dependency on sysinit.target/start
systemd-networkd-wait-online.service: Found dependency on cloud-init.service/start
systemd-networkd-wait-online.service: Found dependency on systemd-networkd-wait-online.service/start
systemd-networkd-wait-online.service: Job systemd-networkd.service/start deleted to break ordering cycle starting with systemd-networkd-wait-online.service/start
Das war interessant, also schaute ich nach, ob das häufiger vorkam:
$ sudo journalctl --since yesterday |grep ordering
dbus.service: Found ordering cycle on basic.target/start
dbus.service: Job sockets.target/start deleted to break ordering cycle starting with dbus.service/start
firewalld.service: Found ordering cycle on sysinit.target/start
firewalld.service: Job cloud-init.service/start deleted to break ordering cycle starting with firewalld.service/start
basic.target: Found ordering cycle on sockets.target/start
basic.target: Job sockets.target/start deleted to break ordering cycle starting with basic.target/start
firewalld.service: Found ordering cycle on sysinit.target/start
firewalld.service: Job cloud-init.service/start deleted to break ordering cycle starting with firewalld.service/start
systemd-networkd-wait-online.service: Found ordering cycle on systemd-networkd.service/start
systemd-networkd-wait-online.service: Job systemd-networkd.service/start deleted to break ordering cycle starting with systemd-networkd-wait-online.service/start
apport-forward.socket: Found ordering cycle on sysinit.target/start
apport-forward.socket: Job cloud-init.service/start deleted to break ordering cycle starting with apport-forward.socket/start
Am Tag vorher hatten wir ein Wartungsfenster, darum gab es mehrere Neustarts. Es waren nicht immer die gleichen Dienste beziehungsweise Targets gelöscht worden, darum fiel das bisher nicht auf. Bei dem vorletzten Neustart erwischte es jedoch den Netzwerkdienst und das bekam das Monitoring mit. Nach dem letzten Neustart war der Netzwerkservice verfügbar, so dass ich mich wieder per SSH zur Fehlersuche anmelden konnte.
Die Lösung
Da ich das Problem bisher nicht kannte, suchte ich zunächst im Netz und fand zwei Stellen, die mir weiterhalfen
- systemd-timesyncd: fails on boot due to ordering cycle (dbus, sysinit)
- generic methodology to debug ordering cycles in systemd
Insbesondere die Antwort bei der zweiten Fundstelle
mit systemd-analyze verify/dot ... brachte mich weiter.
Im wesentlichen schaut man mit systemd-analyze verify ...
nach dem in der Logzeile mit Found ordering cycle on genannten Target oder Service.
In der Ausgabe dieses Befehles findet man dann die Services und Targets,
die an der zyklischen Abhängigkeit beteiligt sind.
Alle zusammen analysiert man dann mit system-analyze dot ... wie folgt:
$ sudo systemd-analyze dot \
network-pre.target \
firewalld.service \
dbus.service \
basic.target \
paths.target \
apport-autoreport.path \
sysinit.target \
cloud-init.service \
systemd-networkd-wait-online.service \
> systemd-analyze.dot
Das Programm erzeugt eine dot-Datei, die im Beispiel nach systemd-analyze.dot geschrieben wird. In der Fehlerausgabe zeigt das Programm die Bedeutung der Farben im Graph an:
Color legend: black = Requires
dark blue = Requisite
dark grey = Wants
red = Conflicts
green = After
Das Werkzeug
Leider war der Graph zu unübersichtlich, um ihn von Hand auszuwerten.
Also startete ich eine neue Suche: "find cycle in dot file". Die Suchergebnisse selbst sahen nicht vielversprechend aus, allerdings schlug der Bing KI-Agent vor, schnell ein Python-Script zu schreiben, dass die Schleifen im Graph findet.
Gesagt, getan.
Nach weniger als einer Minute stand da ein Python-Programm,
das nur pydot als Abhängigkeit brauchte.
In einer virtuellen Umgebung testete ich es mit dem Graphen
und es gab aus,
dass da eine Schleife wäre.
Das wusste ich schon vorher, also teilte ich dem Agent mit, dass ich die Schleife selbst sehen wollte. Das nächste Skript dauerte etwas länger, war aber in weniger als zwei Minuten fertig.
Das war schon ganz gut,
allerdings fiel mir dann noch ein,
dass systemd-analyze dot ...
die Abhängigkeiten farblich hervorhebt,
wie in der oben angegebenen Legende beschrieben.
Also ging es in die nächste Runde mit dem KI-Agenten.
Das nun erzeugte Skript macht genau das,
was ich für die Analyse der VM benötige.
Zusätzlich erzeugt es eine zweite dot-Datei,
in der die Schleifen hervorgehoben sind,
ohne dass ich darum gebeten hätte,
aber das sehe ich ihm erstmal nach.
Der Aufruf ./find_color_cycles.py systemd-analyze.dot
erzeugt die folgende Ausgabe:
Cycles for color '"green"':
sysinit.target -> cloud-init.service -> systemd-networkd-wait-online.service -> systemd-networkd.service -> network-pre.target -> firewalld.service -> basic.target -> sysinit.target
sysinit.target -> cloud-init.service -> systemd-networkd-wait-online.service -> systemd-networkd.service -> network-pre.target -> firewalld.service -> basic.target -> paths.target -> apport-autoreport.path -> sysinit.target
sysinit.target -> cloud-init.service -> systemd-networkd-wait-online.service -> systemd-networkd.service -> network-pre.target -> firewalld.service -> dbus.service -> sysinit.target
sysinit.target -> cloud-init.service -> systemd-networkd-wait-online.service -> systemd-networkd.service -> network-pre.target -> firewalld.service -> dbus.service -> dbus.socket -> sysinit.target
sysinit.target -> cloud-init.service -> systemd-networkd-wait-online.service -> systemd-networkd.service -> network-pre.target -> firewalld.service -> polkit.service -> sysinit.target
sysinit.target -> cloud-init.service -> systemd-networkd-wait-online.service -> systemd-networkd.service -> network-pre.target -> firewalld.service -> sysinit.target
Cycle-highlighted DOT file saved to: highlighted_color_cycles.dot
Damit kann ich nun die Systemd-Konfiguration der VM untersuchen, um die Schleife zu entfernen.
Den KI-Agent bat ich noch um eine Testdatei für den Fall, dass ich das Skript einmal ändern will. und legte es auf GitHub ab.
Posted 2026-10-25