Diango博客--11.Nginx + Gunicorn + Supervisor 方式部署

0.部署前准备

1)使用比较流行的 Nginx + Gunicorn 的方式将 django 开发的博客部署到自己的服务器,让别人能够通过域名访问博客。

2)开发使用的本地环境为 Windows 10,服务器环境为 CentOS 7(64 位)

3)辅助工具 Xshell

1.创建一个超级用户

adduser fxd
passwd fxd
usermod -aG wheel fxd
su - fxd

新用户创建并切换成功了。如果是新服务器的话,最好先更新一下系统,避免因为版本太旧而给后面安装软件带来麻烦。运行下面的两条命令:

sudo yum update
sudo yum upgrade

2.更新 SQLite3

为了方便,我们博客使用了 SQLite3 数据库,django 2.2 要求 SQLite3 数据库版本在 3.8.3 以上,而 CentOS 7 系统自带版本低于 django 2.2 所要求的最低版本,所以首先来更新 SQLite3 的版本。

注意:有可能你使用的服务器系统发行版 SQLite3 已经高于 3.8.3,这一步就可以跳过。请执行 sqlite3 --version 查看 SQLite3 的版本

首先登陆到 sqlite 的官方下载地址,查看最新发布的版本,本教程使用版本为 3.29.0,找到该版本的源码压缩包,复制其下载链接,然后通过 wget 命令下载到服务器(一般将源码放在 ~/src 目录下。)

mkdir -p ~/src
cd ~/src

下载 sqlite3 源码并解压安装

wget https://sqlite.org/2019/sqlite-autoconf-3290000.tar.gz
tar zxvf sqlite-autoconf-3290000.tar.gz
cd sqlite-autoconf-3290000
./configure
make
sudo make install

注意:如果 wget 命令不存在,使用 sudo yum install -y wget 安装即可。

报错:./configure报错
在这里插入图片描述
解决方法:sudo yum install -y gcc glibc
之后执行 ./configure

查看sqlite3版本:
Xshell中重新打开一个终端:

sqlite3 --version

3.安装 Python3 、pip3.6以及 Pipenv

CentOS 7 自带的 Python 发行版为 2.7,因此需要安装 Python3,为了兼容性,我们安装 Python 3.6.4。
首先安装可能的依赖:

sudo yum install -y openssl-devel bzip2-devel expat-devel gdbm-devel readline-devel sqlite-devel

然后下载 Python 3.6.4 的源码并解压:

cd ~/src
wget https://www.python.org/ftp/python/3.6.4/Python-3.6.4.tgz
tar -zxvf Python-3.6.4.tgz

最后编译安装:

cd Python-3.6.4
./configure LD_RUN_PATH=/usr/local/lib LDFLAGS="-L/usr/local/lib" CPPFLAGS="-I/usr/local/include"
make LD_RUN_PATH=/usr/local/lib
sudo make install

注意这里安装 Python 时,Python 会依赖 SQLite3 的库,所以在 configure 时通过 LD_RUN_PATH 指定依赖的搜索目录(因为我们之前更新了 SQLite3 的版本,指定依赖搜索目录确保使用新的 SQLite3 依赖库),另外两个参数作用类似。

然后输入 python3.6 -V 和 pip3.6 -V 命令测试安装结果,输出版本号说明安装成功了。

有了 pip,就可以安装 Pipenv 了:

首先建立软连接:

sudo ln -s /usr/local/bin/pip3.6 /usr/bin/pip3.6
sudo ln -s /usr/local/bin/pip3 /usr/bin/pip3

然后安装:

sudo pip3.6 install pipenv

注意:
python2.7和python3.6的区别
pip2.7和pip3.6的区别
以下部分列出两种指令的输出情况,供参考:

[fxd@instance-6lf3j8lp Python-3.6.4]$ python --version
Python 2.6.6
[fxd@instance-6lf3j8lp Python-3.6.4]$ python3.6 --version
Python 3.6.4


[fxd@instance-6lf3j8lp Python-3.6.4]$ pip --version
pip 7.1.0 from /usr/lib/python2.6/site-packages (python 2.6)
[fxd@instance-6lf3j8lp Python-3.6.4]$ pip3.6 --version
pip 9.0.1 from /usr/local/lib/python3.6/site-packages (python 3.6)


[fxd@instance-6lf3j8lp Python-3.6.4]$ pip freeze
argparse==1.2.1
backports.ssl-match-hostname==3.4.0.2
boto==2.34.0
chardet==2.2.1
Cheetah==2.4.1
cloud-init==0.7.5
configobj==4.6.0
ethtool==0.6
iniparse==0.3.1
jsonpatch==1.2
jsonpointer==1.0
M2Crypto==0.20.2
Markdown==2.0.1
oauth==1.0.1
ordereddict==1.2
policycoreutils-default-encoding==0.1
prettytable==0.7.2
pycurl==7.19.0
Pygments==1.1.1
pygpgme==0.1
python-dmidecode==3.10.15
PyYAML==3.10
requests==2.6.0
setools==1.0
six==1.9.0
urlgrabber==3.9.1
urllib3==1.10.2
yum-metadata-parser==1.1.2

[fxd@instance-6lf3j8lp Python-3.6.4]$ pip3.6 freeze
certifi==2019.11.28
pipenv==2018.11.26
virtualenv==16.7.8
virtualenv-clone==0.5.3

4.部署代码

1)首先要对项目做一点配置,打开 settings.py,找到 ALLOWED_HOSTS,将其修改为:

ALLOWED_HOSTS = [‘127.0.0.1’, 'localhost ', ‘.zmrenwu.com’]

指定了 ALLOWED_HOSTS 的值后,django 将只允许通过指定的域名访问我们的应用,比如这里只允许通过 127.0.0.1,localhost 以及 zmrenwu.com 和其任意子域名(域名前加一个点表示允许访问该域名下的子域名)访问(即 HTTP 报文头部中 Host 的值必须是以上指定的域名,通常你在浏览器输入域名访问网站时,Host 的值就会被设置为网站的域名),这样可以避免 HTTP Host 头攻击。

2)Django 项目中会有一些 CSS、JavaScript 等静态文件,为了能够方便地让 Nginx 处理这些静态文件的请求,我们把项目中的全部静态文件收集到一个统一的目录下,这个目录通常位于 django 项目的根目录,并且命名为 static。为了完成这些任务,需要在项目的配置文件里做一些必要的配置:
文件位置:blogproject/settings.py

# 其他配置...

STATIC_URL = '/static/'
# 加入下面的配置
STATIC_ROOT = os.path.join(BASE_DIR, 'static')

STATIC_ROOT 即指定静态文件的收集路径,这里指定为 BASE_DIR(项目根目录,在 settings.py 文件起始处定义)下的 static 文件夹。

3)使用 git上传代码至服务器。首先安装 git:

sudo yum install -y git

将代码上传到 GitHub 等代码托管平台,这样我们就可以方便地把代码拉取到服务器了。如何将pycharm中的项目上传至github上,请戳这里

通常将应用代码放在 ~/apps/ 目录下,先来设置一下服务器的文件结构,用于存放应用代码等相关文件:

#在用户目录下创建 apps 目录并进入
mkdir -p ~/apps
cd ~/apps
#拉取博客代码
git clone https://github.com/fanxindong/HelloDjango-blog-tutorial-fxd.git

注意:上传的项目代码,需要将其中数据库迁移时生成的代码删除,在服务器上重新迁移!

在这里插入图片描述

然后进入到项目根目录,安装项目依赖:

cd ~/apps/HelloDjango-blog-tutorial
pipenv install --deploy --ignore-pipfile

然后创建一下数据库:

pipenv run python manage.py makemigrations
pipenv run python manage.py migrate

此时查看目录发现已经生成数据库文件db.sqlite3

在这里插入图片描述

4)启动开发服务器:

pipenv run python manage.py runserver 0.0.0.0:8000
在这里插入图片描述
在浏览器中输入服务器域名和端口号,出现博客内容!
在这里插入图片描述

5.使用 Gunicorn

首先进入到项目根目录,安装 Gunicorn:

pipenv install gunicorn

由于我们在服务端修改安装了 gunicorn,代码中 Pipfile 文件和 Pipfile.lock 文件会被更新,因此别忘了把改动同步到本地,具体做法可以自行学习,以下是一个参考:

#服务端提交代码
git add Pipfile Pipfile.lock

若此时报错,则按照要求输出github的name和email
[root@instance-6lf3j8lp HelloDjango-blog-tutorial-fxd]# git config --global user.name “your-name”
[root@instance-6lf3j8lp HelloDjango-blog-tutorial-fxd]# git config --global user.email your-email

git commit -m “add gunicorn dependency”
git push

#本地电脑中拉取代码
git pull

如此时出现错误,请戳这里

然后回到线上服务器,在项目根目录,执行下面的命令启动服务:

pipenv run gunicorn blogproject.wsgi -w 2 -k gthread -b 0.0.0.0:8000

打开浏览器显示如下:

在这里插入图片描述

各个参数的含义:

1)-w 2 表示启动 2 个 worker 用于处理请求(一个 worker 可以理解为一个进程),通常将 worker 数目设置为 CPU 核心数的 2-4 倍。

2)-k gthread 指定每个 worker 处理请求的方式,根据大家的实践,指定为 gthread 的异步模式能获取比较高的性能,因此我们采用这种模式。

3)-b 0.0.0.0:8000,将服务绑定到 8000 端口,运行通过公网 ip 和 8000 端口访问应用。

4)访问 ip:8000(ip 为你服务器的公网 ip),应用成功访问了,但是我们看到样式完全乱了。别急,这不是 bug!此前我们使用 django 自带的开发服务器,它会自动帮我们处理静态样式文件,但是 Gunicorn 并不会帮我们这么做。因为处理静态文件并不是 Gunicorn 所擅长的事,应该将它交给更加专业的服务应用来做,比如 Nginx。

6.启动 Nginx 服务器

Nginx是一个高性能的 HTTP 和反向代理 web 服务器,它的功能非常多,这里我们主要用它来处理静态文件以及将非静态文件的请求反向代理给 Gunicorn。当我们访问一个博客文章详情页面时,服务器会接收到下面两种请求:

  1. 显示文章的详情信息,这些信息通常保存在数据库里,因此需要调用数据库获取数据。
  2. 图片、css、js 等存在服务器某个文件夹下的静态文件。

对于前一种请求,博客文章的数据需要借助 django 从数据库中获取,Nginx 处理不了,它就会把这个请求转发给运行在 Gunicorn 服务中的 django 应用,让 django 去处理。

用 django 去获取静态文件是很耗时的,但 Nginx 可以很高效地处理,因此对于后一种静态文件的请求,只需要去这些静态文件所在的文件夹获取,Nginx 就会代为处理,不再麻烦 django。

首先安装 Nginx:

sudo yum install epel-release -y
sudo yum install nginx -y

运行下面的命令启动 Nginx 服务

service nginx start

小贴士:
service nginx start(启动)
service nginx stop(停止)
service nginx reload(重启)

在浏览器输入 ip(不输入端口则默认为 80 端口,Nginx 默认在 80 端口监听请求),看到 Nginx 的欢迎界面说明 Nginx 启动成功:

在这里插入图片描述

7.配置 Nginx

Nginx 的配置位于 /etc/nginx/nginx.conf 文件中,其内容如下:

user nobody nobody;
...
http {
    # Load modular configuration files from the /etc/nginx/conf.d directory.
    # See http://nginx.org/en/docs/ngx_core_module.html#include
    # for more information.
    include /etc/nginx/conf.d/*.conf;

    server {
        listen       80 default_server;
        listen       [::]:80 default_server;
        server_name  _;
        root         /usr/share/nginx/html;

        # Load configuration files for the default server block.
        include /etc/nginx/default.d/*.conf;

        location / {
        }
    }
}

在 http 配置下有一个 server 模块,server 模块用于配置一个虚拟服务,使这个虚拟服务监听指定的端口和域名。你可以配置多个 server,这样就会启动多个虚拟服务,用于监听不同端口,或者是同一个端口,但是不同的域名,这样你就可以在同一服务器部署多个 web 应用了。

再来看看 server 下的 include,include 会将指定路径中配置文件包含进来,这样便于配置的模块化管理,例如我们可以把不同 web 应用的配置放到 /etc/nginx/conf.d/ 目录下,这样 nginx 会把这个目录下所有以 .conf 结尾的文件内容包含到 nginx.conf 的配置中来,而无需把所有配置都堆到 nginx.conf 中,使得配置文件十分臃肿。

我们来配置博客应用,为了模块化管理,我们将配置写到 /etc/nginx/conf.d/ 目录下。先在服务器的 conf.d 目录下新建一个配置文件,把它叫做 HelloDjango-blog-tutorial-fxd.conf。写入下面的配置内容:
文件位置:/etc/nginx/conf.d/HelloDjango-blog-tutorial-fxd.conf

server {
    charset utf-8;
    listen 80;
    server_name www.fanxindong.com;

    location /static {
        alias /home/fxd/apps/HelloDjango-blog-tutorial-fxd/static;
    }

    location / {
        proxy_set_header Host $host;
        proxy_pass http://127.0.0.1:8000;
    }
}

首先我们配置了一个虚拟服务,编码方式为 utf-8,监听于 80 端口。

服务的域名为 www.fanxindong.com,所以来自这个域名的请求都会被这个服务所处理。

所有URL 匹配 /static 的请求均由 Nginx 处理,alias 指明了静态文件的存放目录,这样 Nginx 就可以在这个目录下找到请求的文件返回给客户端。

其它请求转发给运行在本机 8000 端口的应用程序处理,我们会在这个端口启动 Gunicorn 用于处理 Nginx 转发过来的请求。

重启 nginx 使得配置生效:

service nginx reload

8.关闭 DEBUG 模式,收集静态文件

开发环境下,django 为了调试方便,会将 settings.py 文件中的 DEBUG 选项配置为 True,这样如果程序运行出错,调试信息将一览无余,这在开发时很方便,但部署到线上就会带来巨大安全隐患,所以我们把 DEBUG 选项设置为 False,关闭调试模式,在本地将 settings.py 中的 DEBUG 为:

DEBUG=False

线上服务器更新最新的代码,然后运行命令收集静态文件到之前配置的 STATIC_ROOT 目录下:

pipenv run python manage.py collectstatic

然后使用 Gunicorn 启动服务。

pipenv run gunicorn blogproject.wsgi -w 2 -k gthread -b 0.0.0.0:8000

9.使用 Supervisor管理 Gunicorn 进程

现在 Gunicorn 是我们手工启动的,一旦我们退出 shell,服务器就关闭了,博客无法访问。就算在后台启动 Gunicorn,万一哪天服务器崩溃重启了又得重新登录服务器去启动,非常麻烦。为此使用 Supervisor 来管理 Gunicorn 进程,这样当服务器重新启动或者 Gunicorn 进程意外崩溃后,Supervisor 会帮我们自动重启 Gunicorn。

先按 Ctrl + C 停止刚才启动的 Gunicorn 服务进程。

首先安装 Supervisor。

sudo pip3 install supervisor

设置如下的目录结构(位于 ~/etc 目录下)来管理 Supervisor 有关的文件:

~/etc
├── supervisor
│ ├── conf.d
│ └── var
│ ├── log
└── supervisord.conf

其中 supervisord.conf 是 Supervior 的配置文件,它会包含 conf.d 下的配置。var 目录下用于存放一些经常变动的文件,例如 socket 文件,pid 文件,log 下则存放日志文件。

指令:
mkdir -p ~/etc/supervisor/conf.d
mkdir -p ~/etc/supervisor/var/log

然后进入 ~/etc 目录下生成 Supervisor 的配置文件:

cd ~/etc
echo_supervisord_conf > supervisord.conf


  1. 修改 supervisor.conf,让 Supervisor 进程产生的一些文件生成到上面我们创建的目录下,而不是其默认指定的地方。

首先找到 [unix_http_server] 版块,将 file 设置改为如下的值:

[unix_http_server]
file=/home/fxd/etc/supervisor/var/supervisor.sock

即让 socket 文件生成在 ~/etc/supervisor/var/ 目录下。注意 supervisor 不支持将 ~ 展开为用户 home 目录,所以要用绝对路径指定

  1. 类似的修改 [supervisord] 板块下的 logfile 和 pidfile 文件的路径,还有 user 改为系统用户,这样 supervisor 启动的进程将以系统用户运行,避免可能的权限问题:

logfile=/home/fxd/etc/supervisor/var/log/supervisord.log
pidfile=/home/fxd/etc/supervisor/var/supervisord.pid
user=fxd

  1. 还有 [supervisorctl] 板块下:

serverurl=unix:///home/fxd/etc/supervisor/var/supervisor.sock

  1. [include] 版块,将 /home/yangxg/etc/supervisor/conf.d/ 目录下所有以 .ini 结尾的文件内容包含到配置中来,这样便于配置的模块化管理,和之前 Nginx 配置文件的处理方式是类似的。

files = /home/fxd/etc/supervisor/conf.d/*.ini

  1. 然后我们到 conf.d 文件夹下,新建我们博客应用的配置hellodjango-blog-tutorial-fxd.ini:

[program:hellodjango-blog-tutorial]
command=pipenv run gunicorn blogproject.wsgi -w 2 -k gthread -b 127.0.0.1:8000
directory=/home/fxd/apps/HelloDjango-blog-tutorial-fxd
autostart=true
autorestart=unexpected
user=fxd
stdout_logfile=/home/fxd/etc/supervisor/var/log/Hellodjango-blog-tutorial-fxd-stdout.log
stderr_logfile=/home/fxd/etc/supervisor/var/log/Hellodjango-blog-tutorial-fxd-stderr.log

各项配置的含义:

[program:hellodjango-blog-tutorial] 指明运行应用的进程,名为 hellodjango-blog-tutorial。
command 为进程启动时执行的命令。
directory 指定执行命令时所在的目录。
autostart 随 Supervisor 启动自动启动进程。
autorestart 进程意外退出时重启。
user 进程运行的用户,防止权限问题。
stdout_logfile,stderr_logfile 日志输出文件。

  1. 启动 Supervisor

supervisord -c ~/etc/supervisord.conf

-c 指定 Supervisr 启动时的配置文件。

进入 supervisorctl 进程管理控制台:

supervisorctl -c ~/etc/supervisord.conf

执行 update 命令更新配置文件并启动应用。

浏览器输入域名,可以看到服务已经正常启动了。

10.使用 CDN 加快 Bootstrap 和 jQuery 的加载速度

我们的项目使用了 Bootstrap 和 jQuery,这两个文件我们是从本地加载的。如果服务器性能比较差的话,加载需要耗费很长的时间,网站打开的速度就变得无法忍受。我们使用 CDN 来加快加载速度。具体来说,替换 base.html 的几个静态文件的加载标签:

文件位置:base.html

- <link rel="stylesheet" href="{% static 'blog/css/bootstrap.min.css' %}">
- <script src="{% static 'blog/js/jquery-2.1.3.min.js' %}"></script>
- <script src="{% static 'blog/js/bootstrap.min.js' %}"></script>
+ <link href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">
+ <script src="https://cdn.bootcss.com/jquery/2.1.3/jquery.min.js"></script>
+ <script src="https://cdn.bootcss.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>

本地修改代码后,将代码同步到线上服务器,执行下面的命令重启 hellodjango-blog-tutorial 应用进程:

supervisorctl -c ~/etc/supervisord.conf restart hellodjango-blog-tutorial

这样网站访问的速度将大大提升!

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值