Supervisor运行app_user时,Poetry安装包遇keyringrc.cfg权限错误
我有一个由supervisor管理、以app_user用户运行的应用。应用启动时会检查是否有新包,并通过Python脚本调用poetry安装,但报错:[Errno 13] Permission denied: '/root/.config/python_keyring/keyringrc.cfg'。
安装包的函数代码
import os import sys import subprocess import logging logger = logging.getLogger("general_log") def install_app_packages(): """ Run poetry install to update application packages """ python_path = sys.executable current_dir = os.path.dirname(os.path.realpath(__file__)) project_directory = os.path.dirname(current_dir) poetry_install_command = "poetry install --with prod --no-root" activate_path = f"{python_path[:-7]}/activate" export_poetry = 'export PATH="/opt/apps/venv/poetry/bin:$PATH"' full_command = f"{export_poetry} && source {activate_path} && {poetry_install_command}" try: subprocess.run( full_command, shell=True, cwd=project_directory, executable="/bin/ash" ) return True except Exception as e: logger.error(f"Error while running Poetry Install: {e.__str__()}") return False
详细错误信息
[2024-07-29 12:53:01 +0300] [24580] [INFO] Using worker: sync [2024-07-29 12:53:02 +0300] [24581] [INFO] Booting worker with pid: 24581 Installing dependencies from lock file Package operations: 1 install, 0 updates, 0 removals - Installing semver (3.0.2) PermissionError [Errno 13] Permission denied: '/root/.config/python_keyring/keyringrc.cfg' at /usr/lib/python3.11/pathlib.py:1013 in stat 1009│ """ 1010│ Return the result of the stat() system call on this path, like 1011│ os.stat() does. 1012│ """ → 1013│ return os.stat(self, follow_symlinks=follow_symlinks) 1014│ 1015│ def owner(self): 1016│ """ 1017│ Return the login name of the file owner. Cannot install semver. [2024-07-29 12:53:03 +0300] [24580] [ERROR] Worker (pid:24581) exited with code 3 [2024-07-29 12:53:03 +0300] [24580] [ERROR] Shutting down: Master [2024-07-29 12:53:03 +0300] [24580] [ERROR] Reason: Worker failed to boot.
可正常安装的两种情况
- 以app_user身份直接用gunicorn启动应用时,安装成功,命令为:
(poetry-venv)project_directory$ gunicorn --bind 0.0.0.0:8030 server.wsgi --error-logfile /tmp/gunicorn_error.log --access-logfile /tmp/gunicorn_access.log --preload - 将supervisor配置中的用户改为root(
user=root、group=root)时,安装也成功。
疑问
问题出在应用权限还是Poetry设置?为何脚本会尝试访问root目录下的keyringrc.cfg?这是否和权限配置有关?
问题根源
这是环境变量继承导致的权限问题,和Poetry本身设置无关。当通过supervisor以app_user运行时,进程可能继承了root用户的HOME环境变量,导致Python的keyring库误以为当前用户的家目录是/root,从而尝试访问该目录下的配置文件,而app_user没有权限访问root的家目录。
验证方式
直接用app_user启动时,HOME环境变量是app_user的实际家目录(比如/home/app_user);但通过supervisor启动时,检查进程的环境变量,大概率HOME被设成了/root。
解决方法
在supervisor配置中显式设置HOME环境变量
在supervisor的应用配置里添加:environment=HOME="/home/app_user"替换
/home/app_user为app_user实际的家目录路径。在Python脚本中手动指定HOME环境变量
在调用subprocess之前,修改环境变量:env = os.environ.copy() env["HOME"] = "/home/app_user" # 替换为app_user的实际家目录 subprocess.run( full_command, shell=True, cwd=project_directory, executable="/bin/ash", env=env )修正Poetry配置目录的权限
如果之前用root运行过Poetry,可能生成了root所属的配置文件,需要把Poetry的配置目录(通常是~/.config/pypoetry)的权限改为app_user:chown -R app_user:app_user /home/app_user/.config/pypoetry
两种正常情况的原因
- 直接用app_user启动gunicorn时,shell会正确设置
HOME为app_user的家目录,keyring访问正确路径,无权限问题。 - 用root运行时,进程本身有权限访问
/root目录,自然不会报错。
内容的提问来源于stack exchange,提问作者lukik

