一文看懂Django项目部署

欢迎来我的个人网站查看原文

文章目录

  • 部署Django项目
    • 安装配置 MySQL
      • 安装
      • 创建一个专门的用户
      • (optional) 运行远程连接
    • 安装 Nginx
      • 配置
    • 配置 Django
      • 修改setting文件
      • 收集静态文件
      • (optional) migrate
    • 安装 gunicorn
    • (Optional) 后期维护
    • (Optional) 安装配置 Cron
      • 下载+启动
      • 常用操作
      • 简单例子

部署Django项目

  • 运行环境:Ubuntu 20 (版本影响不大)
  • 软件:MySQL (后端数据库) + Nginx (代理请求) + gunicorn (托管运行Django程序)

以下所有内容都假设你已经配置好了pip和virtualenv虚拟环境,不是的话可以运行如下指令

# install pip
sudo apt-get install python3-pip
# install virtualenv
sudo pip3 install virtualenv
# create virtual environment
python3 -m virtualenv venv
# activate
source venv/bin/activate

安装配置 MySQL

安装

参考: https://www.digitalocean.com/community/tutorials/how-to-install-mysql-on-ubuntu-20-04

# update the package
sudo apt update
# install MySQL
sudo apt install mysql-server
# config the MySQL e.g. set the password of root user (important!)
sudo mysql_secure_installation

创建一个专门的用户

为了安全起见,我们应该给每一个应用程序创建一个独立的数据库账号,并且限制该账号只能操作对应的数据库(权限管理)。这样主要是为了防止由于一个应用程序的漏洞导致黑客可以访问所有的数据。

# login to mysql as root
sudo mysql
# if you want remote connection, set host to '%'
CREATE USER ''@'' IDENTIFIED BY '';
# (optional) create a new DB for Django
CREATE DATABASE <name>;
# grant all privileges to all tables in  database
GRANT ALL PRIVILEGES ON <name>.* TO ''@'';
# update
FLUSH PRIVILEGES;
exit

为了测试是否创建成功,我们可以

 # start the server
systemctl status mysql.service
# check user creation
# method 1
sudo mysqladmin -p -u <username> version
# method 2
mysql -u <username> -p
use <name of database>;

(optional) 运行远程连接

有时候我们希望能远程连接到数据库上面(如:本地运行程序,使用服务器上面的数据)

参考: https://www.digitalocean.com/community/tutorials/how-to-allow-remote-access-to-mysql

  1. sudo emacs /etc/mysql/mysql.conf.d/mysqld.cnf
  2. change bind-address from 127.0.0.1 to 0.0.0.0
  3. test with mysql -u -h -p

安装 Nginx

Nginx是用于反向代理的,可以加快我们网站的访问速度,一些静态资源的重复请求Nginx就可以处理而不需要发到后端程序重复处理,比如用户A访问了图片1,这时候假如用户B也要访问图片1,那么Nginx就会直接返回图片1而不会向后端再请求一次。

基本的安装和启动语法如下:

# install nginx
sudo apt-get install nginx
# start the nginx
sudo service nginx start
# reload/restart nginx (after modified the config)
sudo service nginx reload # only reload the config
# or
sudo service nginx restart # restart the nginx

# test nginx.conf syntax
nginx -t

配置

进入/etc/nginx/sites-available创建一个新的文件(如:blog.config,后缀不重要,没有后缀也可以),写入如下内容(将所有<>中的内容换为你的实际路径)

http访问

server {
  charset utf-8;
  # listen on port 80
  listen 80;
  server_name ;

  location /static {
    # e.g. /home/user1/blog/blog
    alias /staticfiles;
  }

  location /media {
    alias /media;
  }

  location / {
    proxy_set_header Host $host;
    # proxy_pass http://unix:/tmp/.socket;
    # redirect URL (the URL django is listening to)
    proxy_pass http://127.0.0.1:8000;
  }
}

现在很多网站都支持HTTPS访问,假如希望开启https并将所有http的重定向到https的话可以这样写:

https访问

server {
    listen 80;
    server_name ;
    # rewrite the URL to https
    rewrite ^(.*)$ https://${server_name}$1 permanent;
}

server {
  charset utf-8;
  listen 443 ssl;
  server_name xiakewei.com;

  # usually we can put them in '/etc/ssl'
  ssl_certificate <.crt文件路径>;
  ssl_certificate_key <.key文件路径>;

  location /static {
    alias /staticfiles;
  }

  location /media {
    alias /media;
  }

  location / {
    proxy_set_header X-Forwarded-Proto https;
    proxy_set_header Host $host;
    # proxy_pass http://unix:/tmp/.socket;
    proxy_pass http://127.0.0.1:8000;
  }
}

链接该文件到/etc/nginx/sites-enabled

cd /etc/nginx/sites-enabled
sudo ln -s ../sites-available/blog.config .

可以顺便删掉default文件(注意reload一下Nginx使得修改被应用)

如果你需要多个config(如:服务器上运行了多个Web程序),你可以为每个程序创建一个config文件(注意端口不要冲突),然后都链接到/etc/nginx/sites-enabled里面。

配置 Django

修改setting文件

找到/settings.py文件,修改以下内容:

# 禁用DEBUG模式
#(不然出错的时候会显示详细的错误信息,给黑客提供了额外信息)
DEBUG = False

# 将服务器的地址放到允许列表里面
ALLOWED_HOSTS = ['']

# Django会将所有的静态文件(如css,图片)统一放置到这个路径下面(Nginx访问的也是这个路径)
STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles')

# 配置HTTPs访问
SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')
SECURE_SSL_REDIRECT = True
SESSION_COOKIE_SECURE = True
CSRF_COOKIE_SECURE = True
CSRF_TRUSTED_ORIGINS = ['']
SECURE_HSTS_SECONDS = 31536000
SECURE_HSTS_INCLUDE_SUBDOMAINS = True
SECURE_HSTS_PRELOAD = True

注:我们项目中有很多静态文件(如:css, js…)分布在不同的APP里面,部署时需要找一个地方统一收集起来,这就是STATIC_ROOT的作用(注意STATIC_ROOT不能和STATIC_DIR重复,DIR只是开发时候用的静态文件储存位置)

收集静态文件

python3 manage.py collectstatic

运行该指令,Django会将所有app里面的静态文件统一放置到STATIC_ROOT里面,这样Nginx就可以到一个统一的地方访问这些内容。

(optional) migrate

这里主要是针对数据库的修改,假如你修改了任何models.py文件(数据库模型文件),那么就需要在部署之前运行以下指令来应用你的修改。

python3 manage.py makemigrations
# if no change detected, used
python3 manage.py makemigrations <app name>
python3 manage.py migrate

安装 gunicorn

Gunicorn用于运行我们的Django程序

# install
pip3 install gunicorn

# run program
gunicorn -D -w 4 --bind unix:/tmp/<IP>.socket <prj name>.wsgi:application
# or 
gunicorn -D -w 4 --bind localhost:8000 <prj name>.wsgi:application
  • -D:表示后台运行
  • -w 4:表示开启四个线程(效率会高一点,可以根据自己服务器情况决定)

可用该指令查看运行情况 — pstree -ap|grep gunicorn


至此,大功告成!Django已经欢快的跑起来了。

(Optional) 后期维护

部署并不是一劳永逸,有时候我们发现了bug,修改完代码之后又要重启一下程序,大致步骤如下

# switch to project directory
cd <your project DIR>
# activate the virtual environment
source venv/bin/activate
# pull the latest code
git pull
# re-collect the static files
python3 manage.py collectstatic
python3 manage.py migrate
# kill & reboot gunicorn
pkill gunicorn
gunicorn -D -w 4 --bind localhost:8000 <prj name>.wsgi:application

要是觉得每次都要输入这几条指令很麻烦,可以把他们放到一个文件里面re-deploy.sh(脚本相关内容可查看我的另一篇文章:Bash脚本入门),然后每次只需要运行一下就可以实现一键部署了。

注意pkill会把gunicorn整个程序都杀掉,在只部署了一个程序的时候这种方式最方便,但是假如部署了多个程序,一次性全部杀掉肯定是不合理的,这时候我们可以使用下面这条指令(将替换为你的程序名字):

# check the PID
pid=$(pstree -ap | grep -P ".*gunicorn.*.*" | head -n 1 | perl -ne '/.*,\s*(\d*)\s*.*/ and print "$1"')
# kill priginal process
kill $pid

首先获取对应程序的进程号,然后杀掉对应的进程。

(Optional) 安装配置 Cron

一些很常见的需求:

  • 需要每隔10分钟请求一下API
  • 每周日早上十点需要给用户发一下每周总结
  • 等等…

为了实现这些定时需求,就需要引入一个新的软件Cron,该软件是一个time-based job scheduling daemon,专门用于这类定时任务的需求。

下载+启动

sudo apt update
sudo apt install cron
sudo systemctl enable cron

常用操作

# edit the crontab config
crontab -e
# list the config
crontab -l
# remove the config
crontab -r
# see log
grep CRON /var/log/syslog

简单例子

# change default shell to bash (default is sh)
SHELL=/bin/bash

# "At 01:00 on every day-of-week from Tuesday through Saturday."
0 1 * * 2-6 <your command>
# "At 02:30 on Saturday."
30 2 * * 6 <your command>
# e.g. echo "$(date) --- Hello" >> $HOME/out.log

注意这里的command假如你使用的是你自己编写的shell script,一定要放绝对路径 (e.g. $HOME/scripts/myscript.sh)。还有就是假如你的脚本里面用到了一些环境变量,最好在脚本的开头增加一句source "$HOME/.profile" || exit,因为crontab的运行环境里面只有最基础的一些简单变量(如$HOME),所以最好重新添加一下。

注:cron/crontab表达式比较晦涩难懂,可以直接上网搜索"cron表达式生成",有很多网站有相关的功能。

你可能感兴趣的:(django,python)