Escribir un archivo de unidad systemd con una ruta ejecutable establecida por el entorno

17

Estoy escribiendo un archivo de unidad systemd para una aplicación Java y me gustaría controlar la versión de Java utilizada para iniciarlo. Mi (simplificado) archivo de servicio es

[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

Cuando se trata de ponerlo en marcha me sale un error de vuelta

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.

Sé que JAVA_HOMEse establece correctamente; si cambio la ExecStartlínea para comenzar /usr/bin/javay luego agrego algo como -DsomeOption=${JAVA_HOME}puedo verlo bien.

La solución obvia es crear una secuencia de comandos de contenedor, pero creo que no sirve para nada el uso de un archivo de servicio.

¿Cómo puedo configurar JAVA_HOME para mi aplicación Java usando un archivo de unidad?

Robert Munteanu
fuente
¿Por qué el script de envoltura anula el propósito de usar un archivo de servicio exactamente? Seguirá disfrutando de secuenciación y seguimiento de dependencias, monitoreo, etc. SystemD Básicamente, comercios systemd distancia de forma libre programabilidad que tuvimos con SysVinit a favor de horneado en DTRT lógica. Cuando "lo correcto" es algo que systemd no hace, debe colocarlo fuera de systemd, como en un script de shell.
Warren Young
@WarrenYoung: porque de repente empiezo a administrar scripts de shell nuevamente. En mi caso no lograr un script de shell es más útil que los otros bits.
Robert Munteanu
Realmente no veo el problema. ¿Pasas tus días preocupándote por todos los ejecutables que también tienes que administrar? :)
Warren Young
3
De systemd.service (5): "Tenga en cuenta que el primer argumento (es decir, el programa a ejecutar) puede no ser una variable" Eso explica por qué $ {} JAVA_HOME no está desplegado en el comienzo de la ruta de las aplicaciones, pero es cuando se utiliza en algún momento posterior.
Wieland
@WarrenYoung: prefiero un contenedor único sobre el binario. Entiendo que no es un problema para todos, pero es para mí :-)
Robert Munteanu

Respuestas:

12

Desde la sección "Líneas de comando" en systemd.service (5):

Tenga en cuenta que el primer argumento (es decir, el programa a ejecutar) puede no ser una variable.

Iba a sugerir el uso de la especificador instancia %i(se puede leer más sobre esto en systemd.unit (5)), pero (ahora estamos de vuelta en systemd.service (5)):

El primer argumento de la línea de comando (es decir, el programa a ejecutar) puede no incluir especificadores.

Creo que la mejor opción en este momento realmente es crear un script de shell que envuelva la ejecución del binario de Java como lo sugiere Warren Young o podría ejecutar ExecStart directamente como en el ejemplo de las líneas de comando de shell en la sección "Líneas de comando" de systemd.service (5) que tiene el siguiente ejemplo:

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

para que puedas hacer (no probado):

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

Otra opción similar es usar /usr/bin/env:

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

De esta manera, puede omitir 'comillas alrededor del comando completo, lo que es útil si necesita anidar cosas entre comillas.

PD. Como nota al margen, es importante encerrar los nombres de las variables entre {llaves }en los archivos de Systemd o, de lo contrario, no se reconocerán correctamente.

MarSoft
fuente