Frage Wie setze ich eine Umgebungsvariable in Systemd Service?


ich habe ein Arch Linux System mit Systemd und ich habe meinen eigenen Service erstellt. Der Konfigurationsdienst bei /etc/systemd/system/myservice.service sieht aus wie das:

[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?


119
2017-08-01 19:43


Ursprung




Antworten:


Die Zeiten ändern sich und damit auch die Best Practices.

Das aktuell Der beste Weg dies zu tun ist zu laufen systemctl edit myservice, die eine Überschreibungsdatei für Sie erstellt oder Sie eine vorhandene bearbeiten lassen.

In normalen Installationen wird dadurch ein Verzeichnis erstellt /etc/systemd/system/myservice.service.dInnerhalb dieses Verzeichnisses erstellen Sie eine Datei, deren Name endet .conf (typisch override.conf), und in dieser Datei können Sie jeden 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 außerdem, dass Ihr Dienst deaktiviert ist, wenn das Verzeichnis vorhanden und leer ist. Wenn Sie nicht beabsichtigen, etwas in das Verzeichnis zu schreiben, stellen Sie sicher, dass es nicht existiert.


Als Referenz war der alte Weg:

Der empfohlene Weg Dazu erstellen Sie eine Datei /etc/sysconfig/myservice was enthält Ihre Variablen und laden Sie sie dann mit EnvironmentFile.

Weitere Einzelheiten finden Sie in der Fedora-Dokumentation unter Wie schreibe ich ein Systemd-Skript?.


143
2017-08-01 20:07



Ich schätze das sysconfig Der Pfad ist spezifisch für Fedora, aber die Frage bezieht sich auf Arch Linux. Die Antwort von Paluh ist interessanter, denke ich - Ludovic Kuty
/etc/sysconfig ist Fedora-spezifisch. AFAIR Arch Linux drängte darauf, die Config-Dateien irgendwo paketspezifisch zu speichern /etc anstatt dieser Fedora-spezifischen Standort. Mögen /etc/myservice.conf, obwohl die Verwendung zusätzlicher Dateien hier nicht der richtige Weg ist. - Michał Górny
Nein nein Nein. / etc / sysconfig wird nicht empfohlen. Es wird abgeraten, zusammen mit / etc / default / * von debian, weil sie sinnlos sind, und die Namen sind bedeutungslos und nur aus Gründen der Rückwärtskompatibilität sinnvoll (alles von / etc betrifft die Konfiguration des Systems, nicht nur / etc / sysconfig, und / etc / defaults ist für Überschreibungen, nicht die Standardeinstellungen). Setzen Sie die Definitionen direkt in die Unit-Datei oder, wenn dies nicht möglich ist, in eine Umgebungsdatei, die einen paketspezifischen Speicherort hat (wie Michałs Kommentar suggeriert). - zbyszek
@ FrederickNord Es ist nur Variable = Wert-Paare, wie DJANGO_SETTINGS_MODULE=project.settings, eine pro Zeile. - Michael Hampton♦
@MichaelHampton Könnten Sie bitte einen Dokumentationslink für den "aktuell besten Weg" hinzufügen? - jb.


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

Da es sich um Ihre lokale Einheit handelt, ist die Grenze ziemlich verschwommen und jeder Weg würde funktionieren. Wenn Sie jedoch damit beginnen, es zu verteilen, und es würde in /usr/lib/systemd/system, das würde wichtig werden.

Konstanter Wert

Wenn der Wert nicht pro Instanz geändert werden muss, ist der bevorzugte Weg, ihn als zu platzieren Environment=, direkt in der Unit-Datei:

[Unit]
Description=My Daemon

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

[Install]
WantedBy=multi-user.target

Der Vorteil davon ist, dass die Variable in einer einzigen Datei mit der Einheit gespeichert wird. Daher ist die Einheitendatei einfacher zwischen Systemen zu wechseln.

Variabler Wert

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

In diesem Fall ist eine extra Datei zu verwenden. Wie - hängt normalerweise von der Verteilungspolitik ab.

Eine besonders interessante Lösung ist die Verwendung /etc/systemd/system/myservice.service.d Verzeichnis. 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.conf Das fügt die fehlenden Teile der Unit-Datei hinzu:

[Service]
Environment="FOO=bar baz"

Danach führt systemd beim Starten des Dienstes die beiden Dateien zusammen (erinnern Sie sich an systemctl daemon-reload nach dem Ändern eines von beiden). Und da dieser Pfad direkt von systemd verwendet wird, benutzt du ihn nicht EnvironmentFile= dafür.

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


66
2018-04-23 07:48



systemctl daemon-reload ist der Befehl, um Systemd neu zu laden - Dmitry Buzolin
EnvironmentFile= ist besser, wenn die Werte Geheimnisse wie Passwörter sind. Sehen meine Antwort für Details. - Don Kirkby


http://0pointer.de/public/systemd-man/systemd.exec.html#Environment= - Sie haben zwei Optionen (eine, auf die bereits von Michael hingewiesen wurde):

Environment=

und

EnvironmentFile=

34
2017-10-16 13:55





Michael gab eine saubere Lösung, aber ich wollte eine aktualisierte env Variable vom Skript bekommen. Leider ist das Ausführen von Bash-Befehlen in der Systemdatei nicht möglich. Glücklicherweise können Sie bash innerhalb von ExecStart auslösen:

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

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

Beispiel in unserem Fall ist dann:

[Service]
ExecStart=/bin/bash -c "ENV=`script`; /bin/myforegroundcmd"

6
2017-07-23 13:31



Dies funktioniert aus mehreren Gründen nicht (es sei denn, es handelt sich um einen "One-Shot" -Dienst, der ziemlich sinnlos ist). Ich schaffte es, Folgendes zur Arbeit zu bringen: /bin/bash -a -c 'source /etc/sysconfig/whatever && exec whatever-program'. Das -a stellt sicher, dass die Umgebung in den Unterprozess exportiert wird (es sei denn, Sie möchten alle Variablen voranstellen) whatever mit export ) - Otheus
warum wird es nicht funktionieren? Es sollte immer den gesamten Befehl auslösen, der das Ausführen des Skripts beinhaltet, oder? - user1830432
Könnte sein ExecStart=/usr/bin/env ENV=script /bin/myforegroundcmd ist in diesem Fall eine etwas bessere Lösung. - kstep
@Otheus: Tolle Antwort, gerettet am Tag als ich eine Tomcat 8 Unit Datei erstellen musste. - Daniel
Es gibt eine Möglichkeit, einen Bash-Befehl "in" einer Systemd-Service-Datei auszuführen. Siehe diesen Link: coreos.com/os/docs/latest/... - Mark Lakata


Die Antworten von Michael und Michał sind hilfreich und beantworten die ursprüngliche Frage, wie man eine Umgebungsvariable für einen Systemdienst setzt. Aber eins allgemeiner Gebrauch Bei Umgebungsvariablen werden sensible Daten wie Kennwörter an einem Ort konfiguriert, der nicht versehentlich mit dem Code der Anwendung an die Quellcodeverwaltung gebunden wird.

Wenn Sie deshalb eine Umgebungsvariable an Ihren Dienst übergeben möchten, unterlassen Sie benutzen Environment= in der Gerätekonfigurationsdatei. Benutzen EnvironmentFile= und verweisen Sie auf eine andere Konfigurationsdatei, die nur vom Dienstkonto (und Benutzern mit Root-Zugriff) gelesen werden kann.

Die Details der Gerätekonfigurationsdatei sind für jeden Benutzer mit diesem Befehl sichtbar:

systemctl show my_service

Ich habe eine Konfigurationsdatei bei /etc/my_service/my_service.conf und lege meine Geheimnisse dort hinein:

MY_SECRET=correcthorsebatterystaple

Dann habe ich in meiner Diensteinheitsdatei 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 das überprüft ps auxe Diese Umgebungsvariablen können nicht angezeigt werden und andere Benutzer haben keinen Zugriff darauf /proc/*/environ. Überprüfen Sie natürlich Ihr eigenes System.


6
2018-05-04 00:29