【问题标题】:python import of local module failing when run as systemd/systemctl service当作为 systemd/systemctl 服务运行时,本地模块的 python 导入失败
【发布时间】:2016-06-09 01:26:59
【问题描述】:

我有一个 python 应用程序,我想将它作为系统服务运行。当我手动运行该应用程序时,它运行良好。当我将它作为服务运行时,它找不到使用pip install -e my_module 安装的本地模块。

应用程序的主要代码如下:

print(sys.argv)
import pip
installed_packages = pip.get_installed_distributions()
installed_packages_list = sorted(["%s==%s" % (i.key, i.version) for i in installed_packages])
print(installed_packages_list)
print('doing tox')
import tox
print('doing my_mod')
import my_mod
print(my_mod.__file__)
from my_mod.auth.http_auth_provider import HTTPAuthProvider

当我手动运行它时,我得到(注意 my-mod 包含在“已安装包”的第二行):

['/usr/bin/pv_api']
['aiohttp==0.19.0', 'chardet==2.3.0', 'jsonschema==2.5.1', 'pip==7.0.0', 'pluggy==0.3.1', 'pv-api==0.0.0', 'py==1.4.31', 'pycrypto==2.6.1', 'pymongo==3.1.1', 'pyyaml==3.11', 'setuptools==19.6.2', 'six==1.10.0', 'tox==2.3.1', 'virtualenv==14.0.6', 'my-mod==0.1.0', 'webauthsession==1.1.1']
doing tox
doing my_mod
/root/my_module/my_mod/__init__.py

通过服务运行时,日志如下所示(注意 my-mod 不包含在“已安装包”的第二行)::

2016-02-26_00:39:01.90403 ['/usr/bin/pv_api']
2016-02-26_00:39:01.90406 ['aiohttp==0.19.0', 'chardet==2.3.0', 'jsonschema==2.5.1', 'pip==7.0.0', 'pluggy==0.3.1', 'pv-api==0.0.0', 'py==1.4.31', 'pycrypto==2.6.1', 'pymongo==3.1.1', 'pyyaml==3.11', 'setuptools==19.6.2', 'six==1.10.0', 'tox==2.3.1', 'virtualenv==14.0.6', 'webauthsession==1.1.1']
2016-02-26_00:39:01.90407 doing tox
2016-02-26_00:39:01.90407 doing my_mod
2016-02-26_00:39:01.90642 Traceback (most recent call last):
2016-02-26_00:39:01.90642   File "/usr/bin/pv_api", line 9, in <module>
2016-02-26_00:39:01.90642     load_entry_point('pv-api==0.0.0', 'console_scripts', 'pv_api')()
2016-02-26_00:39:01.90643   File "/usr/lib/python3.4/site-packages/pkg_resources/__init__.py", line 547, in load_entry_point
2016-02-26_00:39:01.90643     return get_distribution(dist).load_entry_point(group, name)
2016-02-26_00:39:01.90643   File "/usr/lib/python3.4/site-packages/pkg_resources/__init__.py", line 2719, in load_entry_point
2016-02-26_00:39:01.90643     return ep.load()
2016-02-26_00:39:01.90643   File "/usr/lib/python3.4/site-packages/pkg_resources/__init__.py", line 2379, in load
2016-02-26_00:39:01.90643     return self.resolve()
2016-02-26_00:39:01.90643   File "/usr/lib/python3.4/site-packages/pkg_resources/__init__.py", line 2385, in resolve
2016-02-26_00:39:01.90644     module = __import__(self.module_name, fromlist=['__name__'], level=0)
2016-02-26_00:39:01.90644   File "/usr/lib/python3.4/site-packages/pv/api/main.py", line 33, in <module>
2016-02-26_00:39:01.90644     import my_mod
2016-02-26_00:39:01.90644 ImportError: No module named 'my_mod'

这也可能是有用的信息:

[root@7bb8a6866a85 etc]# ls -la /usr/lib/python3.4/site-packages/my-mod.egg-link 
-rw-r--r-- 1 root root 37 Feb 26 00:20 /usr/lib/python3.4/site-packages/my-mod.egg-link
[root@7bb8a6866a85 etc]# cat /usr/lib/python3.4/site-packages/my-mod.egg-link 
/root/my_module

编辑:

正如您从“installed_pa​​ckages”的输出中看到的那样,通过 requirements.txt 安装的所有其他软件包都正确找到。当我作为服务运行时,找不到我在本地拥有源代码的这个库。 (当我从命令行运行或从 python3 解释器运行import my_mod 时会发现它。

【问题讨论】:

    标签: python python-import systemd


    【解决方案1】:

    我在将新贵heartbeat.conf 转换为systemd heartbeat.service 时遇到了非常相似的问题,requests 模块除外。解决方案是在新的 .service 中指定运行它的用户:

    [Unit]
    Description=web server monitor
    
    [Service]
    WorkingDirectory=/home/<user>/
    User=<user>
    ExecStart=/home/<user>/heartbeat.py
    Restart=always
    
    [Install]
    WantedBy=multi-user.target
    

    没有User=&lt;user&gt;,我进入了journalctl:

    systemd[1]: Started web server monitor.
    heartbeat.py[26298]: Traceback (most recent call last):
    heartbeat.py[26298]:   File "/home/<user>/heartbeat.py", line 2, in <
    heartbeat.py[26298]:     import requests
    heartbeat.py[26298]: ImportError: No module named requests
    systemd[1]: heartbeat.service: Main process exited, code=exited, status=1/FAILURE
    systemd[1]: heartbeat.service: Unit entered failed state.
    

    【讨论】:

    • 注意是User=&lt;user&gt;。值取决于用户名!
    • @kuga 好点。我已经更新了答案以反映这一点。
    【解决方案2】:

    将 python 站点包环境变量添加到 systemctl *.服务文件

    [Unit]
    Description=web server monitor
    
    [Service]
    WorkingDirectory=/home/user/
    User=user
    ExecStart=/home/user/heartbeat.py
    Restart=always
    Environment="PYTHONPATH=$PYTHONPATH:/home/nvidia/.local/lib/python3.6/site-packages"
    
    [Install]
    WantedBy=multi-user.target
    
    

    【讨论】:

    • 这对我有用,一旦我设置了环境路径,一切正常。谢谢。
    【解决方案3】:

    首先在 python 提示符下尝试以下操作。

    $ python
    >>> import my_mod
    Traceback (most recent call last):
    File "<stdin>", line 1, in <module>
    ImportError: No module named my_mod
    >>>
    

    修复 1

    如果您得到上述类型的输出,那么原因可能是由于权限问题。使用以下命令授予站点包的权限。

    sudo chmod -R go+rX /usr/local/lib/python2.7/dist-packages
    

    修复 2

    尝试如下导出 PYTHONPATH:

    export PYTHONPATH="/usr/.local/lib/python2.7/site-packages"
    

    修复 3

    检查是否有多个版本的python在同一台机器上运行。

    如果是,请检查代码开头是否包含正确的解释器,例如#!/usr/bin/python

    【讨论】:

    • 这非常接近于突出真正的问题。问题是该服务是以对安装我的模块的文件夹没有读取权限的用户身份运行的。
    【解决方案4】:

    如果您确实想以 root 身份运行该服务,则必须使用 sudo 安装模块:sudo pip install my_module

    【讨论】:

      【解决方案5】:

      1) 安装supervisor 包(more verbose instructions here):

      sudo apt-get install supervisor
      

      2) 在/etc/supervisor/conf.d/my_mod.conf 为您的守护程序创建一个配置文件:

      [program:my_mod]
      directory=/path/to/project/root
      environment=ENV_VARIABLE=example,OTHER_ENV_VARIABLE=example2
      command=python my_mod.py
      autostart=true
      autorestart=true
      

      3) 重启supervisor 以加载新的.conf

      supervisorctl update
      supervisorctl restart my_mod
      

      【讨论】:

      • 服务已安装。问题是python选择的环境不包含这个库。通过需求文件安装的所有其他库都可以正确找到。
      • 在导入 my_mod 之前添加这一行 sys.path.append("/root/my_module/my_mod") 怎么样?
      【解决方案6】:

      由于您的 python 脚本使用python3.4 执行,您的问题很可能是使用pip 而不是pip3(或者可能是sudo -H pip3)。

      但是,由于您还特别询问如何使用 systemd 服务中的 python 模块,我建议尽可能使用 aptsudo,而不是弄乱 pip(因引入文件权限问题而臭名昭著):

      sudo apt install python3-my_module
      

      【讨论】:

        【解决方案7】:

        我也遇到了导入错误,但我的不是本地导入。我的包没有正确导入。查看服务失败日志*

        Feb 11 06:41:52 pl-dev-demo-1 python3[1675804]:     from foo import test
        Feb 11 06:41:52 pl-dev-demo-1 python3[1675804]: ModuleNotFoundError: No module named 'foo'
        Feb 11 06:41:52 pl-dev-demo-1 systemd[1]: xyzxyz.service: Main process exited, code=exited, status=1/FAILURE
        

        我浪费了很多时间去弄清楚,然后我尝试了这种方法,效果很好。

        在模块中我设置了我的代码路径:

        import sys
        sys.path.append('path_of_my_code_parent_package')
        
        from foo import test 
        

        阅读此文档:

        Setting PYTHONPATH more permanently

        【讨论】:

          【解决方案8】:

          我遇到了同样的问题。我认为pip install 必须是特定于用户的。
          所以我切换到root,然后安装包。之后就成功了。

          但是,我认为在服务文件中指定 User=myUser 会更合适,但是,我希望它以 root 权限运行,但我不确定在指定用户时是否会这样做。

          希望对某人有所帮助

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2017-08-01
            • 2018-04-06
            • 1970-01-01
            • 1970-01-01
            • 2021-04-10
            • 2020-10-22
            • 2017-08-27
            • 1970-01-01
            相关资源
            最近更新 更多