gunicorn+supervisor+nginx+fabric部署Web应用
学习如何去部署一个Web应用。
1、首先选择一个WSGI服务器,之前看的是uWSGI,但uWSGI配置稍微麻烦些,因此这里考虑使用gunicorn。
2、使用supervisor控制进程;
3、选用静态服务器,选用nginx做负载均衡,以及处理静态文件;
4、使用fabric,ansible等工具批量部署。
下面记录我Django项目部署的过程(系统是Ubuntu14.04)。
1、gunicorn
基本用法: 在工程目录下执行:
gunicorn -w4 app.wsgi:application
-w 表示开启多少个 worker,-b 表示 gunicorn 开发的访问地址。
命令敲进去之后,会出现:
Listening at :http://127.0.0.1:8000
Using worker:sync 同步阻塞
4个worker
(感觉比uWSGI简单多了)
默认gunicorn 默认使用同步阻塞的网络模型(-k sync),对于大并发的访问可能表现不够好, 它还支持其它更好的模式,如gevent(协程)。gevent可以保证在IO请求时实现自动切换。
Gunicorn should only need 4-12 worker processes to handle hundreds or thousands of requests per second。gunicorn只需要4-12个进程处理每秒数以千计的请求。
服务模型(Server Model)
Gunicorn是基于 pre-fork 模型的。也就意味着有一个中心管理进程( master process )用来管理 worker 进程集合。Master从不知道任何关于客户端的信息。所有的请求和响应处理都是由 worker 进程来处理的。
Master(管理者)
主程序是一个简单的循环,监听各种信号以及相应的响应进程。master管理着正在运行的worker集合,通过监听各种信号比如TTIN, TTOU, and CHLD. TTIN and TTOU响应的增加和减少worker的数目。CHLD信号表明一个子进程已经结束了,在这种情况下master会自动的重启失败的worker。
gunicorn最好也将配置写到配置文件中,便于管理。在工程目录下, 建立一个gunicorn_conf.py文件。
bind = '127.0.0.1:8000'
workers=4
gunicorn可以充当一个WSGI服务器,但是单纯的使用它,还是有一定风险的。比如因为一些未知的元素,突然服务器挂了,但是你自己却不能及时发现。这时出现了一个利器,在gunicorn中称之为monitor,监控器。最好用的就是supervisor,他是一个有效的进程管理器,会保证在服务器down掉之后,重启应用。
2、supervisor
supervisor用于管理多进程,当进程莫名挂掉可以帮你restart,保证服务持久在线。
首先在工程目录下创建配置文件 echo_supervisord_conf > etc/supervisord.conf
supervisor的使用方法:
[program:myapp]
command=/home/haibo/study/myworks/venv/bin/gunicorn -w4 -b0.0.0.0:2170 myapp:app ; supervisor启动命令
directory=/home/haibo/study/myworks/dailyblog ; 项目的文件夹路径
startsecs=0 ; 启动时间
stopwaitsecs=0 ; 终止等待时间
autostart=false ; 是否自动启动
autorestart=false ; 是否自动重启
stdout_logfile=/home/haibo/study/myworks/dailyblog/log/gunicorn.log ; log 日志
stderr_logfile=/home/haibo/study/myworks/daiy=lyblog/log/gunicorn.err
command里的路径可以是相对,也可以是绝对的,但我一般就写成绝对的,这也利于别人维护嘛。
supervisord -c supervisor.conf 通过配置文件启动supervisor
supervisorctl -c supervisor.conf status 察看supervisor的状态
supervisorctl -c supervisor.conf reload 重新载入 配置文件
supervisorctl -c supervisor.conf start [all]|[appname] 启动指定/所有 supervisor管理的程序进程
supervisorctl -c supervisor.conf stop [all]|[appname] 关闭指定/所有 supervisor管理的程序进程
可以通过supervisor.pid里的pid来kill掉supervisor进程。
当我们修改配置后,需要重新加载配置文件
supervisorctl -c supervisor.conf reload
此时可能出现: 如果出现如下异常:
error: <class 'socket.error'>, [Errno 111] Connection refused: file: /usr/lib64/python2.6/socket.py line: 567
解决办法如下:
先启动supervisor服务
sudo supervisord -c /path/to/your/supervisord.conf
sudo supervisorctl -c /path/to/your/supervisord.conf
然后:
supervisorctl start myapp
记录另外一个问题:当启动supervisor服务时,总是提前unknown error making dispatchers for 'app_name' :EACCES。 这种问题是因为权限引起的,更改工程目录的权限即可。 chown -R haibo:haibo /srvdailyblog/www。
再介绍一下supervisor的组件
1、supervisord
是服务端程序,主要功能是启动supervisor程序自身,启动supervisor管理的子进程,响应来自clients的请求,重启闪退或异常退出的子进程,把子进程的stderr或stdout记录到日志文件中,生成和处理Event。
2、supervisorctl
是客户端程序,主要功能就是可以利用它来查看子进程状态, 启动/停止/重启子进程,获取running子进程的列表等等。。。最牛逼的一点是,supervisorctl不仅可以连接到本机上的 supervisord,还可以连接到远程的supervisord,当然在本机上面是通过UNIX socket连接的,远程是通过TCP socket连接的。supervisorctl和supervisord之间的通信,是通过xml_rpc完成的。 相应的配置在[supervisorctl]块里面
3、web server
Web Server主要可以在界面上管理进程,Web Server其实是通过XML_RPC来实现的,可以向supervisor请求数据,也可以控制supervisor及子进程。配置在[inet_http_server]块里面
4、XML_RPC
远程调用的,上面的supervisorctl和Web Server就它实现
3、Nginx
现在已经完成了Web sever的部署,但还需要一个代理服务器处理静态资源,以及负载均衡。
这里使用的是著名的nginx。
在配置Nginx之前,需要收集admin下的static文件,执行下面命令:
python manage.py collectstatic
nginx配置:
我在工程目录下新建了一个dailyblog.conf配置文件,并进行如下基本配置:
server {
listen 80;
server_name localhost;
charset utf-8;
error_log /tmp/ninx_error.log;
access_log /tmp/ninx_access.log;
location /media {
alias /home/haibo/study/myworks/dailyblog/media;
}
location /static {
alias /home/haibo/study/myworks/dailyblog/static;
}
location / {
proxy_set_header X-Forward-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_redirect off;
proxy_pass http://127.0.0.1:8000; #gunicorn监听的端口
}
}
配置好之后,将配置文件软连接到nginx配置根目录下 :
ln -s /path/to/your/nginx_conf /etc/nginx/site-enabled/yournginx.conf
然后执行sudo /etc/init.d/nginx reload重新启动,就可访问http://localhost了。访问这个会跳转到http://127.0.0.1:8000/了。
上面是基本的配置,可以配置的选项还有很多。我第一次是按照官网那么配置的,就是有http,然后在http里面配置server等等信息,但没有成功,不知道为啥,这是应该解决的问题。
1、什么是Nginx?
Nginx是一个高性能的HTTP和反向代理服务器,也是一个IMAP/POP3/SMTP服务器.Nginx是一款轻量级的Web服务器/反向代理服务器及电子邮件(IMAP/POP3)代理服务器.
目前使用的最多的web服务器或者代理服务器,像淘宝、新浪、网易、迅雷等都在使用
Nginx更多是用于作为静态资源的处理和负载均衡。
静态资源
当我们访问一个博客文章详情页面时,服务器会接收到下面两种请求:
- 显示文章的详情信息,这些信息通常保存在数据库里,因此需要调用数据库获取数据。
- 图片、css、js 等存在服务器某个文件夹下的静态文件。
对于前一种请求,博客文章的数据需要借助 Django 从数据库中获取,Nginx 处理不了,它就会把这个请求转发给 Django,让 Django 去处理。而对于后一种静态文件的请求,只需要去这些静态文件所在的文件夹获取,Nginx 就会代为处理直接处理。
用 Django 去获取静态文件是很耗时的,但 Nginx 可以很高效地处理,这就是我们要使用 Nginx 的原因(当然其功能远不止这些)。
负载均衡
负载均衡即是代理服务器将接收的请求均衡的分发到各服务器中 负载均衡主要解决网络拥塞问题,提高服务器响应速度,服务就近提供,达到更好的访问质量,减少后台服务器大并发压力。
4.fabric
利用fabric是一个自动化管理工具,利用fabric可以避免我们重复敲一些代码。fabric通过ssh进行远程连接,非常方便。
下面是我项目的fabfile文件代码。
_TAR_FILE = 'dailyblog.www.tar.gz'
def pack():
includes = ['blog','dailyblog','media','static','utils','templates','*.conf','*.py','requirements.txt','start_local.sh']
excludes = ['*.pyc','*.pyw']
local('rm -f dist/%s' % _TAR_FILE)
with lcd(os.path.join(os.path.abspath('.'),'www')):
cmd = ['tar','--dereference','-zcvf','../dist/%s' % _TAR_FILE]
cmd.extend(['--exclude=\'%s\'' % ex for ex in excludes])
cmd.extend(includes)
local(' '.join(cmd))
_REMOTE_TMP_TARFILE = '/tmp/%s' % _TAR_FILE
_REMOTE_BASE_DIR = '/srv/dailyblog'
def deploy(first=False):
new_dir = 'www-%s' % datetime.now().strftime('%y-%m-%d_%H-%M-%S')
#upload tar file
put('dist/%s' % _TAR_FILE,_REMOTE_TMP_TARFILE)
with cd(_REMOTE_BASE_DIR):
sudo('mkdir %s' % new_dir)
#unpack tar file
with cd('%s/%s' % (_REMOTE_BASE_DIR,new_dir)):
sudo('tar -zxvf %s' % _REMOTE_TMP_TARFILE)
#create sot link for app project'
with cd(_REMOTE_BASE_DIR):
sudo('rm -rf www')
sudo('ln -s %s www' % new_dir)
sudo('chown haibo:haibo www')
sudo('chown -R haibo:haibo %s' % new_dir)
if first:
#create vitural enviroment
witdh cd('%s' % _REMOTE_BASE_DIR):
run('pip install virtualenv')
run('virtualenv env')
run('source %s/env/bin/activate' % _REMOTE_BASE_DIR)
with cd('%s/%s' % (_REMOTE_BASE_DIR,'www')):
run('pip install -r requirements.txt')
sudo('ln -s dailyblog.conf /etc/nginx/site-enabled/dailyblog.conf')
run('supervisord -c supervisor.conf')
sudo('/etc/init.d/nginx reload')
微信分享/微信扫码阅读