使用 Docker 运行 Django 项目
以前运行 Django 项目的方式是在虚拟机上运行(uwsgi+Django),如果要运行多个不同版本的 Django 项目就蛋疼了,当然也可以使用 virtualenv 虚拟环境工具,但是我觉得用起来比较麻烦,尤其是需要自动化的时候。
Docker 除了众所周知的一些特性之外,最基本的特性就是环境隔离。在虚拟机上运行 Docker 固然对性能没什么提升,但是单纯的用作任务编排也是很好的(尤其想要结合自动化脚本)。下面就介绍一下如何使用 Docker 运行 Django 项目。
安装 Django,并创建项目:
pip3 install django django-admin --version # 2.1.1 django startproject demo
因为我使用 Python3 运行,所以要将 demo/manage.py
中的运行环境改为 Python3, #!/usr/bin/env python
=> #!/usr/bin/env python3
,然后:
./manage.py migrate ./manage.py runserver
默认情况下,连接的 DB 是 SQLite,为了保证我们运行的服务是无状态的,所以把 DB 改为 MySQL,通过远程连接的方式。在本地运行 MySQL:
docker pull mysql:5.7 docker images # 6a834f03bd02 docker run --name dj-mysql -d -e MYSQL_ROOT_PASSWORD=my-secret -p 127.0.0.1:3306:3306 6a834f03bd02 docker ps -a # CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES # 390ac3e7d3ab 6a834f03bd02 "docker-entrypoint.s…" About a minute ago Up About a minute 127.0.0.1:3306-> 3306/tcp, 33060/tcp dj-mysql docker exec -it 390ac3e7d3ab mysql -uroot -pmy-secret mysql> create database demo charset="utf8mb4"; # 创建数据库 Query OK, 1 row affected (0.30 sec) mysql> ^DBy
接下来将 Django 连接 DB 方式改为 MySQL:
DATABASES = { # 'default': { # 'ENGINE': 'django.db.backends.sqlite3', # 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), # } 'default': { 'ENGINE': 'django.db.backends.mysql', 'NAME': 'demo', 'USER': 'root', 'PASSWORD': 'my-secret', 'HOST': 'mysql', 'PORT': '3306', } }
编写 Dockerfile:
FROM python:3 RUN mkdir /data WORKDIR /data ADD requirements.txt /data/ RUN pip install --no-cache-dir -r requirements.txt -i https://pypi.douban.com/simple ADD . /data CMD ["python3", "manage.py", "runserver", "0.0.0.0:8080"]
requirements
包含 django
和 mysqlclient
。
打包镜像:
docker build -t demo:v1.0 .
查看镜像ID,并启动容器:
docker run -it -d --link dj-mysql:mysql -p 127.0.0.1:8003:8080 be691f1720c3
*注意*:为了使用 mysql 需要以
--link
的方式把两个容器连接起来,你也可以使用 network 的方式。
然后浏览器访问:127.0.0.1:8003 ,就可以看到熟悉的欢迎界面了。
以 runserver
的方式是多个线程运行的(1.11 源代码中是两个线程),生产环境下建议使用 uwsgi,uwsgi 可以明显的控制进程数量。
添加 uwsgi.ini 文件到目录下:
[uwsgi] wsgi-file = demo/wsgi.py http = 0.0.0.0:8080 master = true workers = 2 procname-master = uwsgi master procname = uwsgi worker reload-mercy = 8 vacuum = true enable-threads = True lazy-apps = True
这里有两点要注意:
- uwsgi 需要在前台运行(这和 Docker 的运行机制有关),所以不要设置
daemonize2
选项 - Dockerfile 中已经设置了 WORKDIR,就不需要再 uwsgi 中再做
chdir
这样的操作
此时 Dockerfile 为(要将 uwsgi 添加到 requirements.txt 文件中):
FROM python:3 RUN mkdir /data WORKDIR /data ADD requirements.txt /data/ RUN pip install --no-cache-dir -r requirements.txt -i https://pypi.douban.com/simple ADD . /data CMD ["uwsgi", "--ini", "uwsgi.ini"]
重新打包镜像,然后运行即可。
btw,如果仅在本地测试的话 docker-compose
要更方便一些,DB 和 Django 同时启动,并且可以服务发现。
上面只是一个例子,项目实战还需要考虑:
- 设置
.dockerignore
,无关的文件不要打包到镜像中,比如Dockerfile
,__pycache__
- 可变的信息以环境变量的方式注入,比如数据库的 host、账号密码等
- 基础镜像
python:3
有完整的依赖,所以有九百多兆之大,实际项目建议使用python:3-alpine
来替代做为一个基础镜像(不到一百兆),需要的依赖再手动安装一下