¿Cómo habilitar un virtualenv en una unidad de servicio systemd?

85

Quiero "activar" un virtualenv en un archivo de servicio systemd.

Me gustaría evitar tener un proceso de shell entre el proceso systemd y el intérprete de Python.

Mi solución actual se ve así:

[Unit]
Description=fooservice
After=syslog.target network.target

[Service]
Type=simple
User=fooservice
WorkingDirectory={{ venv_home }}
ExecStart={{ venv_home }}/fooservice --serve-in-foreground
Restart=on-abort
EnvironmentFile=/etc/sysconfig/fooservice.env

[Install]
WantedBy=multi-user.target

/etc/sysconfig/fooservice.env

PATH={{ venv_home }}/bin:/usr/local/bin:/usr/bin:/bin
PYTHONIOENCODING=utf-8
PYTHONPATH={{ venv_home }}/...
VIRTUAL_ENV={{ venv_home }}

Pero estoy teniendo problemas. Recibo ImportErrors ya que faltan algunas entradas en sys.path.

guettli
fuente
¿Puede incluir los errores que está recibiendo?
Praveen Yalagandula
@PraveenYalagandula El rastreo no contiene ninguna información útil, ya que la excepción ImportError y todas las líneas arriba contienen solo código personalizado que no importa aquí.
guettli

Respuestas:

112

El virtualenv está "integrado en el intérprete de Python en el virtualenv". Esto significa que puede iniciar pythono console_scriptsdirectamente en ese virtualenv y no necesita activar primero el virtualenv o administrarse PATHusted mismo:

ExecStart={{ venv_home }}/bin/fooservice --serve-in-foreground

o

ExecStart={{ venv_home }}/bin/python {{ venv_home }}/fooservice.py --serve-in-foreground

y elimine la EnvironmentFileentrada.

Para verificar que sea correcto, puede verificar sys.pathejecutando

{{ venv_home }}/bin/python -m site

y comparando la salida con

python -m site
Nils Werner
fuente
2
buen punto Nils. Por cierto, fooservice.py no tiene sentido estar dentro del directorio venv_home, supongo que es un error tipográfico en la pregunta.
stelios
4
Tenga en cuenta que los comandos de impresión sugeridos no son compatibles con Python 3. Si está usando al menos python 2.4, alternativamente puede usar: python -m sitepara obtener una salida con un formato agradable de la variable sys.path junto con información adicional.
Mark Edington
2
Limpio, no lo sabía python -m site. He ajustado mi respuesta.
Nils Werner
1
@NilsWerner Terminé resolviéndolo generando un shell, nada más funcionó en Ubuntu 17.10: github.com/umccr/pcgr-deploy/blob/master/ansible/files/… ... por favor ignore la plantilla jinja2 para ansible, eso se expande correctamente cuando se despliega.
lluvia de ideas
6
Para los que preguntan si esto es ninja2 .... no, los dobles entre llaves son sólo marcadores de posición de la OP inventado: superuser.com/questions/1209919/...
ankostis
11

Si bien la ruta de las bibliotecas está integrada en el intérprete de Python del virtualenv, he tenido problemas con las herramientas de Python que usaban binarios instalados en ese virtualenv. Por ejemplo, mi servicio de flujo de aire apache no funcionaría porque no pudo encontrar el gunicornbinario. Para solucionar esto, aquí está mi ExecStartinstrucción, con una Environmentinstrucción (que establece una variable de entorno solo para el servicio).

ExecStart={{ virtualenv }}/bin/python {{ virtualenv }}/bin/airflow webserver
Environment="PATH={{ virtualenv }}/bin:{{ ansible_env.PATH }}"

ExecStartutiliza explícitamente el intérprete de Python del virtualenv. También estoy agregando una PATHvariable, que agrega la carpeta binaria del virtualenv antes del sistema PATH. De esa manera, obtengo las bibliotecas de Python deseadas, así como los binarios.

Tenga en cuenta que estoy usando ansible para construir este servicio, ergo las llaves de jinja2.

Alexis Lessard
fuente
1

No estoy usando virtualenv sino pyenv: aquí está solo para usar la ruta .pyenv real en el shebang y asegurarse de que esté en la RUTA

Ejemplo: pyenv activa flask-prod para el usuario mortenb que se ejecuta en prod

/home/mortenb/.pyenv/versions/flask-prod/bin/python --version
Python 3.6.2

Luego, a mis scripts de matraces que comienzan en systemd * .service, agrego el siguiente shebang:

#!/home/mortenb/.pyenv/versions/flask-prod/bin/python3
MortenB
fuente
0

En mi caso, solo intenté agregar variables de entorno requeridas para Flask, por ejemplo

[Service]
Environment="PATH=/xx/yy/zz/venv/bin"
Environment="FLASK_ENV=development"
Environment="APP_SETTINGS=config.DevelopmentConfig"

Estaba usando virtualenv, así que /xx/yy/zz/venv/bines la ruta de la carpeta virtualenv.

Sebastián Cardona Osorio
fuente