linux-ubuntu-debian systemd services automation deep-dive

Systemd Services – Unit-Files, Timer & Socket Activation (Artikel 007)

Der definitive Guide zu Systemd. Von einfachen Service-Units über Timer (Cron-Ersatz) bis hin zu fortgeschrittener Socket Activation und Dependency Management.

# Systemd Deep Dive: Mehr als nur systemctl start

TL;DR / Management Summary Systemd ist das Herzstück moderner Linux-Distributionen (Init-System PID 1). Es verwaltet nicht nur Dienste, sondern auch Timer (Cron-Ersatz), Mount-Points und Log-Dateien. Wer Systemd meistert, kann komplexe Abhängigkeiten definieren (“Starte Datenbank erst nach Netzwerk und Mount”), Services automatisch neu starten lassen (Self-Healing) und Ressourcen (CPU/RAM) limitieren.


# 1. Einführung & Architektur

Warum Systemd gewonnen hat.

Systemd parallelisiert den Boot-Vorgang massiv und startet Dienste “on-demand”.

# Unit-Typen Übersicht

  • .service: Der Klassiker. Startet einen Dämon (z.B. Nginx).
  • .timer: Zeitgesteuerte Ausführung (ersetzt Cron).
  • .socket: Lauscht auf einem Port und startet den Service erst bei eingehendem Traffic.
  • .target: Gruppierung von Units (z.B. multi-user.target entspricht Runlevel 3).
graph TD
    A[System Boot] --> B[sysinit.target]
    B --> C[basic.target]
    C --> D[multi-user.target]
    D --> E[nginx.service]
    D --> F[postgresql.service]
    E -.->|Depends on| G[network-online.target]

# 2. Der perfekte Service: Unit-File Anatomie

Wie man einen Dämon sauber definiert.

Unit-Files liegen in /etc/systemd/system/.

# Beispiel: Eigener Python-Webservice

Erstellen Sie /etc/systemd/system/myapp.service:

[Unit]
Description=My Python App
After=network.target postgresql.service
Wants=postgresql.service

[Service]
Type=simple
User=www-data
Group=www-data
WorkingDirectory=/var/www/myapp
ExecStart=/usr/bin/python3 /var/www/myapp/server.py
Restart=always
RestartSec=5s

# Security Hardening (Optional aber empfohlen)
ProtectSystem=full
PrivateTmp=true

[Install]
WantedBy=multi-user.target

Wichtig: Nach jeder Änderung an einer Unit-Datei müssen Sie systemctl daemon-reload ausführen, damit Systemd die Änderungen einliest.


# 3. Timer: Der bessere Cron

Warum Cron ausgedient hat.

Systemd Timer sind mächtiger als Cronjobs: Sie können Abhängigkeiten haben, loggen sauber ins Journal und können auf “Boot-Zeit” reagieren.

Schritt 1: Der Service (backup.service) Definiert was getan wird (ohne [Install] Sektion!).

[Unit]
Description=Daily Backup

[Service]
Type=oneshot
ExecStart=/usr/local/bin/backup.sh

Schritt 2: Der Timer (backup.timer) Definiert wann es getan wird.

[Unit]
Description=Run backup daily

[Timer]
OnCalendar=*-*-* 03:00:00
Persistent=true

[Install]
WantedBy=timers.target

Starten mit: systemctl enable --now backup.timer.


# 4. Socket Activation: Ressourcen sparen

Starten nur bei Bedarf.

Idee: Systemd hält Port 8080 offen. Erst wenn ein Paket ankommt, wird der Webserver gestartet und übernimmt den Socket.

Schritt 1: Der Socket (myapp.socket)

[Socket]
ListenStream=8080

[Install]
WantedBy=sockets.target

Der Service (myapp.service) braucht dann keine Port-Konfiguration mehr, da er den File-Descriptor (FD) von Systemd erbt.


# 5. Day-2 Operations: Management & Limits

Kontrolle behalten.

# Resource Control (Cgroups)

Sie können verhindern, dass ein Dienst den Server lahmlegt.

# Temporär setzen
systemctl set-property myapp.service CPUQuota=50% MemoryMax=512M

# Oder permanent im [Service] Block:
# CPUQuota=50%
# MemoryMax=512M

# Dependency Analyse

Warum dauert der Boot so lange?

systemd-analyze blame
systemd-analyze critical-chain

# 6. Troubleshooting & “War Stories”

Wenn der Dienst nicht hochkommt.

# Story 1: “Der Exit-Code Loop”

Symptom: Status ist “activating (auto-restart)”. Ursache: Das Skript stürzt sofort ab (Exit Code != 0), Systemd startet es neu (wegen Restart=always). Lösung: journalctl -u myapp.service -f nutzen, um den Python/Bash Fehler zu sehen. Oft fehlen Umgebungsvariablen (EnvironmentFile=/etc/default/myapp).

# Story 2: “Timeout beim Boot”

Symptom: Boot hängt 90s bei “A start job is running for…”. Ursache: Ein Service wartet auf das Netzwerk, aber das Netzwerk kommt nicht (z.B. falsche IP). Lösung: Prüfen, ob Type=forking genutzt wird, obwohl der Prozess nicht forkt. Oft ist Type=simple die sicherere Wahl.


# 7. Fazit & Empfehlung

  • Schreiben Sie eigene Unit-Files für alles, was dauerhaft laufen soll (keine screen oder nohup Sessions!).
  • Nutzen Sie Timer statt Cron für komplexe Aufgaben.
  • Härten Sie Services mit ProtectSystem und User, um die Sicherheit zu erhöhen.

# Anhang: Cheatsheet

Aufgabe Befehl
Service Status systemctl status <name>
Logs ansehen journalctl -u <name> -f
Boot-Analyse systemd-analyze
Fehlgeschlagene Units systemctl --failed
Änderungen laden systemctl daemon-reload