Schreiben einer System-Unit-Datei mit einem von der Umgebung festgelegten ausführbaren Pfad

17

Ich schreibe eine systemd-Unit-Datei für eine Java-Anwendung und möchte die zum Starten verwendete Java-Version steuern. Meine (vereinfachte) Servicedatei ist

[Service]
Type=simple
EnvironmentFile=%h/Documents/apps/app/app-%i/app.cfg
ExecStart=${JAVA_HOME}/bin/java ${JAVA_OPTS} -jar %h/Documents/apps/app/app-%i/myapp.jar
SuccessExitStatus=143

Beim Versuch, es zu starten, erhalte ich einen Fehler zurück

Apr 28 12:43:37 rombert systemd[1613]: [/home/robert/.config/systemd/user/[email protected]:7] Executable path is not absolute, ignoring: ${JAVA_HOME}/bin/java ${JAVA_OPT
Apr 28 12:43:37 rombert systemd[1613]: [email protected] lacks both ExecStart= and ExecStop= setting. Refusing.

Ich weiß, dass JAVA_HOMEdas richtig eingestellt ist; Wenn ich die ExecStartZeile zunächst ändere /usr/bin/javaund dann so etwas hinzufüge, wie -DsomeOption=${JAVA_HOME}ich es sehen kann, ist das in Ordnung.

Die offensichtliche Problemumgehung besteht darin, ein Wrapper-Skript zu erstellen, aber ich bin der Meinung, dass es den Sinn einer Servicedatei zunichte macht.

Wie kann ich JAVA_HOME für meine Java-Anwendung mithilfe einer Unit-Datei festlegen?

Robert Munteanu
quelle
Warum hat das Wrapper-Skript genau den Zweck, eine Servicedatei zu verwenden? Sie erhalten weiterhin die Sequenz- und Abhängigkeitsverfolgung, -überwachung usw. von systemd. Grundsätzlich handelt systemd von der Freiform-Programmierbarkeit, die wir mit SysVinit hatten, zugunsten der eingebauten DTRT- Logik. Wenn "das Richtige" etwas ist, was systemd nicht tut, müssen Sie dieses außerhalb von systemd platzieren, wie in einem Shell-Skript.
Warren Young
@WarrenYoung - weil ich plötzlich wieder anfange, Shell-Skripte zu verwalten. In meinem Fall ist es sinnvoller, kein Shell-Skript zu verwalten als die anderen Bits.
Robert Munteanu
Ich sehe das Problem wirklich nicht. Kümmern Sie sich Ihre Tage um alle ausführbaren Dateien, die Sie verwalten müssen? :)
Warren Young
3
Aus systemd.service (5): "Beachten Sie, dass das erste Argument (dh das auszuführende Programm) möglicherweise keine Variable ist." Dies erklärt, warum $ {JAVA_HOME} nicht am Anfang des Anwendungspfads erweitert wird, sondern zu einem späteren Zeitpunkt verwendet wird.
Wieland
@WarrenYoung - Ich bevorzuge einen einzelnen Wrapper gegenüber der Binärdatei. Ich verstehe, dass es nicht jedermanns Sache ist, aber es ist für mich :-)
Robert Munteanu

Antworten:

12

Aus dem Abschnitt "Befehlszeilen" in systemd.service (5):

Beachten Sie, dass das erste Argument (dh das auszuführende Programm) möglicherweise keine Variable ist.

Ich wollte vorschlagen, den %iInstanzspezifizierer zu verwenden (mehr dazu in systemd.unit (5)), aber (jetzt sind wir wieder in systemd.service (5)):

Das erste Argument der Befehlszeile (dh das auszuführende Programm) darf keine Bezeichner enthalten.

Ich denke, die beste Option an dieser Stelle ist die Erstellung eines Shell-Skripts, das die Ausführung der Java-Binärdatei wie von Warren Young vorgeschlagen umschließt, oder Sie könnten eine Shell direkt starten, wie im Beispiel für Shell-Befehlszeilen im Abschnitt "Befehlszeilen" von systemd.service (5) mit folgendem Beispiel:

ExecStart=/bin/sh -c 'dmesg | tac'

so könnte man machen (ungetestet):

ExecStart=/bin/sh -c '${JAVA_HOME}....'
Wieland
quelle
2

Eine andere ähnliche Option ist die Verwendung von /usr/bin/env:

ExecStart=/usr/bin/env "${JAVA_HOME}/bin/java" -jar ...

Auf diese Weise können Sie 'den gesamten Befehl in Anführungszeichen setzen, was nützlich ist, wenn Sie zitierte Elemente verschachteln müssen.

PS. Als Randnotiz ist es wichtig, Variablennamen in {Klammern }in Systemd-Dateien einzuschließen, da sie sonst nicht korrekt erkannt werden.

MarSoft
quelle