# 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](https://github.com/huataihuang/cloud-atlas-draft/tree/6f3204fffc11cf006abd394631e2598d98b415c3/develop/shell/utilities/usermod_groupmod/README.md)
>
> 不过，第二次尝试迁移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](http://vladikk.com/2013/09/12/serving-flask-with-nginx-on-ubuntu/)

修改 `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)](https://stackoverflow.com/questions/12030809/flask-and-uwsgi-unable-to-load-app-0-mountpoint-callable-not-found-or-im)

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

```python
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](https://docs.djangoproject.com/en/2.0/howto/deployment/wsgi/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](https://stackoverflow.com/questions/26031160/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](https://help.pythonanywhere.com/pages/RebuildingVirtualenvs/) 使用以下方法找出依赖的软件包：

```bash
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
```

## 参考

* [ImportError: No module named datetime](https://stackoverflow.com/questions/26031160/importerror-no-module-named-datetime)


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://huataihuang.gitbook.io/cloud-atlas-draft/service/nginx/uwsgi_django_no_module_named_datetime.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
