Fehlerbehebung bei häufigen Systemd-Dienstfehlern effektiv
Diagnostizieren Sie häufige Systemd-Dienstfehler mit systemctl, journalctl, Exit-Codes, Unit-Prüfungen und praktischen Reparaturschritten.
Fehlerbehebung bei häufigen Systemd-Dienstfehlern effektiv
Die meisten Systemd-Dienstfehler sind nicht mysteriös, sobald Sie drei Fragen trennen: Hat systemd die Unit-Datei gelesen, konnte es den Befehl ausführen und blieb die Anwendung nach dem Start gesund? Dies sind unterschiedliche Fehlerpunkte, die unterschiedliche Hinweise hinterlassen.
Der Fehler, den ich am häufigsten sehe, ist, direkt in die Bearbeitung der Unit-Datei einzusteigen. Lesen Sie zuerst den Status und die Logs. Ein fehlgeschlagener Dienst sagt Ihnen normalerweise, ob er eine fehlende ausführbare Datei, einen falschen Benutzer, ein Berechtigungsproblem, ein Abhängigkeits-Reihenfolgeproblem oder einen Anwendungsabsturz getroffen hat. Der genaue Wortlaut ist wichtig.
Das wesentliche Diagnose-Toolkit
Eine effektive Fehlerbehebung stützt sich auf zwei primäre Systemd-Werkzeuge, die sofortiges Feedback zum Dienststatus und zu Betriebslogs bieten.
1. Überprüfen des Dienststatus
Der Befehl systemctl status bietet eine sofortige Momentaufnahme des Zustands der Unit, einschließlich ihres aktuellen Status, aktueller Logs und wichtiger Metadaten wie der Prozess-ID (PID) und des Exit-Codes.
$ systemctl status myapp.service
Wichtige Informationen, auf die Sie achten sollten:
Load:Bestätigt, dass die Unit-Datei korrekt gelesen wurde.loadedist gut. Wennnot foundangezeigt wird, befindet sich Ihre Dienstdatei am falschen Ort oder ist falsch geschrieben.Active:Dies ist der Kernstatus. Wennfailedangezeigt wird, hat der Dienst versucht zu starten und wurde unerwartet beendet.Exit Code:Dieser numerische Code, der oft zusammen mitActive: failedangezeigt wird, ist entscheidend. Er gibt an, warum der Prozess beendet wurde (z. B. 0 für sauberes Beenden, 1 oder 2 für allgemeine Anwendungsfehler, 203 für Ausführungspfadfehler).- Letzte Logs: Systemd fügt oft die letzten Zeilen der Logausgabe des Dienstes bei, die den Fehler sofort offenbaren können.
2. Tiefer Eintauchen in Logs mit Journalctl
Während systemctl status eine Zusammenfassung liefert, bietet journalctl den vollständigen Kontext der Ausführungshistorie des Dienstes, einschließlich der Standardausgabe- und Standardfehlerdatenströme.
Verwenden Sie den folgenden Befehl, um das Journal speziell für Ihren fehlschlagenden Dienst anzuzeigen, mit dem Flag -x für Erklärungen und dem Flag -e, um zum Ende (den neuesten Einträgen) zu springen:
$ journalctl -xeu myapp.service
Tipp: Wenn der Fehler vor Stunden oder Tagen aufgetreten ist, verwenden Sie die Zeitfilteroptionen, wie z. B.
journalctl -u myapp.service --since "2 hours ago".
Schritt-für-Schritt-Diagnose häufiger Fehler
Systemd-Fehler fallen typischerweise in einige vorhersagbare Kategorien. Durch die Untersuchung des Status und der Logs können Sie das Problem schnell kategorisieren und die entsprechende Lösung anwenden.
Fehlertyp 1: Ausführungsfehler (Exit-Code 203)
Ein Exit-Code von 203/EXEC bedeutet, dass systemd die in der ExecStart-Direktive angegebene Datei nicht ausführen konnte. Dies ist einer der häufigsten Konfigurationsfehler.
Ursachen und Lösungen:
Falscher Pfad: Der Pfad zur ausführbaren Datei ist falsch oder nicht absolut.
- Lösung: Verwenden Sie immer den vollständigen, absoluten Pfad in
ExecStart. Stellen Sie sicher, dass die ausführbare Datei an genau diesem Ort existiert.
# FALSCH ExecStart=myapp # RICHTIG ExecStart=/usr/local/bin/myapp- Lösung: Verwenden Sie immer den vollständigen, absoluten Pfad in
Fehlende Berechtigungen: Die Datei hat keine Ausführungsberechtigung für den Benutzer, der den Dienst ausführt.
- Lösung: Überprüfen und setzen Sie Ausführungsberechtigungen:
chmod +x /pfad/zur/ausfuehrbaren/datei.
- Lösung: Überprüfen und setzen Sie Ausführungsberechtigungen:
Fehlender Interpreter (Shebang): Wenn
ExecStartauf ein Skript verweist (z. B. Python oder Bash), könnte die Shebang-Zeile (#!/usr/bin/env python) fehlen oder falsch sein, was die Ausführung verhindert.- Lösung: Überprüfen Sie, ob das Skript eine gültige Shebang-Zeile hat.
Fehlertyp 2: Anwendungsabstürze (Exit-Code 1 oder 2)
Wenn der Dienst erfolgreich startet (systemd findet die ausführbare Datei), aber dann sofort in den failed-Zustand mit einem allgemeinen Anwendungsfehlercode (normalerweise 1 oder 2) übergeht, liegt das Problem innerhalb der Anwendungslogik oder -umgebung.
Ursachen und Lösungen:
Konfigurationsdateifehler: Die Anwendung konnte ihre erforderliche Konfigurationsdatei nicht lesen, oder die Datei enthält ungültige Syntax.
- Lösung: Überprüfen Sie die
journalctl-Ausgabe sorgfältig. Die Anwendung gibt normalerweise eine spezifische Fehlermeldung zum Konfigurationsdateipfad oder zur Syntax aus. Verwenden Sie dieWorkingDirectory=-Direktive, wenn Konfigurationsdateien relativ sind.
- Lösung: Überprüfen Sie die
Ressourcenkonflikt/Zugriffsverweigerung: Die Anwendung konnte aufgrund von Berechtigungsbeschränkungen keinen erforderlichen Port öffnen, auf eine Datenbank zugreifen oder in eine Logdatei schreiben.
- Lösung: Überprüfen Sie die
User=-Direktive in der Dienstdatei und stellen Sie sicher, dass dieser Benutzer Lese-/Schreibzugriff auf alle erforderlichen Ressourcen und Verzeichnisse hat.
- Lösung: Überprüfen Sie die
Fehlertyp 3: Abhängigkeitsfehler
Der Dienst könnte fehlschlagen, weil er startet, bevor eine erforderliche Abhängigkeit bereit ist, wie z. B. eine Datenbank, Netzwerkschnittstelle oder ein eingehängtes Dateisystem.
Ursachen und Lösungen:
Netzwerk nicht bereit: Dienste, die Netzwerkkonnektivität benötigen (z. B. Webserver, Proxys), schlagen oft fehl, wenn sie starten, bevor der Netzwerkstack initialisiert ist.
- Lösung: Wenn der Dienst beim Start eine Adresse oder Route benötigt, fügen Sie die
network-online.target-Ordnung hinzu und stellen Sie sicher, dass der Wait-online-Dienst Ihrer Distribution für Ihren Netzwerkmanager aktiviert ist:
[Unit] Description=Mein Webdienst After=network-online.target Wants=network-online.target- Lösung: Wenn der Dienst beim Start eine Adresse oder Route benötigt, fügen Sie die
Dateisystem nicht eingehängt: Der Dienst versucht, auf Dateien auf einem Volume zuzugreifen, das noch nicht eingehängt wurde (besonders kritisch für sekundäre Speicher oder Netzwerkmounts).
- Lösung: Verwenden Sie
RequiresMountsFor=, um systemd explizit mitzuteilen, welcher Pfad vor dem Start verfügbar sein muss.
[Unit] RequiresMountsFor=/mnt/data/storage- Lösung: Verwenden Sie
Fehlertyp 4: Benutzer- und Umgebungsprobleme (Exit-Code 217)
Exit-Code 217/USER deutet oft auf einen Fehler im Zusammenhang mit Benutzer- oder Gruppendirektiven oder nicht verfügbaren Umgebungsvariablen hin.
Ursachen und Lösungen:
Ungültiger Benutzer/Gruppe: Der in der
User=- oderGroup=-Direktive angegebene Benutzer existiert auf dem System nicht.- Lösung: Überprüfen Sie, ob der Benutzername über
id <benutzername>existiert.
- Lösung: Überprüfen Sie, ob der Benutzername über
Fehlende Umgebungsvariablen: Systemd-Dienste laufen in einer sauberen Umgebung, was bedeutet, dass Shell-Variablen (wie
PATHoder benutzerdefinierte API-Schlüssel) nicht vererbt werden.- Lösung: Definieren Sie notwendige Variablen direkt in der Dienstdatei oder über eine Umgebungsdatei.
[Service] # Direkte Definition Environment="API_KEY=ABCDEFG" # Verwendung einer externen Datei (z. B. /etc/sysconfig/myapp) EnvironmentFile=/etc/sysconfig/myapp
Fehlerbehebungsworkflow und Best Practices
Wenn Sie eine Dienstdatei ändern, befolgen Sie immer diesen Dreischritt-Zyklus, um sicherzustellen, dass Ihre Änderungen übernommen und korrekt getestet werden.
1. Validieren der Konfigurationssyntax
Verwenden Sie systemd-analyze verify, um die Dienst-Unit-Datei zu überprüfen, bevor Sie versuchen, sie zu starten. Dies fängt einfache Syntaxfehler ab.
$ systemd-analyze verify /etc/systemd/system/myapp.service
2. Neuladen des Daemons
Systemd speichert Konfigurationsdateien zwischen. Nach jeder Änderung an einer Unit-Datei müssen Sie systemd anweisen, seine Konfiguration neu zu laden.
$ systemctl daemon-reload
3. Neustarten und Status überprüfen
Versuchen Sie, den Dienst neu zu starten, und überprüfen Sie sofort seinen Status und seine Logs.
$ systemctl restart myapp.service
$ systemctl status myapp.service
Umgang mit sofortigen Neustarts und Timeouts
Wenn Ihr Dienst in eine restarting-Schleife gerät oder sofort ohne offensichtliche Logmeldung fehlschlägt, sollten Sie in Erwägung ziehen, diese Direktiven im Abschnitt [Service] anzupassen:
| Direktive | Zweck | Best Practice |
|---|---|---|
Type= |
Wie systemd den Prozess verwaltet (z. B. simple, forking). |
Verwenden Sie simple, es sei denn, die Anwendung daemonisiert sich explizit. |
TimeoutStartSec= |
Wie lange systemd darauf wartet, dass der Hauptprozess Erfolg signalisiert. | Erhöhen Sie diesen Wert, wenn die Anwendung eine lange Startzeit hat (z. B. große Datenbankinitialisierung). |
Restart= |
Definiert, wann der Dienst automatisch neu gestartet werden soll (z. B. always, on-failure). |
Verwenden Sie on-failure für Produktionsanwendungen, um endlose Neustartschleifen bei wiederholten Konfigurationsfehlern zu vermeiden. |
Fehlerzustände genauer lesen
failed ist nicht der einzige schlechte Zustand. Eine Unit kann nach einem sauberen Beenden inactive (dead) sein, was für Type=oneshot-Jobs normal ist, aber verdächtig für einen Daemon, von dem Sie erwartet haben, dass er weiterläuft. Eine Unit kann activating sein, bis TimeoutStartSec= abläuft. Eine Unit kann active (exited) sein, wenn der Befehl beendet wurde und systemd dies für akzeptabel hält. Bevor Sie die Neustartrichtlinie ändern, stellen Sie sicher, dass der Diensttyp zum Programm passt.
Für einen normalen Vordergrundprozess beginnen Sie mit:
[Service]
Type=simple
ExecStart=/usr/local/bin/myapp
Für ein Skript, das einmal läuft und beendet wird:
[Service]
Type=oneshot
ExecStart=/usr/local/sbin/rotate-reports
Für ältere Daemons, die sich selbst in den Hintergrund forken, kann Type=forking erforderlich sein, aber verwenden Sie es nicht aus Gewohnheit. Viele moderne Anwendungen bleiben bereits im Vordergrund, wenn sie unter systemd ausgeführt werden. Wenn Sie systemd mitteilen, dass es forken erwartet, und der Prozess nicht so forkt, wie systemd es erwartet, können Sie irreführende Startfehler erhalten.
Eine Triage-Checkliste, die unter Druck funktioniert
Wenn ein Dienst ausgefallen ist und Leute warten, verwenden Sie eine feste Sequenz:
systemctl status myapp.service --no-pager
journalctl -u myapp.service -b --no-pager
systemctl cat myapp.service
systemctl show myapp.service -p FragmentPath -p User -p Group -p WorkingDirectory -p ExecStart
Suchen Sie nach dem ersten echten Fehler, nicht nach der letzten Zeile. Der letzte Journaleintrag sagt möglicherweise nur, dass systemd die Unit als fehlgeschlagen markiert hat. Die nützliche Zeile befindet sich oft darüber: Permission denied, No such file or directory, Address already in use, Failed at step USER oder eine anwendungsspezifische Ausnahme.
Wenn der Dienst kürzlich bearbeitet wurde, überprüfen Sie die Syntax und den Neuladestatus:
sudo systemd-analyze verify /etc/systemd/system/myapp.service
sudo systemctl daemon-reload
Wenn systemctl status sagt, dass sich die Unit-Datei auf der Festplatte geändert hat, warnt systemd Sie, dass der Manager die neue Definition nicht neu geladen hat. Ein Neustart des Dienstes vor daemon-reload könnte weiterhin veraltete Einstellungen verwenden.
Berechtigungsprobleme, die nicht wie Berechtigungsprobleme aussehen
Ein Dienst kann von Ihrer Shell aus perfekt laufen und unter systemd fehlschlagen, weil er nicht als Sie läuft. Überprüfen Sie User=, Group=, WorkingDirectory= und alle Härtungsoptionen wie ProtectSystem=, ReadWritePaths=, PrivateTmp= oder NoNewPrivileges=.
Zum Beispiel:
[Service]
User=webapp
WorkingDirectory=/srv/webapp
ExecStart=/srv/webapp/bin/server
ReadWritePaths=/srv/webapp/var
ProtectSystem=strict
Mit ProtectSystem=strict ist der größte Teil des Dateisystems für den Dienst schreibgeschützt. Das ist eine gute Härtungseinstellung, bedeutet aber, dass die Anwendung nur in Pfade schreiben darf, die Sie explizit erlauben. Wenn das Journal sagt, dass die App keine PID-Datei, Cache-Datei, SQLite-Datenbank oder Upload-Verzeichnis erstellen kann, könnte die Sandboxing der Unit der Grund sein.
Überprüfen Sie auch die Berechtigungen der übergeordneten Verzeichnisse. Die ausführbare Datei kann Modus 755 haben, aber wenn /srv/webapp für den Dienstbenutzer nicht durchsuchbar ist, wird systemd sie trotzdem nicht ausführen können. Verwenden Sie:
namei -l /srv/webapp/bin/server
sudo -u webapp /srv/webapp/bin/server --check-config
Das Ausführen einer sicheren Konfigurationsprüfung als Dienstbenutzer fängt viele Probleme ab, ohne den vollständigen Daemon zu starten.
Neustartschleifen und Ratenbegrenzungen
Restart=on-failure ist nützlich, kann aber den ursprünglichen Fehler in einer Flut von wiederholten Starts verbergen. Systemd wendet auch eine Startratenbegrenzung an. Wenn ein Dienst zu oft in einem kurzen Zeitfenster fehlschlägt, sehen Sie möglicherweise start-limit-hit.
Nützliche Befehle:
systemctl status myapp.service
systemctl reset-failed myapp.service
sudo systemctl start myapp.service
reset-failed behebt nicht die Ursache. Es löscht nur den fehlgeschlagenen Zustand von systemd und den Ratenbegrenzungsspeicher, damit Sie nach einer Änderung erneut testen können. Wenn Sie es weiterhin benötigen, verlangsamen Sie das Tempo und beheben Sie den ersten Fehler im Journal.
Debuggen von anhaltenden Problemen
Wenn Standardlogs das Problem nicht offenbaren, leitet die Anwendung möglicherweise ihre Ausgabe um.
- Überprüfen Sie
StandardOutputundStandardError: Standardmäßig werden diese an das Journal weitergeleitet. Wenn sie auf/dev/nulloder eine Datei gesetzt sind, müssen Sie diese Orte direkt auf Fehlermeldungen überprüfen. - Temporäre Ausführlichkeit: Wenn möglich, konfigurieren Sie die Anwendung (oder ihre Befehlszeilenargumente in
ExecStart) vorübergehend so, dass sie mit maximaler Ausführlichkeit läuft (z. B.--debugoder-v), um bei Fehlern detailliertere Logausgaben zu erzeugen.
Ein vernünftiger Haltepunkt
Sobald der Dienst startet, überprüfen Sie noch eines: ob er tatsächlich Arbeit verrichtet. systemctl status kann Ihnen nur den Prozesszustand aus Sicht von systemd mitteilen. Ein Webdienst kann aktiv sein, während er 500er zurückgibt. Ein Worker kann aktiv sein, während er jeden Job fehlschlagen lässt. Nach der Behebung des Problems auf Unit-Ebene führen Sie die eigene Gesundheitsprüfung der Anwendung durch, sehen Sie sich ihre Anwendungslogs an und bestätigen Sie, dass die Abhängigkeit, mit der sie spricht, erreichbar ist.
Für die meisten Vorfälle ist der nützliche Pfad kurz: systemctl status, dann journalctl -u, dann die Unit mit systemctl cat inspizieren, dann den Befehl als konfigurierten Dienstbenutzer testen. Das hält Sie nahe an den Beweisen und fern von zufälligen Unit-Datei-Änderungen.
Notieren Sie die endgültige Ursache im Runbook oder in den Bereitstellungsnotizen des Dienstes, solange sie noch frisch ist. "Systemd repariert" ist später nicht nützlich. "Dienst fehlgeschlagen mit 203/EXEC, weil die Bereitstellung /opt/app/current/bin/server ohne Ausführungsberechtigung erstellt hat" ist nützlich. Der nächste Vorfall wird sich normalerweise wie der letzte reimen.