Como habilitar um virtualenv em uma unidade de serviço systemd?

87

Eu quero "ativar" um virtualenv em um arquivo de serviço systemd.

Eu gostaria de evitar um processo de shell entre o processo systemd e o interpretador python.

Minha solução atual é assim:

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

Mas estou tendo problemas. Recebo ImportErrors, pois algumas entidades em sys.path estão faltando.

Guettli
fonte
Você pode incluir os erros que está recebendo?
Praveen Yalagandula
@PraveenYalagandula O traceback não contém nenhuma informação útil, uma vez que a Exceção ImportError e todas as linhas acima contêm apenas código personalizado que não importa aqui.
guettli

Respostas:

117

O virtualenv é "embutido no interpretador Python no virtualenv". Isso significa que você pode iniciar pythonou console_scriptsdiretamente naquele virtualenv e não precisa ativar o virtualenv primeiro ou gerenciar PATHvocê mesmo:

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

ou

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

e remova a EnvironmentFileentrada.

Para verificar se está realmente correto, você pode verificar sys.pathexecutando

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

e comparando a saída com

python -m site
Nils Werner
fonte
2
bom ponto Nils. A propósito, fooservice.py não faz sentido estar dentro do diretório venv_home, suponho que seja um erro de digitação na pergunta.
stelios
4
Observe que os comandos de impressão sugeridos não são compatíveis com Python 3. Se você estiver usando pelo menos o python 2.4, você pode, alternativamente, apenas usar: python -m sitepara obter uma saída bem formatada da variável sys.path junto com informações adicionais.
Mark Edington
2
Legal, eu não sabia python -m site. Eu ajustei minha resposta.
Nils Werner
1
@NilsWerner Eu acabei resolvendo isso gerando um shell, nada mais funcionou no Ubuntu 17.10: github.com/umccr/pcgr-deploy/blob/master/ansible/files/… ... por favor, ignore o modelo jinja2 para ansible, ele expande-se corretamente quando implantado.
brainstorm
6
Para aqueles que estão se perguntando se este é ninja2 .... não, as chaves duplas são apenas marcadores de posição que o OP inventou: superuser.com/questions/1209919/…
ankostis
12

Embora o caminho para as bibliotecas esteja realmente embutido no interpretador python do virtualenv, tive problemas com ferramentas python que usavam binários instalados nesse virtualenv. Por exemplo, meu serviço de fluxo de ar do Apache não funcionava porque não conseguia encontrar o gunicornbinário. Para contornar isso, aqui está minha ExecStartinstrução, com uma Environmentinstrução (que define uma variável de ambiente apenas para o serviço).

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

ExecStartusa explicitamente o interpretador python do virtualenv. Também estou adicionando uma PATHvariável, que adiciona a pasta binária do virtualenv antes do sistema PATH. Dessa forma, obtenho as bibliotecas Python desejadas, bem como os binários.

Observe que estou usando ansible para construir este serviço, logo as chaves de jinja2.

Alexis Lessard
fonte
1

Não estou usando virtualenv, mas pyenv: aqui está apenas para usar o caminho real .pyenv no shebang e certificar-se de que está no PATH

Ex: pyenv ativar flask-prod para o usuário mortenb que está sendo executado no prod

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

Então, aos meus scripts de flask começando em systemd * .service, adiciono o seguinte shebang:

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

No meu caso, apenas tentei adicionar variáveis ​​de ambiente necessárias para o Flask, por exemplo

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

Eu estava usando o virtualenv, então /xx/yy/zz/venv/biné o caminho da pasta virtualenv.

Sebastian Cardona Osorio
fonte