如何在 systemd 服务单元中启用 virtualenv?
How to enable a virtualenv in a systemd service unit?
我想在 systemd 服务文件中“激活”一个 virtualenv。
我想避免在 systemd 进程和 python 解释器之间有一个 shell 进程。
我目前的解决方案是这样的:
[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 }}
但是我遇到了麻烦。我收到 ImportErrors,因为 sys.path
中的一些条目丢失了。
virtualenv 是 "baked into the Python interpreter in the virtualenv"。这意味着您可以直接在该 virtualenv 中启动 python
或 console_scripts
,而无需先激活 virtualenv 或自行管理 PATH
。:
ExecStart={{ venv_home }}/bin/fooservice --serve-in-foreground
或
ExecStart={{ venv_home }}/bin/python {{ venv_home }}/fooservice.py --serve-in-foreground
并删除 EnvironmentFile
条目。
要验证它确实正确,您可以通过 运行
检查 sys.path
{{ venv_home }}/bin/python -m site
并将输出与
进行比较
python -m site
我使用的不是 virtualenv,而是 pyenv:这里只是为了在 shebang 中使用真实的 .pyenv 路径,并确保它在 PATH 中
例如:pyenv 为用户 mortenb 激活 flask-prod,它是 运行 in prod
/home/mortenb/.pyenv/versions/flask-prod/bin/python --version
Python 3.6.2
然后在以 systemd *.service 开始的烧瓶脚本中添加以下 shebang:
#!/home/mortenb/.pyenv/versions/flask-prod/bin/python3
虽然库的路径确实嵌入到 virtualenv 的 python 解释器中,但我遇到了 python 使用安装在该 virtualenv 中的二进制文件的工具的问题。例如,我的 apache airflow 服务无法工作,因为它找不到 gunicorn
二进制文件。要解决此问题,请使用我的 ExecStart
指令和 Environment
指令(单独为服务设置环境变量)。
ExecStart={{ virtualenv }}/bin/python {{ virtualenv }}/bin/airflow webserver
Environment="PATH={{ virtualenv }}/bin:{{ ansible_env.PATH }}"
ExecStart
显式使用 virtualenv 的 python 解释器。我还添加了一个 PATH
变量,它在系统 PATH
之前添加了 virtualenv 的二进制文件夹。这样,我就得到了所需的 python 库和二进制文件。
请注意,我正在使用 ansible 来构建此服务,因此请注意 jinja2 的大括号。
在我的例子中,我只是尝试添加 Flask 所需的环境变量,例如
[Service]
Environment="PATH=/xx/yy/zz/venv/bin"
Environment="FLASK_ENV=development"
Environment="APP_SETTINGS=config.DevelopmentConfig"
我使用的是 virtualenv,所以 /xx/yy/zz/venv/bin
是 virtualenv 文件夹的路径。
我想在 systemd 服务文件中“激活”一个 virtualenv。
我想避免在 systemd 进程和 python 解释器之间有一个 shell 进程。
我目前的解决方案是这样的:
[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 }}
但是我遇到了麻烦。我收到 ImportErrors,因为 sys.path
中的一些条目丢失了。
virtualenv 是 "baked into the Python interpreter in the virtualenv"。这意味着您可以直接在该 virtualenv 中启动 python
或 console_scripts
,而无需先激活 virtualenv 或自行管理 PATH
。:
ExecStart={{ venv_home }}/bin/fooservice --serve-in-foreground
或
ExecStart={{ venv_home }}/bin/python {{ venv_home }}/fooservice.py --serve-in-foreground
并删除 EnvironmentFile
条目。
要验证它确实正确,您可以通过 运行
检查sys.path
{{ venv_home }}/bin/python -m site
并将输出与
进行比较python -m site
我使用的不是 virtualenv,而是 pyenv:这里只是为了在 shebang 中使用真实的 .pyenv 路径,并确保它在 PATH 中
例如:pyenv 为用户 mortenb 激活 flask-prod,它是 运行 in prod
/home/mortenb/.pyenv/versions/flask-prod/bin/python --version
Python 3.6.2
然后在以 systemd *.service 开始的烧瓶脚本中添加以下 shebang:
#!/home/mortenb/.pyenv/versions/flask-prod/bin/python3
虽然库的路径确实嵌入到 virtualenv 的 python 解释器中,但我遇到了 python 使用安装在该 virtualenv 中的二进制文件的工具的问题。例如,我的 apache airflow 服务无法工作,因为它找不到 gunicorn
二进制文件。要解决此问题,请使用我的 ExecStart
指令和 Environment
指令(单独为服务设置环境变量)。
ExecStart={{ virtualenv }}/bin/python {{ virtualenv }}/bin/airflow webserver
Environment="PATH={{ virtualenv }}/bin:{{ ansible_env.PATH }}"
ExecStart
显式使用 virtualenv 的 python 解释器。我还添加了一个 PATH
变量,它在系统 PATH
之前添加了 virtualenv 的二进制文件夹。这样,我就得到了所需的 python 库和二进制文件。
请注意,我正在使用 ansible 来构建此服务,因此请注意 jinja2 的大括号。
在我的例子中,我只是尝试添加 Flask 所需的环境变量,例如
[Service]
Environment="PATH=/xx/yy/zz/venv/bin"
Environment="FLASK_ENV=development"
Environment="APP_SETTINGS=config.DevelopmentConfig"
我使用的是 virtualenv,所以 /xx/yy/zz/venv/bin
是 virtualenv 文件夹的路径。