systemd Targets, Sockets und Timer im Detail
AI generated
$
/etc
Linux · systemd · Init-System
systemd Targets, Sockets und Timer im Detail
Unit-Typen jenseits von .service

Wer systemd nur über systemctl start und systemctl status kennt, sieht nur einen Bruchteil des Init-Systems. Target-Units strukturieren den Bootvorgang als gerichteten Graph, Socket-Units starten Dienste erst bei der ersten Verbindung, und beide Konzepte spielen zusammen mit Timer-Units, um Ressourcen zu sparen und Abhängigkeiten sauber abzubilden.

15 Min. Lesezeit Targets · Sockets · Timer · Unit-Dependencies systemd 245+ · Debian · Ubuntu · RHEL

1. Warum Targets und Sockets mehr sind als Kalender-Jobs

Die meisten Einsteiger begegnen systemd zunächst über Service-Units: systemctl start nginx, systemctl enable php8.4-fpm. Doch die Unit-Typen von systemd gehen weit über einfache Dienste hinaus, und gerade Target-Units und Socket-Units lösen strukturelle Probleme, die klassische Init-Systeme mit sequenziellen Runlevel-Skripten nie sauber gelöst haben. Ein Target ist kein Skript, sondern ein reiner Synchronisationspunkt im Abhängigkeitsgraph, ein Socket ist keine Alternative zu einem Service, sondern ein vorgeschalteter Aktivierungsmechanismus.

Wer nur Timer-Units kennt und Cron-Jobs damit ersetzt, verpasst den größeren Zusammenhang: systemd modelliert das gesamte System als Graph von Units mit expliziten Abhängigkeiten, und Targets sowie Sockets sind die Knotenpunkte, die diesen Graph erst robust und parallelisierbar machen. Dieser Artikel konzentriert sich bewusst auf Targets und Sockets als eigenständige Unit-Typen und betrachtet Timer nur dort, wo sie in denselben Abhängigkeitsgraph eingebettet sind.

2. Unit-Datei-Anatomie: Sections und Unit-Typen im Überblick

Jede systemd-Unit-Datei folgt demselben Grundschema aus benannten Sections in eckigen Klammern. Die Section [Unit] beschreibt Metadaten und Abhängigkeiten wie Description=, After=, Requires= und Wants=, unabhängig vom konkreten Unit-Typ. Die typspezifische Section, also [Service], [Socket], [Timer] oder [Mount], enthält die eigentliche Konfiguration. Die Section [Install] definiert schließlich, wie und wo die Unit beim Aktivieren mit systemctl enable in den Abhängigkeitsbaum eingehängt wird, typischerweise über WantedBy=.

Neben den bekannten .service-Units gibt es unter anderem .target für Synchronisationspunkte, .socket für Kommunikationsendpunkte, .timer für zeitgesteuerte Aktivierung, .mount und .automount für Dateisysteme, sowie .path für Aktivierung basierend auf Dateisystemänderungen. Jeder dieser Typen kann eigene Abhängigkeiten definieren, und systemd löst diese Abhängigkeiten beim Systemstart als parallelen Graph auf, statt wie klassische Init-Skripte streng sequenziell vorzugehen.


# /etc/systemd/system/example.service — anatomy of a unit file
[Unit]
Description=Example application service
# Ordering and dependency directives, type independent
After=network-online.target
Wants=network-online.target
Requires=example.socket

[Service]
# Type specific section — differs for .service, .socket, .timer, ...
Type=notify
ExecStart=/usr/bin/example-daemon --config /etc/example/config.yaml
Restart=on-failure
RestartSec=5

[Install]
# Determines where this unit attaches when enabled
WantedBy=multi-user.target

3. Targets verstehen: Synchronisationspunkte statt Runlevel

Ein Target ist eine Unit ohne eigene ausführbare Logik. Sie besitzt keine [Service]- oder [Socket]-Section, sondern dient ausschließlich als Bündelungspunkt für andere Units. multi-user.target etwa fasst alle Units zusammen, die für einen Mehrbenutzer-Systemzustand ohne grafische Oberfläche nötig sind. graphical.target baut darauf auf und fügt den Display-Manager hinzu. Diese Struktur ersetzt die alten SysV-Runlevel 0 bis 6 durch benannte, semantisch verständliche Ziele, die zusätzlich beliebig erweiterbar sind.

Der entscheidende Unterschied zu Runlevels liegt in der Parallelität: Ein Runlevel-Wechsel arbeitete Skripte in numerischer Reihenfolge strikt nacheinander ab. Ein Target dagegen definiert nur, welche Units erreicht sein müssen, bevor das Target selbst als aktiv gilt, und systemd startet alle unabhängigen Units innerhalb dieses Ziels parallel. Das verkürzt Bootzeiten erheblich, weil zum Beispiel Netzwerk-Setup und Festplatten-Mounts, die keine Abhängigkeit zueinander haben, gleichzeitig ablaufen, statt aufeinander zu warten.

4. Eigene Targets erstellen und mit isolate wechseln

Eigene Targets sind sinnvoll, wenn man eine Gruppe zusammengehöriger Dienste als benannte Einheit ansprechen möchte, etwa alle Komponenten einer Anwendung. Eine eigene Target-Unit-Datei benötigt meist nur die [Unit]-Section mit einer Beschreibung und optional Requires= für zwingende Abhängigkeiten. Mit systemctl isolate mein-stack.target stoppt systemd alle Units, die nicht Teil des Abhängigkeitsbaums dieses Targets sind, und startet gezielt nur die dort definierten Units, ganz ähnlich einem klassischen Runlevel-Wechsel, aber mit expliziten, nachvollziehbaren Abhängigkeiten statt nummerierter Skripte.

Ein praktisches Beispiel: Ein eigenes magento-stack.target könnte php8.4-fpm.service, nginx.service, redis-server.service und mysql.service bündeln. Ein einzelner Befehl systemctl status magento-stack.target zeigt dann sofort, ob der gesamte Stack als erreicht gilt, statt vier einzelne Status-Abfragen ausführen zu müssen. Das PartOf=-Directive in den einzelnen Service-Units sorgt zusätzlich dafür, dass ein Neustart des Targets auch die zugehörigen Services neu startet.


# /etc/systemd/system/magento-stack.target — custom grouping target
[Unit]
Description=Magento application stack (web, cache, database)
Requires=php8.4-fpm.service nginx.service redis-server.service mysql.service
After=php8.4-fpm.service nginx.service redis-server.service mysql.service

[Install]
WantedBy=multi-user.target

5. Sockets verstehen: das Prinzip der Socket-Aktivierung

Eine Socket-Unit definiert einen Kommunikationsendpunkt, etwa einen TCP-Port, einen UNIX-Socket-Pfad oder eine FIFO, den systemd selbst öffnet und überwacht, noch bevor der zugehörige Dienst überhaupt läuft. Trifft eine Verbindung an diesem Endpunkt ein, startet systemd den passenden Service just in time und reicht die bereits geöffnete Verbindung an ihn weiter. Dieses Prinzip heißt Socket-Aktivierung und stammt konzeptionell aus inetd, wurde in systemd aber deutlich robuster und performanter umgesetzt.

Der Vorteil liegt in zwei Bereichen: Erstens starten Dienste erst bei tatsächlichem Bedarf, was Ressourcen spart, besonders bei selten genutzten Diensten. Zweitens entkoppelt Socket-Aktivierung Boot-Reihenfolge von Dienstverfügbarkeit, denn der Socket existiert bereits, sobald systemd ihn erstellt hat, unabhängig davon, ob der eigentliche Dienst schon gestartet ist. Verbindende Clients müssen also nicht mehr warten, bis der Dienst vollständig hochgefahren ist, sie werden lediglich kurz gepuffert, während systemd den Prozess im Hintergrund startet.

6. Eine eigene Socket-Unit für einen Dienst schreiben

Eine minimale Socket-Unit besteht aus einer [Socket]-Section mit einer Endpunkt-Direktive, etwa ListenStream= für TCP oder ListenStream=/run/mein-dienst.sock für einen UNIX-Socket. Die zugehörige Service-Unit trägt denselben Basisnamen, damit systemd die Kopplung automatisch erkennt, etwa mein-dienst.socket und mein-dienst.service. Wichtig ist, dass die Service-Unit selbst keinen ListenStream mehr definiert, das übernimmt vollständig die Socket-Unit.

In der Praxis nutzt man dieses Muster zum Beispiel für einen internen Health-Check-Dienst, der die meiste Zeit über inaktiv bleiben soll. Statt eines dauerhaft laufenden Prozesses, der Arbeitsspeicher belegt, lauscht nur der von systemd selbst verwaltete Socket, und der eigentliche Prozess wird nur bei tatsächlichem Zugriff gestartet und kann sich nach einer konfigurierbaren Leerlaufzeit wieder beenden, ohne den Port freizugeben.


# /etc/systemd/system/healthcheck.socket
[Unit]
Description=Socket for the on-demand health check service

[Socket]
ListenStream=127.0.0.1:9100
Accept=no

[Install]
WantedBy=sockets.target

# /etc/systemd/system/healthcheck.service — no ListenStream here
[Unit]
Description=On-demand health check responder
Requires=healthcheck.socket

[Service]
# systemd passes the already-open socket via file descriptor 3
ExecStart=/usr/local/bin/healthcheck-responder
StandardInput=socket

7. Accept=yes vs. Accept=no und Performance-Implikationen

Die Direktive Accept= in der [Socket]-Section entscheidet über ein grundlegendes Verhalten mit spürbaren Performance-Auswirkungen. Bei Accept=no, dem Standard und der empfohlenen Einstellung für die meisten Anwendungsfälle, startet systemd genau einen Prozess der zugehörigen Service-Unit, der den Socket selbst über accept() bedient und beliebig viele Verbindungen intern verarbeitet, ganz so, wie es moderne Server wie nginx oder PHP-FPM ohnehin selbst tun. Diese Variante ist effizient, weil kein zusätzlicher Prozess-Fork pro Verbindung nötig ist.

Bei Accept=yes hingegen startet systemd für jede einzelne eingehende Verbindung eine eigene Instanz der Service-Unit, vergleichbar mit dem klassischen inetd-Modell. Das eignet sich für einfache, kurzlebige Dienste, etwa ein simples Diagnose-Skript, verursacht aber bei hoher Verbindungsrate erheblichen Overhead durch wiederholtes Forken und Instanziieren. Für produktive Webanwendungen und Datenbankdienste ist Accept=no praktisch immer die richtige Wahl, Accept=yes bleibt Nischenfällen mit geringer, unregelmäßiger Last vorbehalten.

8. Zusammenspiel: Targets, Sockets und Timer im Boot-Graph

Targets, Sockets und Timer sind keine isolierten Konzepte, sondern Knoten im selben Abhängigkeitsgraph. sockets.target bündelt sämtliche Socket-Units und wird typischerweise vor basic.target erreicht, wodurch sichergestellt ist, dass alle Kommunikationsendpunkte existieren, bevor reguläre Dienste starten. timers.target bündelt analog alle Timer-Units. Ein eigenes Target kann gezielt sowohl Socket- als auch Timer-Units über Wants= referenzieren, um einen vollständigen funktionalen Bereich abzubilden, etwa alle Hintergrundaufgaben einer Anwendung inklusive ihrer periodischen Wartungsjobs.

Ein Timer selbst besitzt ebenfalls eine [Unit]-Section und kann über After= und Requires= von einem bestimmten Target abhängen, etwa um sicherzustellen, dass ein Wartungs-Timer erst nach magento-stack.target aktiv wird, statt schon während der frühen Bootphase. Diese Kombination aus Targets als Synchronisationspunkten, Sockets als bedarfsgesteuerten Einstiegspunkten und Timern als zeitgesteuerten Auslösern ergibt einen deklarativen, robusten Abhängigkeitsgraph, der klassischen Init-Skripten in Nachvollziehbarkeit und Parallelisierbarkeit klar überlegen ist.


# Visualize how a custom target ties services, sockets and timers together
systemctl list-dependencies magento-stack.target

# Show which units belong to sockets.target
systemctl list-dependencies sockets.target

# Confirm a timer is ordered after the application stack target
systemctl show maintenance.timer -p After -p Requires

9. Debugging mit systemd-analyze und Vergleichstabelle

Das Werkzeug systemd-analyze blame zeigt, welche Units beim Boot am meisten Zeit beansprucht haben, während systemd-analyze critical-chain die längste Abhängigkeitskette bis zum Erreichen eines Targets visualisiert, was besonders hilfreich ist, um unnötige serielle Abhängigkeiten zwischen Targets zu identifizieren. Für Sockets liefert systemctl list-sockets eine Übersicht aller aktiven Endpunkte samt zugehöriger Service-Unit, und ss -lp ergänzt das um die Betriebssystemsicht auf tatsächlich lauschende Sockets.

Unit-Typ Zweck Auslöser Typische Section
.service Prozess starten und überwachen manuell, Abhängigkeit, Socket, Timer [Service]
.target Synchronisationspunkt bündeln Erreichen der Abhängigkeiten nur [Unit] und [Install]
.socket Endpunkt vorab öffnen eingehende Verbindung [Socket]
.timer zeitgesteuerte Aktivierung Kalenderzeit oder Bootabstand [Timer]
.path dateisystembasierte Aktivierung Datei erscheint oder ändert sich [Path]

Diese Übersicht zeigt, dass Targets, Sockets und Timer jeweils unterschiedliche Probleme lösen und sich gegenseitig ergänzen, statt Alternativen zueinander zu sein. Ein gut strukturiertes System nutzt alle drei Typen gezielt: Targets zur Gruppierung, Sockets zur bedarfsgesteuerten Aktivierung, Timer zur zeitgesteuerten Ausführung.

Mironsoft

Linux-Serveradministration und systemd-Architektur für PHP-Hosting

Ein sauberer systemd-Abhängigkeitsgraph statt gewachsener Init-Skripte?

Wir modellieren eure Anwendungsstacks als eigene Targets, richten Socket-Aktivierung für bedarfsgesteuerte Dienste ein und sorgen für nachvollziehbare, parallelisierte Boot-Zeiten auf euren Produktionsservern.

Unit-Design

Eigene Targets für Anwendungsstacks mit klaren Abhängigkeiten

Socket-Aktivierung

Bedarfsgesteuerte Dienste statt dauerhaft laufender Prozesse

Boot-Optimierung

Analyse mit systemd-analyze und Abbau unnötiger serieller Abhängigkeiten

10. Zusammenfassung

Targets sind reine Synchronisationspunkte ohne eigene ausführbare Logik und ersetzen die starren SysV-Runlevel durch benannte, parallelisierbare Ziele im Abhängigkeitsgraph. Sockets öffnen Kommunikationsendpunkte vorab und starten den zugehörigen Dienst erst bei tatsächlichem Bedarf, was Ressourcen spart und Boot-Reihenfolge von Dienstverfügbarkeit entkoppelt. Accept=no ist für die meisten produktiven Dienste die richtige Wahl, Accept=yes bleibt seltenen, kurzlebigen Diensten vorbehalten.

Erst im Zusammenspiel entfalten diese Unit-Typen ihre volle Stärke: eigene Targets bündeln zusammengehörige Services, Sockets, und Timer zu einer benannten, gemeinsam steuerbaren Einheit. Wer systemd nur als Ersatz für /etc/init.d-Skripte oder als Cron-Alternative betrachtet, verpasst genau diesen strukturellen Mehrwert von Targets und Sockets als eigenständige, mächtige Bausteine des Init-Systems.

systemd Targets, Sockets und Timer: Das Wichtigste auf einen Blick

Targets

Reine Synchronisationspunkte ohne eigenen Prozess. Ersetzen Runlevel durch benannte, parallelisierbare Ziele.

Sockets

Öffnen Endpunkte vorab, starten Dienste erst bei Bedarf. Accept=no ist die empfohlene Standardeinstellung.

Eigene Targets

Bündeln zusammengehörige Services über Requires= und After=, steuerbar per systemctl isolate.

Debugging

systemd-analyze blame und critical-chain zeigen Boot-Engpässe, list-sockets zeigt aktive Endpunkte.

11. FAQ: systemd Targets, Sockets und Timer

1Target vs. Service?
Ein Service startet einen Prozess, ein Target ist nur ein Synchronisationspunkt ohne eigene Logik.
2Targets statt Runlevel?
Ja, funktional als Abhängigkeitsgraph statt strikt sequenzieller Skripte, mit Parallelität und expliziten Abhängigkeiten.
3Was ist Socket-Aktivierung?
systemd öffnet den Endpunkt vorab und startet den Dienst erst bei eingehender Verbindung, just in time.
4Accept=yes oder no?
Accept=no für die meisten produktiven Dienste, Accept=yes nur für einfache, kurzlebige Dienste mit geringer Last.
5Eigenes Target erstellen?
Unit-Datei mit .target-Endung anlegen, Requires= und After= referenzieren, per systemctl isolate aktivieren.
6Sockets und sockets.target?
sockets.target bündelt alle Socket-Units und wird vor basic.target erreicht, damit Endpunkte früh existieren.
7Timer von Target abhängig?
Ja, über After= und Requires= in der [Unit]-Section der Timer-Unit.
8Langsamen Boot analysieren?
systemd-analyze blame und critical-chain zeigen Startzeiten und die längste Abhängigkeitskette.
9Mehr Ressourcen bei Sockets?
Im Gegenteil, sie sparen Ressourcen, weil der Prozess erst bei Bedarf startet.
10Müssen alle drei kombiniert werden?
Nein, jeder Typ funktioniert eigenständig. Bei komplexen Stacks entfaltet das Zusammenspiel den größten Nutzen.