Ubuntu配置环境5:Nginx+Gunicorn+Supervisor

首先,本文的mysite是指自己的站点名称。

安装nginx

 apt-get install nginx

关闭nginx默认的log

vi /etc/nginx/nginx.conf
找到以下access_log和error_log,修改为null。
access_log /dev/null;
error_log /dev/null;

接下来配置站点配置,进入nginx站点配置目录,并新建配置文件

cd /etc/nginx/sites-available/
vi mysite

写入一下对应站点配置文本,并保存

server {  
        listen   80;  
        server_name www.mysite.com mysite.com;
        #修改最大上传为10M,默认为2M,超出大小出现413 Request Entity Too Large错误
        client_max_body_size 10M;
         #一定要记得在网站目录下创建logs文件夹,不然会报错,不需要可注释掉
        #access_log /var/www/mysite/logs/access.log;
        #error_log /var/www/mysite/logs/access.log;
        

        #默认请求,nginx反向代理(动态页面转发至gunicorn)
        location / {  
            #将访客IP加入headers中,否则获取到的将是127.0.0.1
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header Host $http_host;  
            proxy_redirect off;  
            #如果请求的文件不存在,则将路由转发到gunicorn的8000端口
            if (!-f $request_filename) {  
                proxy_pass http://127.0.0.1:8000;  
                break;  
            }  
        }

        #静态文件请求转发给目录
        location ^~ /static/ {
                root /var/www/mysite/app;
        }
    }

上面的内容中proxy_pass http://127.0.0.1:8000; 是表示动态页面转发到本机8000端口,这个端口就是gunicorn开放的服务。
这样静态页面nginx就直接返回给访客,动态页面则转发给gunicorn处理。

这里插一句:由于使用nginx反向代理到gunicorn,那么在flask中获取IP就需要

#X-Forward-For参数为nginx反向代理转发到gunicorn时设置的参数
ip = request.headers.get('X-Forward-For') or request.remote_addr

如果需要将nginx直接指向网站根目录,则需要禁止通过nginx直接访问py和app,可将以下配置内容追加在上面的server{}中。【不推荐这种做法】
但是不建议这样,有安全隐患。nginx最好不要直接指向网站根目录,而是应该通过gunicorn路由访问。

        root /var/www/mysite;  
        #禁止直接访问.py文件
        location ~* \.py$ {
            deny all;
        }
        #禁止访问/app/目录
        location ^~ /app/ {
            deny all;
        }

启用站点配置文件

cd /etc/nginx/sites-enabled
#添加引用链接
ln -s /etc/nginx/sites-available/mysite ./mysite
#查看引用是否成功
ls -l
Paste_Image.png

检测配置文件是否有错误

sudo nginx -t

重启nginx

service nginx restart

开启防火墙端口

如果系统中没有安装ufw,则可以跳过,没有安装的话表现为命令不识别。
安装了ufw的话,如果相关端口没有开放,配置好nginx后会出现自己可以访问(wget网址试试),外网却无法访问

#查看开放的端口
ufw status
#添加80端口
ufw allow 80
Ubuntu配置环境5:Nginx+Gunicorn+Supervisor_第1张图片
Paste_Image.png

安装Gunicorn

进入配置好的virtualenvs虚拟目录,激活网站虚拟环境

cd /var/virtualenvs
source mysite_venv/bin/activate

安装Gunicorn

pip install gunicorn
#进入网站根目录
cd /var/www/mysite
#创建配置文件
vi gunicorn.conf

输入配置文本并保存:

# 进程为5
workers = 5

# 监听本地8000端口,之后这个端口来的就是看这个网站的。
bind = '127.0.0.1:8000'

#如果要搭配gevent使用,请加上取消注释
#worker_class="gevent" #sync, gevent,meinheld

注意:如果需要使用gevent模式,请先pip install gevent,然后在gunicorn.conf配置文件中加上worker_class="gevent",其他都和往常一样。

gunicorn启动后的提示:


Ubuntu配置环境5:Nginx+Gunicorn+Supervisor_第2张图片
Paste_Image.png

到这里gunicorn已经安装并配置好了,如果要正常用gunicorn启动网站项目,需要项目中有对应的启动文件,现在可以先跳过这一步,直接跳到安装Supervisor。

当我们安装并配置好 gunicorn 之后,需要用 gunicorn 启动 flask,注意网站项目中 manage.py里面的 app.run(),这句代码是作为 flask 自带的server服务的启动 入口,由于flask自带的server很性能很差,这里我们服务器上使用 gunicorn,manage.py和myapp.py一样,都是作为启动入口文件,供server调用运行。在项目的manage.py文件中,gunicom不会执行代码中的.run(),是需要加上一段代码对接gunicom。

在网站项目中需要一个gunicorn的启动入口的文件,如果没有就自己新建一个文件,名字无所谓,我取的是myapp.py,
内容为

import os
from app import create_app,db

app = create_app(os.getenv('mysite_CONFIG') or 'default')

#使用Gunicorn需要这两行代码对接
from werkzeug.contrib.fixers import ProxyFix
app.wsgi_app = ProxyFix(app.wsgi_app)

这个文件和manage.py一样,也是一个启动文件,不同的是,myapp.py专门作为gunicorn启动使用,manage.py是用作flask自带的web-server启动,同时manage.py里面还有一些管理代码,一样可以使用python manage.py shell或python manage.py db init等命令来管理数据库。

运行Gunicorn,
--config gunicorn.conf是根据配置文件来运行
manage为自己的run文件

gunicorn -c gunicorn.conf myapp:app

安装Supervisor

我们的网站现在虽然能访问了,但是假如你重启服务器,网站的动态文件就会打不开,因为gunicorn不会开机自己启动,需要一个小保姆开机后自动给他启动,这里我们就使用supervisor。

Supervisor是一款服务器管理工具,用于监控和守护进程。阿里云会偶尔宕机,宕机后会切换物理服务,造成服务器重启。故而官网也强调过,程序最好有自动重启、重连机制。所以我们需要Supervisor当保姆,照顾我们的后台进程。

 apt-get install supervisor

注意:supervisor需要系统默认是python2.7才能兼容支持,否则会安装失败,使用python -V查看系统默认py版本

向supervisor添加gunicorn的启动项

cd /etc/supervisor/conf.d
vi mysite.conf

粘贴一下文本并保存

# 进程的名字,取一个以后自己一眼知道是什么的名字。(这行字不能删,第一行需要一行注释,删了就有问题)
[program:mysite]
# 定义Gunicorn启动命令,我们手动在ssh启动Gunicorn需要cd到网站目录然后输入 gunicorn -c gunicorn.conf myapp:app,所以这里所有路径都要写成绝对路径,这样系统才能找到这些路径
command=/var/virtualenvs/mysite_venv/bin/gunicorn myapp:app -c /var/www/mysite/gunicorn.conf
# 网站目录
directory=/var/www/mysite
# 进程所属用户
user=root
# 自动重启设置。
autostart=true
autorestart=true
# 日志存放位置(可能造成print中文UnicodeEncodeError)
#stdout_logfile=/var/www/mysite/logs/gunicorn_supervisor.log
# 设置环境变量。这里这行的意思是:设置环境变量MODE的值为UAT。请根据自己的需要配置,如没有需要这行可以删除。
#environment = MODE="UAT"

[supervisord]

保存后就进入supervisorctl控制台

supervisorctl

进入控制台

reread
update
start mysite

启动完成后,以后每次开机supervisor都会帮我们自动按照配置文件启动gunicorn服务。

Ubuntu配置环境5:Nginx+Gunicorn+Supervisor_第3张图片
Paste_Image.png

如果发生错误请退出控制台,尝试重启服务

service supervisor restart

现在重启服务器后,如果网站能正常访问了,说明gunicorn自动启动了,这也表示我们的supervisor配置成功了。

以后如果更新了网站项目文件,让gunicorn重新加载新的项目文件也只需要使用supervisor管理gunicorn进程就好了。
重新载入配置文件并停止所有进程并按新的配置启动:supervisorctl reload

以下是所有supervisorctl 的命令

supervisorctl status: 查看当前运行的进程列表
supervisorctl stop xxx: 停止某一个进程(xxx),xxx为[program:theprogramname]里配置的值。
supervisorctl start xxx: 启动某个进程
supervisorctl restart xxx: 重启某个进程
supervisorctl stop groupworker: 重启所有属于名为groupworker这个分组的进程(start,restart同理)
supervisorctl stop all,停止全部进程,注:start、restart、stop都不会载入最新的配置文件。
supervisorctl reload,载入最新的配置文件,停止原有进程并按新的配置启动、管理所有进程。
supervisorctl update,根据最新的配置文件,启动新配置或有改动的进程,配置没有改动的进程不会受影响而重启。
注意:显示用stop停止掉的进程,用reload或者update都不会自动重启。

supervisor使用中遇到的一些错误

============错误A
参考https://www.v2ex.com/t/210122

如果提示unix:///var/run/supervisor.sock no such file
error: , [Errno 2] No such file or directory: file: /usr/lib/python2.7/socket.py line: 224
这表明supervisord服务端没有成功启动,多半是/etc/supervisor/conf.d下面自己的配置文件出问题

cd /etc/supervisor/conf.d
supervisord -c mysite.conf
Paste_Image.png

这里就告诉我配置文件17行出了问题

修改好配置文件后,

#重新生成supervisor.sock文件,启动监听服务
supervisord -c supervisord.conf
#重新加载自定义配置文件
supervisorctl reload

============错误B
如果配置文件有错误,会提示你提示

Paste_Image.png

如果有错误则exit退出控制台,vi mysite.conf修改错误后再继续进入控制台,并reread重新读取配置文件。
如果都正确了,则在supervisorctl的控制台中输入命令,启动supervisor任务。
(注意:如果要supervisor启动任务,则会启动gunicorn,自己先使用gunicorn命令试试能否正常启动网站项目)。

#进入网站目录
cd /var/www/mysite
#测试能否正常启动网站项目
gunicorn -c gunicorn.conf myapp:app

如果能正常启动就ctrl+c结束,然后继续进入supervisorctl启动任务。

supervisorctl

==============错误C

这样就错误:

[program:taokeapi]
# 定义Gunicorn启动命令,我们手动在ssh启动Gunicorn需要cd到网站目录然后输入 gunicorn -c gunicorn.conf myapp:app,所以>这里所有路径都要写成绝对路径,这样系统才能找到这些路径
command=/var/virtualenvs/taokeapi_venv/bin/gunicorn myapp:app -c /var/www/taokeapi/gunicorn.conf
# 网站目录
directory=/var/www/taokeapi
# 进程所属用户
user=root
# 自动重启设置。
autostart=true
autorestart=true

[supervisord]

这样就正确:

# 进程的名字,取一个以后自己一眼知道是什么的名字。
[program:taokeapi]
# 定义Gunicorn启动命令,我们手动在ssh启动Gunicorn需要cd到网站目录然后输入 gunicorn -c gunicorn.conf myapp:app,所以>这里所有路径都要写成绝对路径,这样系统才能找到这些路径
command=/var/virtualenvs/taokeapi_venv/bin/gunicorn myapp:app -c /var/www/taokeapi/gunicorn.conf
# 网站目录
directory=/var/www/taokeapi
# 进程所属用户
user=root
# 自动重启设置。
autostart=true
autorestart=true

[supervisord]

差别仅仅是第一行多了一行注释。。。
不知道是BUG还是什么,总之第一行需要注释,去掉就会出问题。。。

======错误D

Paste_Image.png

使用supervisor启动gunicorn,执行print就出错。
而直接启动gunicorn则没问题。
可见错误在supervisor上面。。

经过多次排查,发现,
vi /etc/supervisor/conf.d/taokeapi.conf配置文件中多了一行,

stdout_logfile=/var/www/mysite/logs/gunicorn_supervisor.log

由于supervisor是基于python2,当运行python3的项目时,print就会被写入这个日志文件,python2在有些系统中输出中文就会出现UnicodeEncodeError错误。
解决办法:
配置文件中去掉这行输出日志目录,完整配置如下:

# 进程的名字,取一个以后自己一眼知道是什么的名字。
[program:taokeapi]
# 定义Gunicorn启动命令,我们手动在ssh启动Gunicorn需要cd到网站目录然后输入 gunicorn -c gunicorn.conf myapp:app,所以>这里所有路径都要写成绝对路径,这样系统才能找到这些路径
command=/var/virtualenvs/taokeapi_venv/bin/gunicorn myapp:app -c /var/www/taokeapi/gunicorn.conf
# 网站目录
directory=/var/www/taokeapi
# 进程所属用户
user=root
# 自动重启设置。
autostart=true
autorestart=true

[supervisord]

然后重新加载配置文件

supervisord -c taokeapi.conf

supervisorctl
>reread
>update
>reload

这样就发现没问题了

你可能感兴趣的:(Ubuntu配置环境5:Nginx+Gunicorn+Supervisor)