Docker + uWSGI + nginx + MySQL + Django 论Django Web生产环境的最佳搭配

由于下学期要参与我川著名“内卷展览大会”——大创,前后端的一些表面功夫还是得了解一些,正好上个暑假用django开发的小项目在学期末尝试性地上线生产环境试运行了一小会,期间也折腾了不少方案,这里给出一套成熟的Django Web生产环境的配置供大家参考:docker + uwsgi + nginx + mysql + Django。

Docker

Docker作为一款简单易用的容器化技术,广受开发人员喜爱。在我们这套方案中,我们将利用docker-compose搭建两个容器:web和db,其中web中运行uWSGI+nginx+Django,db中运行MySQL。

Dockerfile

下面给出web的Dockerfile供参考:

FROM centos:7 MAINTAINER MrZilinXiao ENV TZ "Asia/Shanghai" ENV DOCKER_SRC=SCUCourseKiller ENV DOCKER_HOME=/root ENV DOCKER_PROJECT=/root/SCUCourseKiller WORKDIR $DOCKER_HOME RUN mkdir SCUCourseKiller RUN yum -y install epel-release yum-utils && \ yum -y install git nginx gcc gcc-c++ crontabs && \ yum -y install python36 python36-devel python36-pip && \ yum clean all RUN yum -y install mariadb-devel mysql-devel WORKDIR $DOCKER_PROJECT COPY ./ ./ RUN pip3 install -i https://pypi.tuna.tsinghua.edu.cn/simple -r requirements.txt --default-timeout=100 EXPOSE 8000 RUN chmod u+x start_script ENTRYPOINT ["./start_script"]

可以看见,build基于centos,安装好必要的依赖包之后直接通过yum安装了python3.6,将当前目录文件全部拷贝进docker后又用pip安装了依赖,最后运行start_script这个shell文件。

start_script

#!/bin/bash export LANG="en_US.UTF-8" # nginx settings sed -i '/user/{s/nginx/root/}' /etc/nginx/nginx.conf ln -s /root/SCUCourseKiller/mysite_nginx.conf /etc/nginx/conf.d/ nginx # application settings export DJANGO_SETTINGS_MODULE=SCUCourseKiller.settings python3 ./manage.py makemigrations python3 ./manage.py migrate --noinput python3 ./manage.py loaddata ./fixtures/superuser.json python3 ./manage.py collectstatic --noinput uwsgi --ini ./mysite_uwsgi.ini

start_script文件主要完成docker运行的初始化任务,包括建立nginx配置文件的软链接、数据库的migration和管理员用户的导入(可省略)、uWSGI的运行。

docker-compose

docker-compose是一款辅助docker管理的小工具,可以很方便地配置docker镜像、实现容器管理,特别是对依赖关系的管理。

docker-compose的配置文件为yaml格式,对缩进格式要求极其严格,且这类错误不好检查,故在出现错误时建议使用第三方检查工具。

version: '3.3' services: db: container_name: mymysql image: mysql:5.7 restart: always environment: MYSQL_DATABASE: SCUCourseKiller MYSQL_USER: root MYSQL_PASSWORD: SCUCourseKiller MYSQL_ROOT_PASSWORD: SCUCourseKiller command: mysqld --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci --init-connect='SET NAMES utf8mb4;' --innodb-flush-log-at-trx-commit=0 ports: - 3306:3306 volumes: - "./SCUKiller/mysql/config:/etc/mysql/conf.d" restart: always container_name: SCUCourseKiller build: ./ command: ["./wait-for-it.sh", "db:3306"] ports: - 8000:8000 depends_on: - db links: - db

将以上内容与Dockerfile放置在同级目录下,其中需要注意的参数有:

  • restart:容器重启后是否跟随重启。
  • volumes:指出本地与容器的卷挂载关系,本次只在db容器中设置了挂载,用于加载自定义的mysql配置文件my.cnf,后续数据库配置过程会提及。
  • command:容器启动前执行的命令,这项命令的优先级在Dockerfile的ENTRYPOINT之前,可以结合wait-for-it.sh实现在特定端口开放前的阻塞,避免数据库未加载完成就载入Django导致错误。
  • depends_on:依赖关系的简单设定,决定build和run时运行的先后顺序。注意,运行先后顺序的确定与上面的wait-for-it.sh并不冲突,这里的顺序并不阻塞,即Docker并不会等到MySQL完全启动完成后再开始启动Django。
  • links:配置Docker之间网络关系的简单配置,将直接将两个容器放置在bridge中。复杂的网络关系配置可以通过与services同级的networks配置项配置。e.g.:
networks: killerNet: driver: bridge ipam: config: - subnet: 172.19.0.0/16

uWSGI

uWSGI是一个简易的Web主机,在此项目中作为Nginx与Django之间的中间件用于更好地处理多并发。其与nginx可以采用本地端口或sock文件通信,与Django则采用WSGI接口通信。

mysite_uwsgi.ini文件:

[uwsgi] # Django-related settings # the base directory (full path) chdir = /root/SCUCourseKiller # Django's wsgi file module = SCUCourseKiller.wsgi # the virtualenv (full path) # home = /path/to/virtualenv # /process-related settings # master # master = true # maximum number of worker processes processes = 2 enable-threads = true # the socket (use the full path to be safe) socket = /root/SCUCourseKiller/SCUCourseKiller/docker_app.sock # ... with appropriate permissions - may be needed chmod-socket = 666 # clear environment on exit vacuum = true

nginx

nginx的配置主要注意与uWSGI的通信即可,其余则需要注意static、media路径的转发:

# mysite_nginx.conf upstream django { server unix:///root/SCUCourseKiller/SCUCourseKiller/docker_app.sock; } # configuration of the server server { # the port your site will be served on, default_server indicates that this server block # is the block to use if no blocks match the server_name listen 8000 default_server; # the domain name it will serve for server_name 0.0.0.0; # substitute your machine's IP address or FQDN charset utf-8; # max upload size client_max_body_size 75M; # adjust to taste access_log /root/SCUCourseKiller/log/access.log main; error_log /root/SCUCourseKiller/log/error.log info; # Django media location /media { alias /root/SCUCourseKiller/media; # your Django project's media files - amend as required } location /static { alias /root/SCUCourseKiller/static; # your Django project's static files - amend as required } # Finally, send all non-media requests to the Django server. location / { uwsgi_pass django; # for a file socket include /root/SCUCourseKiller/uwsgi_params; # the uwsgi_params file you installed } }

MySQL

MySQL的配置在Docker中略有提及,主要包括MySQL在初始化设置时需要配置库名、用户名和密码并更改编码格式以支持中文。为实现修改并发连接数等高级操作,我们可以自定义my.cnf配置文件并挂载至容器中特定目录即可。

# my.cnf

[mysqld]

character-set-server=utf8mb4 default-time-zone=’+8:00′ innodb_rollback_on_timeout=’ON’ max_connections=1024 innodb_lock_wait_timeout=15

Django

首先确保通过python manage.py runserver可以成功启动Debug模式主机,随后将settings.py中的DEBUG设为false。centos7中安装完python后并没有django等依赖包,需要自行设置requirements.txt文件:

mysqlclient retrying Django==2.1.8 Pillow==5.3.0 requests==2.19.1 urllib3==1.23 uwsgi

开发、运行与生产上线

每次修改完代码后,可通过centos中的git pull同步或者直接在docker中通过docker exec -it [Docker Hash或容器名称] /bin/bash进入容器,用vi修改。

本地测试与上线时:

docker-compose build # 构建容器 docker-compose start -d # 以daemon守护模式启动 docker-compose logs -f # 查看日志

推荐站内搜索:什么叫ip地址、云主机、独立ip空间、备案域名查询、免费永久虚拟主机、云服务器、香港最好虚拟主机、ip代理服务器、网站域名ip地址查询、全能虚拟主机、