使用 Docker 部署 Django Web server 最佳实践

Table of Contents

2018 年 9 月 8 日,我写了 Docker 运行 Django 项目,随着自己对 Docker 的更深一步了解,以及在 [qwerty](https://github.com/zhangjie2012/qwerty) 项目中的实践,感觉之前写的略有不足。这篇文章进行一定的补充说明。

1 使用 Supervisor

在虚拟机上部署 Django 项目,一般使用的是 uwsgi,但是在容器中运行的服务必须有一个前台进程,所以在之前的文章中去掉了 uwsgi 的 daemonize2 选项,uwsgi 日志相关的配置也都删除了(因为要跑到前台),所以 uwsgi 的日志相当于是打在了标准输出上。 虽然这符合 Docker 的规范,但是在项目上线运行调试的过程中,uwsgi 的日志最好能够保留下来,打印到标准输出,Docker 重启时就不存在了。

Supervisor 是 Python 写的一个进程控制系统,可以很方便的启动、重启、关闭进程。我们可以使用 Supervisor 来管理 uwsgi 进程,然后使得 Supervisor 跑在前台即可。 如果有多个进程需要运行在容器中,也可以使用 Supervisor,比如常见的 nginx+uwsgi 。配置比较简单:

[program:app-uwsgi]
command = /usr/local/bin/uwsgi --ini /code/uwsgi.ini

然后在 Docker 启动命令设为 supervisord -n-n for run in the foreground)。拓展阅读:Run multiple services in a container

2 服务参数传递

Web 服务会有一些参数要设置,比如 DB,缓存的地址、账号、密码等,以及日志的输出路径等等,Docker 部署时建议可变参数已环境变量( --env )的方式注入,但是实际操作中发现服务配置项往往与预期的要多,使用环境的方式启动命令会很长,很容易搞错,不容易维护。 所以,将所以的服务配置项,使用 yml 文件维护,启动时挂载配置文件到容器指定目录下即可。

3 设置 bind mounts

一些需要落地宿主机的文件,最常见的为服务日志,使用 bind mounts( --mounts )日志目录映射到宿主机(按照固定的目录规则,也方面后期日志收集),上面所有的服务配置文件也可以 mount 到容器中;

4 将 migrate 在启动脚本中执行

使用 Django 经常会需要 migrate ,在容器启动后,手动进入容器中执行 migrate 非常麻烦。好在 Dockerfile 中的 ENTRYPOINT~,~CMD 运行直接指定一个启动脚本,以应对复杂的服务启动。 实际操作也比较简单,写一个 startup.sh 脚本,内部执行 migrate 然后启动服务即可。

5 对上篇文章的纠正

  1. 使用 --network 而不是 --link--link 将被 Docker 废弃,network 的方式功能更强大,也比 --link 好用,具体见:Legacy container links
  2. 实际项目直接选择 python:3 ,虽然使用 python:3-alpine 看似镜像很小,但安装了众多依赖后(python-dev),大小也差不了多少。而且我尝试基于 python:3-alpine 安装 mysqlclient 库时没成功;

qwerty 项目覆盖了上面所有的实践,不太清楚的地方,直接看代码即可。

Date: 2019-03-03 15:13

Author: JerryZhang