Fehlerbehebung bei fehlgeschlagenen Systemd-Diensten: Ein praktischer Leitfaden für Sysadmins
Systemd-Dienste sind das Rückgrat moderner Linux-Systeme, können aber fehlschlagen. Dieser praktische Leitfaden befähigt Sysadmins, systematisch häufige Systemd-Dienstfehler zu beheben. Lernen Sie, `journalctl` effektiv für die Log-Analyse zu nutzen, Abhängigkeitsprobleme zu diagnostizieren, Exit-Codes zu interpretieren und spezifische Korrekturen für Webserver, Datenbanken und mehr anzuwenden, um die Dienstfunktionalität schnell wiederherzustellen.
Fehlerbehebung bei fehlgeschlagenen Systemd-Diensten: Ein praktischer Leitfaden für Sysadmins
Fehlgeschlagene Systemd-Dienste sind in der Regel weniger mysteriös, als sie auf den ersten Blick erscheinen. Die nützlichen Beweise befinden sich bereits auf der Maschine: die Unit-Definition, der genaue Befehl, den systemd auszuführen versuchte, der Exit-Status und die Journal-Zeilen rund um den Fehler. Der Trick besteht darin, sie in der richtigen Reihenfolge zu lesen, anstatt den Dienst zehnmal neu zu starten und zu hoffen, dass sich die Nachricht ändert.
Ich beginne normalerweise mit drei Fragen: Hat systemd die Unit gefunden, wurde der Prozess gestartet und hat die Anwendung selbst ihre Konfiguration oder Umgebung abgelehnt? Die folgenden Befehle halten diese Untersuchung fundiert.
Grundlegendes zu Systemd-Dienstfehlern
Wenn ein Systemd-Dienst nicht startet oder unerwartet abstürzt, liegt dies oft an einer Vielzahl von Gründen. Diese können von einfachen Konfigurationsfehlern, fehlenden Abhängigkeiten, Ressourcenbeschränkungen bis hin zu Fehlern im Dienst selbst reichen. Systemd bietet robuste Mechanismen, um Ihnen zu helfen, die genaue Ursache dieser Fehler zu ermitteln.
Häufige Ursachen für Dienstfehler:
- Konfigurationsfehler: Falsche Einstellungen in der
.service-Unit-Datei des Dienstes oder zugehörigen Konfigurationsdateien. - Fehlende Abhängigkeiten: Der Dienst ist auf andere Systemressourcen (wie Netzwerk, andere Dienste, bestimmte Dateisysteme) angewiesen, die nicht verfügbar sind oder noch nicht gestartet wurden.
- Ressourcenerschöpfung: Der Dienst benötigt mehr Speicher, CPU oder Festplatten-I/O, als das System bereitstellen kann.
- Berechtigungsprobleme: Dem Dienstprozess fehlen die erforderlichen Berechtigungen, um auf erforderliche Dateien, Verzeichnisse oder Netzwerkports zuzugreifen.
- Fehler im Dienst: Die Anwendung selbst hat einen Fehler, der während des Starts oder des Betriebs zu einem Absturz führt.
- Beschädigte Daten: Von dem Dienst verwendete wichtige Datendateien sind beschädigt.
- Netzwerkprobleme: Probleme mit Netzwerkschnittstellen, DNS oder Firewall-Regeln, die den Dienst daran hindern, sich an Ports zu binden oder zu kommunizieren.
Schritt 1: Überprüfen des Dienststatus
Der erste Schritt bei der Fehlerbehebung eines fehlgeschlagenen Dienstes besteht darin, seinen aktuellen Status zu überprüfen. Der systemd-Befehl systemctl ist Ihr primäres Werkzeug dafür.
Verwenden von systemctl status
Der Befehl systemctl status <dienstname>.service bietet eine präzise Übersicht über den aktuellen Zustand des Dienstes, aktuelle Logeinträge und Prozessinformationen.
sudo systemctl status nginx.service
Beispielausgabe (fehlgeschlagener Dienst):
● nginx.service - A high performance web server and reverse proxy
Loaded: loaded (/lib/systemd/system/nginx.service; enabled; vendor preset: enabled)
Active: failed (result=exit-code) since Tue 2023-10-27 10:30:00 UTC; 1min ago
Docs: man:nginx(8)
Process: 1234 ExecStart=/usr/sbin/nginx -g daemon on; master_process on; (code=exited, status=1/FAILURE)
Main PID: 1234 (code=exited, status=1/FAILURE)
Oct 27 10:30:00 your-server systemd[1]: Starting A high performance web server and reverse proxy...
Oct 27 10:30:00 your-server nginx[1234]: nginx: [emerg] bind() to port 80 failed (98: Address already in use)
Oct 27 10:30:00 your-server systemd[1]: nginx.service: Main process exited, code=exited, status=1/FAILURE
Oct 27 10:30:00 your-server systemd[1]: Failed to start A high performance web server and reverse proxy.
Wichtige Informationen, auf die Sie in der systemctl status-Ausgabe achten sollten:
Active:: Diese Zeile gibt den aktuellen Zustand an.failedist der Zustand, der uns interessiert. Es könnte auchfailed (result=exit-code)oderfailed (result=oom-kill)angezeigt werden. Dasresultliefert oft einen Hinweis.Process:: Details zu dem Prozess, den systemd auszuführen versuchte. Wenncode=exited, status=...angezeigt wird, ist dies entscheidend.- Logeinträge: Die aktuellsten Logzeilen enthalten oft die direkte Fehlermeldung des Dienstes.
Schritt 2: Analysieren von Logs mit journalctl
Der Befehl journalctl ist systemds leistungsstarkes Werkzeug zum Abfragen und Anzeigen von Logs aus dem systemd-Journal. Es ist unerlässlich, um detaillierte Einblicke in die Ursache eines Dienstfehlers zu erhalten.
Grundlegende journalctl-Verwendung für Dienste
Um Logs für einen bestimmten Dienst anzuzeigen, verwenden Sie das Flag -u:
sudo journalctl -u <dienstname>.service
Um Logs in Echtzeit zu verfolgen:
sudo journalctl -f -u <dienstname>.service
Um Logs vom letzten Bootvorgang anzuzeigen (nützlich für Dienste, die während des Starts fehlgeschlagen sind):
sudo journalctl -b -u <dienstname>.service
Um Logs seit einem bestimmten Zeitpunkt anzuzeigen:
sudo journalctl --since "2023-10-27 10:00:00" -u <dienstname>.service
Interpretieren der journalctl-Ausgabe
Achten Sie auf Fehlermeldungen, Stack-Traces oder spezifische Fehlercodes, die von der Anwendung oder systemd selbst gemeldet werden. Die Beispielausgabe von systemctl status zeigte bereits einen entscheidenden Fehler: bind() to port 80 failed (98: Address already in use). Dies weist eindeutig darauf hin, dass ein anderer Prozess bereits Port 80 verwendet und Nginx am Start hindert.
Tipp: Wenn der Dienst sehr ausführlich ist, können Sie die Ausgabe einschränken:
sudo journalctl -n 50 -u <dienstname>.service # Zeigt die letzten 50 Zeilen an
Schritt 3: Überprüfen von Dienstabhängigkeiten und -anforderungen
Systemd-Dienste sind oft von anderen Diensten oder Systemressourcen abhängig, die verfügbar sein müssen. Wenn eine Abhängigkeit nicht erfüllt ist, wird der Dienst nicht starten.
Anzeigen von Abhängigkeiten
Sie können die Abhängigkeiten eines Dienstes mit systemctl cat überprüfen und nach Direktiven wie Requires=, Wants=, After=, Before= und PartOf= suchen.
systemctl cat <dienstname>.service
Beispielsweise muss ein Dienst, der an eine bestimmte Adresse bindet, möglicherweise nach der Konfiguration des Netzwerks geordnet werden. After=network-online.target steuert nur die Reihenfolge; es zieht dieses Ziel nicht von selbst in die Transaktion. Wenn der Dienst es wirklich benötigt, sehen Sie oft beides:
Wants=network-online.target
After=network-online.target
Seien Sie konservativ mit Requires=. Es erzeugt eine stärkere Beziehung und kann Ihren Dienst stoppen, wenn die erforderliche Unit stoppt. Viele Anwendungsdienste benötigen nur Wants= plus After=.
Überprüfen auf fehlende Abhängigkeiten
Obwohl systemctl status oft auf Abhängigkeitsprobleme hinweist, kann es hilfreich sein, explizit zu überprüfen, ob erforderliche Dienste aktiv sind.
systemctl is-active <abhaengigkeitsdienstname>.service
Wenn ein erforderlicher Dienst maskiert oder gestoppt ist, kann dies das Starten Ihres Zieldienstes verhindern.
systemctl list-dependencies <dienstname>.service
Dieser Befehl zeigt den vollständigen Abhängigkeitsbaum.
Schritt 4: Verstehen von Exit-Codes
Wenn ein Dienst fehlschlägt, beendet er sich mit einem bestimmten Exit-Code. Dieser Code liefert wertvolle Informationen über die Art des Fehlers.
- Exit-Code 0: Erfolg.
- Exit-Code 1: Allgemeiner Fehler für viele Programme. Die spezifische Bedeutung hängt von der Anwendung ab.
- Exit-Code 127: Befehl nicht gefunden (oft aufgrund eines falschen
ExecStart-Pfads oder einer fehlenden ausführbaren Datei). - Exit-Code 137: Durch
SIGKILLbeendet. Dies hängt oft, aber nicht immer, mit Speicherdruck zusammen. - Exit-Code 139: Durch
SIGSEGV(Segmentation Fault) beendet.
Aus der systemctl status-Ausgabe haben wir status=1/FAILURE gesehen. Dies ist ein allgemeiner Fehler, und die vorausgehenden Logmeldungen sind entscheidend, um zu verstehen, warum es mit Status 1 fehlgeschlagen ist.
Identifizieren von OOM-Kills
Wenn systemctl status failed (result=oom-kill) anzeigt, bedeutet dies, dass der Linux Out-Of-Memory (OOM)-Killer den Prozess des Dienstes beendet hat, weil das System kritisch wenig Speicher hatte.
Um dies zu bestätigen, finden Sie oft zugehörige Meldungen in journalctl oder dmesg:
dmesg | grep -i oom
Fehlerbehebung bei OOM-Fehlern
- System-RAM erhöhen: Wenn möglich.
- Speichernutzung reduzieren: Optimieren Sie den Dienst oder andere laufende Prozesse.
- Swap konfigurieren: Stellen Sie sicher, dass ausreichend Swap-Speicherplatz verfügbar ist.
- Dienstspeicherlimits überprüfen: Eine
MemoryMax=-Einstellung kann einen dienstspezifischen OOM verursachen, selbst wenn der Host noch freien Speicher hat. - Aktuelle Bereitstellungen überprüfen: Speicherfehler folgen oft auf eine Konfigurationsänderung, eine Verkehrsänderung oder eine Versionsänderung.
Schritt 5: Überprüfen der Unit-Datei, die systemd tatsächlich verwendet
Gehen Sie nicht davon aus, dass die Datei in Ihrem Editor die vollständige Unit ist. Pakete, Drop-Ins und Überschreibungen können zur endgültigen Definition kombiniert werden:
systemctl cat <dienstname>.service
systemctl show <dienstname>.service -p FragmentPath -p DropInPaths
Dies fängt ein häufiges Problem ein: Jemand hat /usr/lib/systemd/system/app.service bearbeitet, während eine Überschreibung in /etc/systemd/system/app.service.d/override.conf immer noch Environment= oder ExecStart= ändert.
Nach dem Bearbeiten von Unit-Dateien oder Drop-Ins laden Sie systemd neu:
sudo systemctl daemon-reload
Wenn Sie diesen Schritt vergessen, verwendet systemctl restart möglicherweise weiterhin die alte Unit-Definition.
Schritt 6: Häufige dienstspezifische Probleme und Korrekturen
Während die obigen Schritte allgemein sind, haben bestimmte Dienste häufige Fehlermodi.
Webserver (Nginx, Apache)
- Port bereits belegt: Wie im Beispiel gesehen, könnte ein anderer Prozess auf Port 80 oder 443 lauschen. Verwenden Sie
sudo ss -tulnp | grep :80, um den störenden Prozess zu finden. - Konfigurationssyntaxfehler: Führen Sie den Konfigurationstest des Webservers aus (z. B.
sudo nginx -todersudo apachectl configtest). - Fehlende SSL-Zertifikate: Stellen Sie sicher, dass die Zertifikatsdateien vorhanden und lesbar sind.
Datenbanken (MySQL, PostgreSQL)
- Berechtigungen des Datenverzeichnisses: Stellen Sie sicher, dass der Datenbankbenutzer korrekte Lese-/Schreibrechte für sein Datenverzeichnis hat.
- Beschädigte Datendateien: Möglicherweise ist eine Wiederherstellung aus einem Backup oder die Verwendung datenbankspezifischer Wiederherstellungstools erforderlich.
- Festplattenspeicher voll: Datenbanken können erheblichen Festplattenspeicher verbrauchen.
Netzwerkdienste
- Falsche IP-Adressen oder Hostnamen: Überprüfen Sie die Netzwerkkonfiguration.
- Firewall-Regeln: Stellen Sie sicher, dass die erforderlichen Ports geöffnet sind.
- DNS-Auflösungsprobleme: Überprüfen Sie
/etc/resolv.confund die Netzwerkkonnektivität.
Schritt 7: Fortgeschrittene Techniken zur Fehlerbehebung
Erneutes Aktivieren und Neustarten des Dienstes
Laden Sie nach Änderungen ggf. die Units neu und starten Sie dann den Dienst neu. Sie müssen enable nicht jedes Mal ausführen, es sei denn, Sie ändern das Bootverhalten.
sudo systemctl daemon-reload # Lädt die systemd-Manager-Konfiguration neu
sudo systemctl restart <dienstname>.service
Verwenden von systemctl --failed
Dieser Befehl listet alle Units auf, die sich derzeit in einem fehlgeschlagenen Zustand befinden.
systemctl --failed
Überprüfen von Ressourcenlimits (ulimit)
Einige Dienste schlagen möglicherweise fehl, wenn sie Betriebssystem-Ressourcenlimits erreichen. Überprüfen Sie die Limits mit ulimit -a als Benutzer, unter dem der Dienst läuft, oder überprüfen Sie die eigenen Ressourcenkontrollrichtlinien von systemd in der Unit-Datei.
Für systemd-verwaltete Dienste sind Unit-Eigenschaften oft relevanter als das ulimit einer interaktiven Shell:
systemctl show <dienstname>.service -p LimitNOFILE -p User -p Group -p MemoryMax -p TasksMax
Wenn eine Anwendung too many open files meldet, vergleichen Sie LimitNOFILE mit der Verbindungsanzahl und Dateinutzung der Anwendung. Wenn ein Dienst keine Threads oder Kindprozesse erstellen kann, überprüfen Sie TasksMax.
Debugging-Flags
Viele Anwendungen haben Debug-Modi oder ausführliche Protokollierung, die über Befehlszeilenargumente in der ExecStart-Zeile der .service-Datei aktiviert werden können. Konsultieren Sie die Dokumentation der Anwendung.
Ein kurzes Beispiel: Dienst funktioniert manuell, schlägt beim Booten fehl
Dies ist eine der häufigsten systemd-Beschwerden. Ein Entwickler führt den Befehl von Hand aus und es funktioniert. Der gleiche Befehl schlägt als Dienst fehl. Der übliche Unterschied ist die Umgebung.
Überprüfen Sie den Dienstbenutzer und das Arbeitsverzeichnis:
systemctl show myapp.service -p User -p Group -p WorkingDirectory
systemctl cat myapp.service
Suchen Sie dann nach Annahmen in der App: relative Pfade, Dateien in einem Home-Verzeichnis, Umgebungsvariablen aus .bashrc oder Anmeldeinformationen, die von einer interaktiven Shell geladen werden. systemd liest Ihre Shell-Startdateien nicht für einen Dienst. Wenn die App APP_ENV=production oder DATABASE_URL=... benötigt, legen Sie diese Konfiguration in der Unit mit Environment=, einer EnvironmentFile= oder Ihrem normalen Secret-Management-Pfad ab.
Boot-only-Fehler können auch Reihenfolgeprobleme sein. Ein Dienst kann starten, bevor DNS, die Netzwerkadresse oder ein eingehängtes Dateisystem bereit ist. Beheben Sie das nicht mit einem blinden Sleep in der Anwendung. Drücken Sie die Abhängigkeit in der Unit aus:
Wants=network-online.target
After=network-online.target
RequiresMountsFor=/srv/myapp
RequiresMountsFor= ist nützlich, wenn der Dienst einen bestimmten Pfad benötigt, insbesondere wenn dieser Pfad von einer separaten Festplatte oder einem Netzwerkmount stammt. Es ist klarer, als zu hoffen, dass ein breites Ziel zufällig zuerst fertig wird.
Zurücksetzen des Fehlerzustands
Nachdem ein Dienst fehlgeschlagen ist, merkt sich systemd den Fehlerzustand, bis er zurückgesetzt wird oder die Unit erfolgreich ist. Das ist hilfreich für die Sichtbarkeit, kann aber Statusüberprüfungen verwirren, nachdem Sie das Problem bereits behoben haben:
sudo systemctl reset-failed myapp.service
sudo systemctl restart myapp.service
systemctl status myapp.service
Verwenden Sie reset-failed, nachdem Sie die benötigten Beweise gesichert haben. Während eines Vorfalls sind der Fehlerzustand und die Journal-Zeitstempel nützliche Hinweise.
Eine weitere kleine Gewohnheit hilft nach lauten Fehlern: Überprüfen Sie, ob die Unit in einer Neustartschleife steckt, bevor Sie etwas bearbeiten.
systemctl show myapp.service -p NRestarts -p RestartUSec
Wenn die Neustartanzahl schnell steigt, stoppen Sie die Unit, während Sie untersuchen. Das schützt Abhängigkeiten vor wiederholten fehlerhaften Verbindungen und hält das Journal lesbar.
Das zuverlässige Muster ist: Lesen Sie status, lesen Sie das Journal, überprüfen Sie die effektive Unit mit systemctl cat, überprüfen Sie Abhängigkeiten und Pfade, und starten Sie dann erst neu, nachdem Sie wissen, was sich geändert hat. Das hält die systemd-Fehlerbehebung langweilig, was genau das ist, was Sie während eines Ausfalls wollen.