Docker容器迁移后uWSGI运行报错"ImportError: No module named datetime"

在将Docker容器从主机A迁移到主机B之后,启动uwsgi服务后发现有报错

*** Operational MODE: preforking ***
Traceback (most recent call last):
  File "./my_django_app/wsgi.py", line 12, in <module>
    from django.core.wsgi import get_wsgi_application
  File "/home/admin/venv2/lib/python2.7/site-packages/django/__init__.py", line 3, in <module>
    from django.utils.version import get_version
  File "/home/admin/venv2/lib/python2.7/site-packages/django/utils/version.py", line 3, in <module>
    import datetime
ImportError: No module named datetime
unable to load app 0 (mountpoint='') (callable not found or import error)
*** no app loaded. going in full dynamic mode **

照理Docker容器迁移应该时完全一致才对,为何会出现找不到模块datetime呢?

此外,通过WEB访问显示错误Internal Server Error

尝试了两次迁移Docker容器,出现的报错信息完全一样。

排查

  • 去除uwsgi,直接通过Django访问是正常的

python manage.py runserver 0:8000

是什么原因导致的加载错误?

容器从主机A迁移到主机B,由于主机B上的用户uid/gid和主机A迁移过来的容器中uid/gid不同同,我曾经做过一次通过工具usermod和groupmod修改用户帐号名/uid/gid

不过,第二次尝试迁移Docker容器,没有执行过更改用户uid/gid,一样报错。

  • 尝试手工启动uwsgi:(my_django_app是Django项目)

cd my_django_app

uwsgi --socket /home/admin/venv2/sock --chmod-socket=664

有提示信息

*** Operational MODE: single process ***
*** no app loaded. going in full dynamic mode ***
*** uWSGI is running in multiple interpreter mode ***

访问web,再次出现Internal Server Error

参考 Serving Flask with Nginx

修改 my_django_app_uwsgi.ini

[uwsgi]

# Django-related settings
# the base directory (full path)
chdir           = /home/admin/my_django_app
# Django's wsgi file
app = my_django_app
module          = %(app)
# the virtualenv (full path)
home            = /home/admin/venv2

# process-related settings
# master
master          = true
# maximum number of worker processes
processes       = 10
# the socket (use the full path to be safe
socket          = /home/admin/venv2/sock
# ... with appropriate permissions - may be needed
# chmod-socket    = 664
# clear environment on exit
vacuum          = true

将其中的原先没有生效的段落(实际没有这个配置)

# Django's wsgi file
module          = my_django_app.wsgi

修改成

# Django's wsgi file
app = my_django_app
module          = %(app)

再次启动提示

*** Operational MODE: preforking ***
unable to load app 0 (mountpoint='') (callable not found or import error)
*** no app loaded. going in full dynamic mode ***

这个问题是因为参考Flask and uWSGI - unable to load app 0 (mountpoint='') (callable not found or import error)

因为uWSGI期望的变量名是application,这个变量在my_django_app/wsgi.py中可以看到

import os

from django.core.wsgi import get_wsgi_application

os.environ.setdefault("DJANGO_SETTINGS_MODULE", "my_django_app.settings")

application = get_wsgi_application()

参考 How to use Django with uWSGI 应该修改成:

# Django's wsgi file
module          = my_django_app.wsgi:application

此时报错重新出现:

*** Operational MODE: preforking ***
Traceback (most recent call last):
  File "./my_django_app/wsgi.py", line 12, in <module>
    from django.core.wsgi import get_wsgi_application
  File "/home/admin/venv2/lib/python2.7/site-packages/django/__init__.py", line 3, in <module>
    from django.utils.version import get_version
  File "/home/admin/venv2/lib/python2.7/site-packages/django/utils/version.py", line 3, in <module>
    import datetime
ImportError: No module named datetime
unable to load app 0 (mountpoint='') (callable not found or import error)
*** no app loaded. going in full dynamic mode ***

应该是Django加载datetime模块问题,是否我迁移容器时候出现了数据丢失?

my_django_app_uwsgi.ini中添加一行可以使得服务启动后后台运行,并生成日志

daemonize      = /home/admin/venv2/my_django_app.log

日志中报错同上

目前基本判断还是Docker迁移的问题,这次排查对daemonize方式运行uwsgi有了了解,另外摸索了Django的配置,看来官方文档配置是最准确的,还需要再改进改进。

重建virtualenv环境

ImportError: No module named datetime提到了解决方法,原因是操作系统升级以后导致的问题。

我的容器迁移应该没有操作系统变化才对。不过,virtualenv的环境中的python是2.7.14版本,而操作系统似乎升级过(当前是CentOS 5.11),python版本是2.4.3

mv ~/venv2 ~/venv2.bak

virtualenv venv2
source venv2/bin/activate

但是,我发现重新创建一次virtualenv虚拟环境,显示的Python版本依然是 2.7.14

  • 重新从项目中获取需要的模块重新安装

参考了 Rebuilding a Virtualenv 使用以下方法找出依赖的软件包:

source venv2.bak/bin/activate
cd my_project   # 进入项目目录
pip freeze > requirements.txt

然后重新安装需要的依赖

pip install -r requirements.txt

重新安装uwsgi

  • 安装uWSGI

pip install uwsgi

其他模块安装

经过重建virtualenv,以及重新安装了uwsgi之后,确实可以正确运行了。不过,我也发现使用pip freeze > requirements.txt并没有完全包含所有使用的模块。例如,使用到的django-url-filter没有列出,手工安装

pip install django-url-filter

参考

Last updated