最近在看关于Docker和Nginx方面的内容,先于在Docker上开发以及部署python应用自然要先能够在本机上部署,其中找到一篇文章写的最为详细并且实验成功,所以在此翻译转载过来以备后需。【原文链接】
简介:
这篇文章将介绍在ubuntu14.04环境下使用nginx作为反向代理服务器,uWSGI作为服务器来部署最简单的flask应用。
(也就是浏览器发送的web request先到达Nginx服务器,而后Nginx服务器再将其转发到uWSGI服务器做实际处理)
前提要求:
首先需要一个拥有可执行sudo命令的非root用户。
对于WSGI,uWSGI以及uwsgi有一定的了解。
WSGI:web server gateway interface,其是一种网络服务接口,通过它我们可以忽略掉网络请求与返回响应的具体细节而专注于处理逻辑,是一种通信协议。【廖雪峰的WSGI教程】
uwsgi: 是一个基于二进制的线路协议(wire protocol),被uWSGI应用服务器实现来用于与功能更加强大的web服务器做通信。
uWSGI:一个实现了WSGI以及uwsgi通信协议的应用服务器。【文档】
安装所需组件:
sudo apt-get update
sudo apt-get install python-pip python-dev nginx
sudo pip install virtualenv #安装virtualenv
mkdir ~/myproject #创建实际要用到的目录
cd ~/myproject
virtualenv myprojectenv #创建虚拟环境myprojectenv
source myprojectenv/bin/activate #激活虚拟环境
创建一个flask应用
注:现在在虚拟环境中,并且在~/myproject目录下
安装Flask与uwsgi
pip install uwsgi flask
创建flask app:
#/myproject/myproject.py
from flask import Flask
application = Flask(__name__)
@application.route("/")
def hello():
return "<h1 style='color:blue'>Hello There!</h1>"
if __name__ == "__main__":
application.run(host='0.0.0.0')
#注,现在python myproject.py即能够在浏览器中看到输出
创建WSGI接入点
接下来我们将创建一个文件作为我们的flask应用与uWSGI服务器的接入点,这用于告诉uWSGI如何调用我们的应用:
# ~/myproject/wsgi.py
from myproject import application
if __name__ == "__main__":
application.run()
配置uWSGI:
目前应用以及接入点都创建好了,接下来处理uWSGI的配置
测试uWSGI服务器可用:
可以通过我们上面设置的接入点文件来做测试, We'll also specify the socket so that it will be started on a publicly available interface and the protocol so that it will use HTTP instead of the uwsgi
binary protocol:
uwsgi --socket 0.0.0.0:8000 --protocol=http -w wsgi
这时通过ip:8000就应该能够访问到上面flask应用的输出,表明uWSGI服务没有问题
到此虚拟环境就可以关闭了:
deactivate
创建uwsgi配置文件:
上面已经测试了uWSGI可以用于作为服务器来呈现应用,但为了获得更好的性能,还需要对其进行配置
# ~/myproject/myproject.ini
[uwsgi] # uWSGI识别符,从而要执行下面的setting
module = wsgi # 申明使用wsgi.py模块
master = true #启动master模式
processes = 5 #调用5个进程用于处理连接
#在上面的测试中,我们将uWSGI暴露到了8000端口,但是在这里我们使用Nginx来获取客户端连接,随后才将其转发到uWSGI服务器
#由于他们都在同一机器上,使用一个Unix socket来传递将更加安全快速,我们设置其为myproject.sock并且放到myproject目录下
#并且,我们需要改变其权限,在随后我们将获得Nginx group对于uWSGI进程的所有权,所以我们需要保证此socket能够读写
#与此同时通过设置vacuum来达到进程结束后清理此socket的设计
socket = myproject.sock
chmod-socket = 660
vacuum = true
#die-on-term
option:because the Upstart init system and uWSGI have different ideas on what different process signals should mean.
# Setting this aligns the two system components, implementing the expected behavior:
die-on-term = true
注:你会发现配置文件并没有像命令行启动样指明所用协议,那是因为默认的uWSGI就使用uwsgi协议【一种快速的用于与其他服务器交流的二进制协议,此比使用HTTP协议高效】
创建启动脚本:
创建启动脚本的目的是让ubuntu能够自动启动uWSGI服务器来启动我们的flask应用
$sudo vim /etc/init/myproject.conf
#操作系统有不同的runlevel,通过下面的设置既是开机启动,关机(重启,单一用户模式)时关闭
description "uWSGI server instance configured to serve myproject"
start on runlevel [2345]
stop on runlevel [!2345]
#设置uWSGI运行时的用户以及用户组,
setuid user
setgid www-data #Nginx在www-data用户组下,所以这里需要设置为www-data从而使其可以读写socket文件
env PATH=/home/user/myproject/myprojectenv/bin #设置使用的虚拟环境的地址
chdir /home/user/myproject #切换到应用目录
exec uwsgi --ini myproject.ini #Afterwards, we can simply call the uWSGI executable and pass it the configuration file we wrote:
在上面配置完成推出后可通过下面语句启动:
sudo start myproject
注:此语句会提供是否启动成功的提示
配置Nginx代理请求:
目前,我们的uWSGI应用服务已经开始运行了,正在等待socket文件中的请求,接下来我们就来设置Nginx来使用uwsgi协议传递web request到socket文件
在Nginx的sites-available目录下创建一个新的server模块配置文件:
$sudo vim /etc/nginx/sites-available/myproject
server {
listen 80; #监听80端口
server_name server_domain_or_IP; #设置主机名或主机IP
location / { #当使用浏览器访问主页时
include uwsgi_params; #使用uwsgi_para文件设置一些常用的uWSGI参数
uwsgi_pass unix:/home/user/myproject/myproject.sock; #使用uwsgi_pass把request传递到socket文件
}
}
关闭文件
通过link以上配置文件到site-enable目录来激活上面的配置:
sudo ln -s /etc/nginx/sites-available/myproject /etc/nginx/sites-enabled
可以通过一下语句检查语法错误:
sudo nginx -t
如果没有问题,通过以下语句重启Nginx服务来读取新的配置:
sudo service nginx restart
好了,现在就大功搞成了,通过浏览器就能够访问到我们的上面的flask应用了
总结:
这篇文章,我们在虚拟环境下创建了一个flask应用,通过创建WSGI接入点使得所有WSGI-capable的应用能够与之交互,并且配置了uWSGI服务器提供此功能,然后,我们创建了一个能够自动启动应用的脚本。随后我们配置了Nginx的server模块来传递web request到应用服务器。
外记:
在试验成功作者的案例后,我准备在我的服务器上部署下这篇文章提到的我以前用flask做的简易博客,我在其过程中遇到了两个问题:
1:如何在virtual环境下安装MySQLdb模块,总所周知,在ubuntu中我们使用apt-get install python-mysqldb来安装,在激活了虚拟环境使用这个安装后进入python使用import MySQLdb依然会报错没有此模块,当然,使用pip install MySQL-python也是不行的,后来查了会儿发现有两种解决方法一时在虚拟环境时使用--system-site-package,这是由于默认的是--no-site-package,也就是不带有原python安装了的库,另一个说法是其实是可以使用pip安装的,只是先要安装相关依赖。我觉得最好的办法是部分使用第一种,也就是在创建虚拟环境时是不是可以部分的引入包,这个尚待明天研究
2:在使用--system-site-package解决了上面的问题后一切都很顺利,当满怀欣喜准备打开网站时弹出了以下东东:
(注:服务器和域名都是在阿里云上买的)
注:关于用uwsgi与nginx同理部署Django的链接
uwsgi文档,其讲的十分全面