Einsatz von Docker Containern mit Systemd für automatisiertes Starten

Warum Systemd mit Docker für Produktionseinsätze kombiniert werden

Moderne Infrastruktur verlangt, dass containerisierte Dienste unerwartete Neustarts, Hardwareausfälle oder Paketupdates überleben. Während Docker Neustartrichtlinien ()) anbietet, funktionieren diese Richtlinien nur so lange, wie der Docker-Daemon läuft. Systemd – das Init-System, das von Ubuntu, Debian, Fedora, CentOS und den meisten modernen Linux-Distributionen verwendet wird – führt dies durch die Verwaltung des Lebenszyklus des Docker-Daemons selbst und kann Container starten, noch bevor der Docker-Socket verfügbar ist.

Durch das Einwickeln jedes Docker-Containers in eine Systemd Service File erhalten Betriebsteams eine konsistente Schnittstelle zum Starten, Stoppen und Überwachen von Containern, wodurch die Abhängigkeit von Ad-hoc-Scripts und manuellen Eingriffen reduziert wird.

Erstellen eines Systemd Service für einen Single Docker Container

Der Standardansatz beinhaltet das Schreiben einer Service Unit-Datei, die Docker-Befehle zum Ausführen und Stoppen des Containers aufruft. Im Folgenden gehen wir Schritt für Schritt durch den Prozess, beginnend mit einem Basisbeispiel und dann mit den üblichen Produktionsanforderungen.

Schritt 1: Schreiben Sie die Service Unit-Datei

Erstellen Sie eine Datei mit dem Namen und verwenden Sie die folgende Vorlage als Ausgangspunkt:

[Unit]
Description=My Application Container
After=network-online.target docker.service
Wants=network-online.target
Requires=docker.service

[Service]
Restart=always
RestartSec=10
StartLimitBurst=3
ExecStartPre=-/usr/bin/docker kill myapp
ExecStartPre=-/usr/bin/docker rm myapp
ExecStart=/usr/bin/docker run --rm --name myapp \
 -e DB_HOST=10.0.1.50 \
 -e DB_PORT=5432 \
 -v /data/myapp:/app/data \
 -p 8080:8080 \
 myregistry/myapp:latest
ExecStop=/usr/bin/docker stop -t 10 myapp
ExecStopPost=-/usr/bin/docker rm myapp

[Install]
WantedBy=multi-user.target

Erklärung der wichtigsten Direktiven:

Schritt 2: Aktivieren und Starten des Dienstes

sudo systemctl daemon-reload
sudo systemctl enable myapp.service
sudo systemctl start myapp.service

Die sagt systemd, Service-Dateien erneut zu lesen. erstellt den Symlink, so dass der Dienst beim Booten beginnt.

Verwaltung des Dienstes mit Standard-Systemd-Befehlen

Sobald der Dienst ausgeführt wird, steuern Sie ihn wie jeder andere Systemdienst:

Erweiterte Konfigurationsmuster

Produktionsbereitstellungen erfordern oft mehr als nur eine einfache Im Folgenden finden Sie allgemeine Verbesserungen, die Sie Ihren Systemd Service-Dateien hinzufügen können.

Vorbeigehende Umweltvariablen

Hardcoding-Geheimnisse oder Konfiguration in der Service-Datei werden nicht empfohlen, sondern eine separate Umgebungsdatei verwenden:

[Service]
EnvironmentFile=-/etc/myapp/env.conf
ExecStart=/usr/bin/docker run --rm --name myapp \
 --env-file /etc/myapp/env.conf \
 myregistry/myapp:latest

Das Präfix vor dem Pfad bedeutet, dass der Dienst auch dann startet, wenn die Datei nicht vorhanden ist (nützlich während der Ersteinrichtung).

Vernetzung und Port Bindings

Für Container, die auf demselben Host miteinander kommunizieren müssen, sollten Sie oder benutzerdefinierte Brückennetzwerke verwenden.

ExecStart=/usr/bin/docker run --rm --name web \
 --network=my-net \
 -p 443:443 \
 -v /etc/ssl/certs:/etc/ssl/certs:ro \
 myregistry/web:latest

Wenn Sie ein benutzerdefiniertes Netzwerk verwenden, stellen Sie sicher, dass das Netzwerk existiert, bevor der Dienst startet.

ExecStartPre=/usr/bin/docker network create my-net

Intercontainer-Abhängigkeiten

Wenn ein Container vor dem Start bereit sein muss (z. B. eine Web-App, die auf eine Datenbank wartet), kann systemd die Bestellung erzwingen.

[Unit]
Description=Web App Container
After=network-online.target docker.service mydb.service
BindsTo=mydb.service

bindet den Lebenszyklus der Web-App an den Datenbankcontainer – wenn die Datenbank stoppt, wird auch die Web-App gestoppt.

Gesundheitschecks und Bereitschaft

Docker Health Checks können mit systemd integriert werden, um eine vorzeitige Verfügbarkeit des Dienstes zu verhindern.

ExecStartPost=/usr/local/bin/wait-for-health.sh http://localhost:8080/health 30

Das Skript sollte nur dann aus 0 auslaufen, wenn der Container in Ordnung ist.

Ressourcenlimits über Systemd

Sie können die CPU und den Speicher eines Containers auf cgroup-Ebene ohne Docker-eigene Ressourcen-Flags einschränken.

[Service]
MemoryMax=512M
CPUQuota=50%

Diese Einstellungen erzeugen ein hartes Limit, das systemd unabhängig von Docker durchsetzt.

Verwalten mehrerer Container: Systemd vs. Docker Compose

Für eine kleine Anzahl von Containern (z. B. 2-5) sind einzelne Systemd-Service-Dateien einfach und wartungsfähig. Wenn ein Projekt jedoch viele miteinander verbundene Dienste umfasst, wird Docker Compose bequemer. Sie können den gesamten Docker Compose-Stack immer noch systemd verwenden, um den gesamten Docker Compose-Stack zu orchestrieren, indem Sie eine einzelne Serviceeinheit erstellen, die aufruft. Beispiel:

[Unit]
Description=My Application Stack
After=network-online.target docker.service
Requires=docker.service

[Service]
Type=oneshot
RemainAfterExit=yes
WorkingDirectory=/opt/myapp
ExecStart=/usr/local/bin/docker-compose up -d
ExecStop=/usr/local/bin/docker-compose down

[Install]
WantedBy=multi-user.target

Dieser Ansatz gibt Ihnen die Einfachheit von Compose zum Definieren von Diensten in Kombination mit dem Lifecycle-Management von systemd. Beachten Sie, dass verwendet wird, weil sofort ausläuft. hält die Einheit in einem “aktiven” Zustand, bis aufgerufen wird.

Welche Methode sollten Sie wählen?

Problembehandlung bei gemeinsamen Problemen

Selbst bei sorgfältiger Einrichtung können Sie auf Probleme stoßen. Unten sind häufige Fallstricke und ihre Lösungen.

Service schlägt fehl mit "Kann sich nicht mit dem Docker-Daemon verbinden"

Das bedeutet normalerweise, dass der Dienst startet, bevor der Docker-Socket fertig ist. Stellen Sie sicher, dass Ihr Gerät und enthält.

Container-Neustarts in einer Schleife

Wenn der Container sofort ausläuft, wird systemd ihn gemäß und neu starten. Überprüfen Sie Containerprotokolle mit Erhöhen Sie (z. B. 30 Sekunden) und stellen Sie ein, um eine Besetzte Schleife zu verhindern.

Service hört nicht sauber auf

Wenn ein falsch konfigurierter den Container laufen lässt, überprüfen Sie, ob den korrekten Containernamen verwendet.

Umweltvariablen nicht geladen

Wenn Sie verwenden, bestätigen Sie, dass die Datei vorhanden und durch root lesbar ist. Vermeiden Sie das Zitieren von Problemen – systemd strip quotes from variable values. Für die geheime Injektion sollten Sie systemd credentials oder einen dedizierten Secret Manager verwenden.

Sicherheitsüberlegungen

Das Ausführen von Docker-Containern durch systemd wirft einige Sicherheitspunkte auf:

[Service]
ProtectSystem=strict
ReadWritePaths=/var/log/myapp
PrivateTmp=true
User=myappuser

Externe Ressourcen

Für weitere Informationen, konsultieren Sie diese offiziellen Referenzen:

Schlussfolgerung

Durch die Integration von Systemd mit Docker-Containern erhalten Sie einen robusten, automatisierten Startmechanismus, der sich nahtlos in den Rest Ihres Linux-Systems integrieren lässt. Durch das Schreiben gut strukturierter Service Unit-Dateien können Sie die Startreihenfolge steuern, Abhängigkeiten verwalten, Ressourcenlimits festlegen und Protokolle mit Tools überwachen, die Ihr Operationsteam bereits kennt. Ob Sie einzelne Dienste für jeden Container oder eine einzelne Einheit auswählen, um einen Compose-Stack zu orchestrieren, bietet systemd die Zuverlässigkeit und Vorhersagbarkeit, die Produktionsumgebungen erfordern.

Beginnen Sie mit einer einfachen Unit-Datei, testen Sie sie gründlich, und legen Sie dann erweiterte Optionen wie Umgebungsdateien, Gesundheitschecks und Sicherheitshärtung fest. Mit diesem Ansatz überleben Ihre Docker-Container Neustarts, Abstürze und Konfigurationsänderungen ohne manuelle Eingriffe, sodass sich Ihr Team auf die Erstellung von Anwendungen konzentrieren kann.