Wie setze ich die Umgebungsvariable im Systemd Service?

162

Ich besitze ein Arch Linux-System mit systemd und habe meinen eigenen Dienst erstellt. Der Konfigurationsdienst bei /etc/systemd/system/myservice.servicesieht folgendermaßen aus:

[Unit]
Description=My Daemon

[Service]
ExecStart=/bin/myforegroundcmd

[Install]
WantedBy=multi-user.target

Jetzt möchte ich eine Umgebungsvariable für die /bin/myforegroundcmd. Wie mache ich das?

lfagundes
quelle

Antworten:

197

Die Zeiten ändern sich und bewährte Methoden auch.

Der derzeit beste Weg, dies zu tun, ist das Ausführen systemctl edit myservice, wodurch eine Überschreibungsdatei für Sie erstellt wird oder Sie eine vorhandene bearbeiten können.

Bei normalen Installationen wird ein Verzeichnis erstellt /etc/systemd/system/myservice.service.d, und in diesem Verzeichnis wird eine Datei erstellt, deren Name .conf(normalerweise override.conf) auf endet. In dieser Datei können Sie einen beliebigen Teil der von der Distribution gelieferten Einheit hinzufügen oder überschreiben.

Zum Beispiel in einer Datei /etc/systemd/system/myservice.service.d/myenv.conf:

[Service]
Environment="SECRET=pGNqduRFkB4K9C2vijOmUDa2kPtUhArN"
Environment="ANOTHER_SECRET=JP8YLOc2bsNlrGuD6LVTq7L36obpjzxd"

Beachten Sie auch, dass Ihr Dienst deaktiviert wird, wenn das Verzeichnis existiert und leer ist! Wenn Sie nicht beabsichtigen, etwas in das Verzeichnis aufzunehmen, stellen Sie sicher, dass es nicht vorhanden ist.


Als Referenz war der alte Weg:

Der empfohlene Weg , dies zu tun, besteht darin, eine Datei zu erstellen, /etc/sysconfig/myservicedie Ihre Variablen enthält, und sie dann mit zu laden EnvironmentFile.

Ausführliche Informationen finden Sie in der Fedora-Dokumentation zum Schreiben eines systemd-Skripts .

Michael Hampton
quelle
4
Ich denke, der sysconfigPfad ist spezifisch für Fedora, aber die Frage betrifft Arch Linux. Die Antwort von paluh ist interessanter, denke ich
Ludovic Kuty
1
/etc/sysconfigist Fedora-spezifisch. AFAIR Arch Linux drängte darauf, die Konfigurationsdateien an einem paketspezifischen Ort anstatt an /etcdiesem Fedora-spezifischen Ort zu haben. Wie /etc/myservice.conf, wenn zusätzliche Datei hier scheint nicht den richtigen Weg.
Michał Górny
5
Nein nein Nein. / etc / sysconfig wird nicht empfohlen. Es wird, zusammen mit / etc / default / * von debian, davon abgeraten, weil sie sinnlos sind und die Namen bedeutungslos und nur aus Gründen der Abwärtskompatibilität sinnvoll sind (bei / etc geht es ausschließlich um die Konfiguration des Systems, nicht nur um / etc / sysconfig und / etc / defaults dienen zum Überschreiben, nicht der Standardeinstellung. Fügen Sie die Definitionen einfach direkt in die Unit-Datei ein oder, falls dies nicht möglich ist, in eine Umgebungsdatei mit einem paketspezifischen Speicherort (wie in Michałs Kommentar vorgeschlagen).
Zbyszek
1
@FrederickNord Es handelt sich nur um Paare aus Variable und Wert, z. B. DJANGO_SETTINGS_MODULE=project.settingseines pro Zeile.
Michael Hampton
1
@MichaelHampton Kannst du bitte einen Dokumentationslink für "current best way" hinzufügen?
jb.
77

Die Antwort hängt davon ab, ob die Variable konstant sein soll (dh nicht vom Benutzer geändert werden soll, der die Einheit erhält) oder variabel (vom Benutzer festgelegt werden soll).

Da es sich um Ihre örtliche Einheit handelt, ist die Grenze ziemlich verschwommen und in beiden Fällen funktioniert es. Wenn Sie jedoch anfangen würden, es zu verbreiten, und es würde in enden /usr/lib/systemd/system, würde dies wichtig werden.

Konstanter Wert

Wenn sich der Wert nicht pro Instanz ändern muss, ist die bevorzugte Methode Environment=, ihn direkt in der Unit-Datei zu platzieren:

[Unit]
Description=My Daemon

[Service]
Environment="FOO=bar baz"
ExecStart=/bin/myforegroundcmd

[Install]
WantedBy=multi-user.target

Dies hat den Vorteil, dass die Variable mit der Einheit in einer einzigen Datei gespeichert wird. Daher ist es einfacher, die Unit-Datei zwischen den Systemen zu verschieben.

Variabler Wert

Die obige Lösung funktioniert jedoch nicht gut, wenn sysadmin den Wert der Umgebungsvariablen lokal ändern soll. Insbesondere müsste der neue Wert jedes Mal festgelegt werden, wenn die Einheitendatei aktualisiert wird.

In diesem Fall ist eine zusätzliche Datei zu verwenden. Wie - hängt in der Regel von der Distributionsrichtlinie ab.

Eine besonders interessante Lösung ist die Verwendung eines /etc/systemd/system/myservice.service.dVerzeichnisses. Im Gegensatz zu anderen Lösungen wird dieses Verzeichnis von systemd selbst unterstützt und enthält daher keine verteilungsspezifischen Pfade.

In diesem Fall platzieren Sie eine Datei wie /etc/systemd/system/myservice.service.d/local.confdiese und fügen die fehlenden Teile der Unit-Datei hinzu:

[Service]
Environment="FOO=bar baz"

Danach führt systemd die beiden Dateien beim Starten des Dienstes zusammen (denken Sie daran, systemctl daemon-reloadnachdem Sie eine der beiden Dateien geändert haben). Und da dieser Pfad direkt von systemd verwendet wird, verwenden Sie dies nicht EnvironmentFile=.

Wenn der Wert nur auf einigen der betroffenen Systeme geändert werden soll, können Sie beide Lösungen kombinieren, indem Sie eine Standardeinstellung direkt in der Einheit und eine lokale Überschreibung in der anderen Datei festlegen.

Michał Górny
quelle
systemctl daemon-reloadist der Befehl zum Nachladen von systemd
Dmitry Buzolin
EnvironmentFile=ist besser, wenn die Werte Geheimnisse wie Passwörter sind. Siehe meine Antwort für Details.
Don Kirkby
17

Die Antworten von Michael und Michał sind hilfreich und beantworten die ursprüngliche Frage, wie eine Umgebungsvariable für einen systemd-Dienst festgelegt wird. Eine häufige Verwendung von Umgebungsvariablen besteht jedoch darin, vertrauliche Daten wie Kennwörter an einem Ort zu konfigurieren, an dem sie nicht versehentlich mit dem Code Ihrer Anwendung zur Quellcodeverwaltung verpflichtet werden.

Wenn das ist , warum Sie eine Umgebungsvariable zu Ihrem Dienst übergeben mögen, nicht verwendet Environment=in der Einheit - Konfigurationsdatei. Verwenden EnvironmentFile=Sie eine andere Konfigurationsdatei, die nur vom Dienstkonto (und von Benutzern mit Root-Zugriff) gelesen werden kann, und verweisen Sie darauf.

Die Details der Einheitenkonfigurationsdatei sind für jeden Benutzer mit diesem Befehl sichtbar:

systemctl show my_service

Ich habe eine Konfigurationsdatei bei /etc/my_service/my_service.confund meine Geheimnisse dort abgelegt:

MY_SECRET=correcthorsebatterystaple

Dann habe ich in meiner Service Unit-Datei Folgendes verwendet EnvironmentFile=:

[Unit]
Description=my_service

[Service]
ExecStart=/usr/bin/python /path/to/my_service.py
EnvironmentFile=/etc/my_service/my_service.conf
User=myservice

[Install]
WantedBy=multi-user.target

Ich habe überprüft, dass ps auxediese Umgebungsvariablen nicht angezeigt werden und andere Benutzer keinen Zugriff darauf haben /proc/*/environ. Überprüfen Sie dies natürlich auf Ihrem eigenen System.

Don Kirkby
quelle
8

Michael gab eine saubere Lösung, aber ich wollte eine aktualisierte env-Variable aus dem Skript erhalten. Leider ist die Ausführung von bash-Befehlen in der systemd-Unit-Datei nicht möglich. Glücklicherweise können Sie Bash in ExecStart auslösen:

http://www.dsm.fordham.edu/cgi-bin/man-cgi.pl?topic=systemd.service&sect=5

Beachten Sie, dass diese Einstellung Shell-Befehlszeilen nicht direkt unterstützt. Wenn Shell-Befehlszeilen verwendet werden sollen, müssen diese explizit an eine Shell-Implementierung übergeben werden.

Beispiel in unserem Fall ist dann:

[Service]
ExecStart=/bin/bash -c "ENV=`script`; /bin/myforegroundcmd"
user1830432
quelle
7
Dies wird aus mehreren Gründen nicht funktionieren (es sei denn, es handelt sich um einen "One-Shot" -Dienst, der ziemlich sinnlos ist). Ich schaffte es die folgende Arbeit zu bekommen: /bin/bash -a -c 'source /etc/sysconfig/whatever && exec whatever-program'. Die -agewährleistet wird die Umgebung auf den Teilprozess ausgeführt (es sei denn , Sie alle Variablen in Präfix wollen whatevermit export)
Otheus
warum klappt es nicht Es sollte immer den gesamten Befehl auslösen, der das Ausführen des Skripts beinhaltet, nicht wahr?
user1830432
Vielleicht ExecStart=/usr/bin/env ENV=script /bin/myforegroundcmdist eine etwas bessere Lösung in diesem Fall.
kstep
@ Theus: Tolle Antwort, gespeichert am Tag, an dem ich eine Tomcat 8 Unit-Datei erstellen musste.
Daniel
1
Es gibt eine Möglichkeit, einen bash-Befehl "in" einer systemd-Servicedatei auszuführen. Siehe diesen Link: coreos.com/os/docs/latest/…
Mark Lakata