Ubuntu配置环境3: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

启用站点配置文件

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
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启动测试

cd /var/www/mysite
gunicorn -c gunicorn.conf myapp:app

启动后提示:


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服务。

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: <class 'socket.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

这样就发现没问题了

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,236评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,867评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,715评论 0 340
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,899评论 1 278
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,895评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,733评论 1 283
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,085评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,722评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,025评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,696评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,816评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,447评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,057评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,009评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,254评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,204评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,561评论 2 343

推荐阅读更多精彩内容