Dynamische Variablen in System-Service-Unit-Dateien

14

Gibt es eine Möglichkeit, Umgebungsvariablen in einer systemd-Service-Unit-Datei dynamisch zuzuweisen?

Wir haben einen Computer mit 4 GPUs und möchten mehrere Instanzen eines bestimmten Dienstes pro GPU hochfahren. Z.B:

  • gpu_service @ 1: 1.service
  • gpu_service @ 2: 1.service
  • gpu_service @ 3: 1.service
  • gpu_service @ 4: 1.service
  • gpu_service @ 1: 2.service
  • gpu_service @ 2: 2.service
  • gpu_service @ 3: 2.service
  • gpu_service @ 4: 2.service
  • bis zum Erbrechen

Das 1: 1, 2: 1 usw. ist also effektiv das% i in der Service-Unit-Datei.

Damit der Dienst an eine bestimmte GPU gebunden werden kann, überprüft die ausführbare Dienstdatei eine bestimmte Umgebungsvariable, z.

USE_GPU=4

Gibt es eine Möglichkeit, wie ich% i in die Service Unit-Datei aufnehmen und sie durch eine (Shell-) Funktion ausführen kann, um die GPU-Nummer abzuleiten, und dann die Umgebungsvariable USE_GPU entsprechend festlegen kann?

Am wichtigsten ist, dass ich nicht mühsam mehrere /etc/systemd/system/gpu_service@x:y.service/local.confDateien schreiben muss , nur um mehr Instanzen aufzubauen.

Kal
quelle

Antworten:

10

Wenn Sie vorsichtig sind, können Sie eine kleine Bash-Skriptsequenz als Ihren exec-Befehl in die Instanzdienstdatei einfügen. Z.B

ExecStart=/bin/bash -c 'v=%i; USE_GPU=$${v%:*} exec /bin/mycommand'

Das $$in der Zeichenfolge wird $im an bash übergebenen Ergebnis zu einem einzelnen , wird aber vor allem ${...}von systemd nicht mehr interpoliert. (Frühere Versionen von systemd haben die Verwendung von nicht dokumentiert $$, daher weiß ich nicht, ob es damals unterstützt wurde).

meuh
quelle
Am Ende habe ich so etwas gemacht. :)
Kal
1
Rufen Sie a bash -cauf, um ein Programm aus der Unit-Datei heraus zu starten. Anrufen exec? Dies ist wie die Verwendung eines Gabelstaplers auf einem Gabelstapler (möglicherweise mit einem anderen Gabelstapler), da der erste Gabelstapler Probleme mit dem Gabelstapler hat.
David Tonhofer
Leider kann man mit ExecStartPre keine env-Datei schreiben und diese dann verwenden, anscheinend muss sie vorher geschrieben werden, damit so etwas funktioniert. Oder ein Wrapper-Skript, um die Aufteilung durchzuführen :) Die andere bizarre Option wäre, einen anderen Dienst zum Einrichten der Umgebung zu erstellen. Datei, nicht sicher, wie das mit Vorlagen funktionieren würde, tho: stackoverflow.com/a/42841480/32453
Rogerdpack
8

Kein eingebauter Weg. Sie müssen diese Schritte ausführen, bevor Ihr Dienst gestartet wird. Eine Möglichkeit wäre, es in eine Umgebungsdatei zu schreiben.

[Service]
# Note you need to escape percentage sign
ExecStartPre=/bin/sh -c "my_awesome_parser %%i > /run/gpu_service_%i"
EnvironmentFile=/run/gpu_service_%i
ExecStart=...
Umut
quelle
4

Es sieht so aus, als ob Sie tatsächlich Umgebungsvariablen in einer systemd-Unit-Datei festlegen können ...

Per Vorschläge von Kommentatoren ist hier die Lösung:

Umgebungsvariablen in systemd-Einheiten verwenden

Umweltrichtlinie

systemd verfügt über eine Environment-Direktive, die Umgebungsvariablen für ausgeführte Prozesse festlegt. Es wird eine durch Leerzeichen getrennte Liste von Variablenzuweisungen benötigt. Diese Option kann mehrmals angegeben werden. In diesem Fall werden alle aufgelisteten Variablen gesetzt. Wenn dieselbe Variable zweimal festgelegt wird, überschreibt die spätere Einstellung die frühere Einstellung. Wenn dieser Option die leere Zeichenfolge zugewiesen wird, wird die Liste der Umgebungsvariablen zurückgesetzt, alle vorherigen Zuweisungen haben keine Auswirkung. Environments-Direktiven werden in integrierten Container Linux-Systemeinheiten verwendet, z. B. in etcd2 und flannel.

Mit dem folgenden Beispiel können Sie Ihren etcd2-Daemon für die Verwendung der Verschlüsselung konfigurieren. Erstellen Sie einfach ein /etc/systemd/system/etcd2.service.d/30-certificates.confDrop-In für etcd2.service:

[Service]
# Client Env Vars
Environment=ETCD_CA_FILE=/path/to/CA.pem
Environment=ETCD_CERT_FILE=/path/to/server.crt
Environment=ETCD_KEY_FILE=/path/to/server.key
# Peer Env Vars
Environment=ETCD_PEER_CA_FILE=/path/to/CA.pem
Environment=ETCD_PEER_CERT_FILE=/path/to/peers.crt
Environment=ETCD_PEER_KEY_FILE=/path/to/peers.key

Führen Sie dann sudo systemctl daemon-reloadund aus sudo systemctl restart etcd2.service, um neue Umgebungen auf den etcd2-Daemon anzuwenden.

Zitierter Text aus der folgenden URL: https://coreos.com/os/docs/latest/using-environment-variables-in-systemd-units.html

CyberK
quelle
2
Während dies theoretisch die Frage beantworten mag, wäre es vorzuziehen, die wesentlichen Teile der Antwort hier aufzunehmen und den Link als Referenz bereitzustellen.
Stephen Rauch
1
Während Ihr Kommentar theoretisch meine zukünftigen Antworten im Stapelaustausch verbessern kann, wäre es besser, wenn Sie die wesentlichen Teile der Antwort in Ihren Kommentar aufgenommen hätten, anstatt nur darauf hinzuweisen, wie inkompetent jemand sein könnte :)
CyberK
1
Willkommen bei Stack Exchange! Danke für den Kommentar, du hast mich zum Lächeln gebracht. Vielen Dank, dass Sie sich die Zeit genommen haben, Ihre Antwort zu bearbeiten. Wir versuchen, etwas zu schaffen, das im Laufe der Zeit einen Wert hat, und verknüpfen Sie nur Antworten, die einfach nicht gut altern.
Stephen Rauch
Wenn Sie hinzufügen Environment=ABC=%i, wird diese Umgebung eingestellt. Variable "auf die Gesamtheit von% i". Ich vermute, Sie könnten einen Wrapper erstellen, um das "Zeug jenseits des Zitats" zu entfernen, das Sie nicht wollen, und es nennt die echte ausführbare Datei. Aber wenn Sie einen Wrapper %iExecStart=my_wrapper %i
erstellen
0

Es ist hässlich und nicht ganz das, wonach Sie gefragt haben, und es erlaubt auch keinen Autostart, aber für Follower ist es möglich, etwas in der systemctl- Umgebung zu tun :

$ sudo systemctl set-environment USE_GPU=4 # add it to the env. variables for future services
$ sudo systemctl start gpu_service@4:2.service

Ich versuche nur alle Möglichkeiten aufzulisten :)

Rogerdpack
quelle