由于下学期要参与我川著名“内卷展览大会”——大创,前后端的一些表面功夫还是得了解一些,正好上个暑假用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 <xiaozilin1@gmail.com>
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 # 查看日志
Last modification:January 13th, 2020 at 07:48 pm
If you think my article is useful to you, please feel free to appreciate