如何在CentOS 7上使用uWSGI和Nginx为Flask应用程序提供服务

2018-10-22 11:38:16 浏览数 (1)

介绍

在本指南中,我们将使用CentOS 7上的Flask微框架设置一个简单的Python应用程序。本文的大部分内容将是关于如何设置uWSGI应用程序服务器以启动应用程序和Nginx作为前端结束反向代理。

准备

一台已经设置好可以使用sudo命令的非root账号的CentOS服务器,并且已开启防火墙。没有服务器的同学可以在这里购买,不过我个人更推荐您使用免费的腾讯云开发者实验室进行试验,学会安装后再购买服务器。

当您准备好继续时,请继续阅读。

从CentOS和EPEL存储库安装组件

我们的第一步是从存储库安装我们需要的所有部分。我们需要添加EPEL存储库,其中包含一些额外的包,以便安装我们需要的一些组件。

您可以键入以下命令启用EPEL回购:

代码语言:javascript复制
sudo yum install epel-release

一旦在我们的系统上配置了对EPEL存储库的访问,我们就可以开始安装我们需要的软件包。我们将安装pipPython包管理器,以便安装和管理我们的Python组件。我们还将获得构建uWSGI所需的编译器和Python开发文件。我们现在也会安装Nginx。

您可以键入以下命令安装所有这些组件:

代码语言:javascript复制
sudo yum install python-pip python-devel gcc nginx

创建Python虚拟环境

接下来,我们将设置一个虚拟环境,以便将Flask应用程序与系统上的其他Python文件隔离开来。

首先使用pip方法安装virtualenv软件包:

代码语言:javascript复制
sudo pip install virtualenv

现在,我们可以为Flask项目创建一个上级目录。创建后移动到目录:

代码语言:javascript复制
mkdir ~/myproject
cd ~/myproject

我们可以通过输入以下内容创建一个虚拟环境来存储我们的Flask项目的Python需求:

代码语言:javascript复制
virtualenv myprojectenv

这将安装Python的本地副本和pip进项目目录中名为myprojectenv的目录。

在我们在虚拟环境中安装应用程序之前,我们需要激活它。您可以输入以下命令:

代码语言:javascript复制
source myprojectenv/bin/activate

您的提示将更改为表示您现在正在虚拟环境中运行。它看起来像这样:(myprojectenv)user@host:~/myproject$

设置Flask应用程序

现在您已进入虚拟环境,我们可以安装Flask和uWSGI并开始设计我们的应用程序:

安装Flask和uWSGI

我们可以使用本地实例pip来安装Flask和uWSGI。键入以下命令以获取这两个组件:

代码语言:javascript复制
pip install uwsgi flask

创建示例应用程序

现在我们已经有了Flask,我们可以创建一个简单的应用程序。Flask是一个微框架。它不包括许多功能更全面的框架可能存在的工具,并且主要作为一个模块存在,您可以将其导入到项目中以帮助您初始化Web应用程序。

虽然您的应用程序可能更复杂,但我们将在单个文件中创建Flask应用程序,我们将调用它myproject.py

代码语言:javascript复制
nano ~/myproject/myproject.py

在此文件中,我们将放置我们的应用程序代码。基本上,我们需要导入flask并实例化Flask对象。我们可以使用它来定义在请求特定路由时应该运行的函数。我们将在代码中调用Flask应用程序application来复制您在WSGI规范中找到的示例:

代码语言:javascript复制
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')

这基本上定义了访问根域时要呈现的内容。完成后保存并关闭文件。

您可以输入以下命令测试Flask应用:

代码语言:javascript复制
python myproject.py

访问服务器的域名或IP地址,然后访问Web浏览器中终端输出(最有可能是:5000)中指定的端口号。你应该看到这样的东西:

完成后,在终端窗口中按CTRL-C几次以停止Flask开发服务器。

创建WSGI入口点

接下来,我们将创建一个文件,作为我们应用程序的入口点。这将告诉我们的uWSGI服务器如何与应用程序进行交互。

我们将命名该文件为wsgi.py

代码语言:javascript复制
nano ~/myproject/wsgi.py

该文件非常简单,我们只需从我们的应用程序导入Flask实例,然后运行它:

代码语言:javascript复制
from myproject import application
​
if __name__ == "__main__":
    application.run()

完成后保存并关闭文件。

配置uWSGI

我们现在编写了我们的申请并建立了我们的切入点 我们现在可以转到uWSGI了。

测试uWSGI服务

我们要做的第一件事是测试以确保uWSGI可以为我们的应用程序提供服务。

我们可以通过简单地传递入口点的名称来实现这一点。我们还将指定套接字,以便它将在公共可用接口和协议上启动,以便它将使用HTTP而不是uwsgi二进制协议:

代码语言:javascript复制
uwsgi --socket 0.0.0.0:8000 --protocol=http -w wsgi

如果您访问附加:8000到Web浏览器末尾的服务器域名或你的IP地址,您应该会看到如下所示的页面:

确认它运行正常后,在终端窗口中按CTRL-C。

我们现在已经完成了虚拟环境,因此我们可以将其停用:

代码语言:javascript复制
deactivate

现在任何操作都将在系统的Python环境中完成。

创建uWSGI配置文件

我们已经测试过uWSGI能够为我们的应用程序提供服务,但我们希望能够为长期使用提供更强大的功能。我们可以使用我们想要的选项创建一个uWSGI配置文件。

让我们把它放在我们的项目目录中并调用它myproject.ini

代码语言:javascript复制
nano ~/myproject/myproject.ini

在内部,我们将从头[uwsgi]开始,以便uWSGI知道应用设置。我们将通过引用我们的wsgi.py文件指定模块,减去扩展名:

代码语言:javascript复制
[uwsgi]
module = wsgi

接下来,我们将告诉uWSGI以主模式启动并生成五个工作进程来提供实际请求:

代码语言:javascript复制
[uwsgi]
module = wsgi
​
master = true
processes = 5

当我们进行测试时,我们在网络端口上暴露了uWSGI。但是,我们将使用Nginx来处理实际的客户端连接,然后将请求传递给uWSGI。由于这些组件在同一台计算机上运行,因此首选Unix套接字,因为它更安全,更快。我们将调用套接字myproject.sock并将其放在此目录中。

我们还必须更改套接字的权限。我们稍后将给予Nginx组对uWSGI进程的所有权,因此我们需要确保套接字的组所有者可以从中读取信息并写入它。我们还将在进程停止时通过添加“vacuum”选项来清理套接字:

代码语言:javascript复制
[uwsgi]
module = wsgi
​
master = true
processes = 5
​
socket = myproject.sock
chmod-socket = 660
vacuum = true

我们需要做的最后一件事是设置die-on-term选项。这是必要的,因为Upstart init系统和uWSGI对于不同的过程信号应该意味着什么有不同的想法。设置此选项会对齐两个系统组件,实现预期的行为:

代码语言:javascript复制
[uwsgi]
module = wsgi
​
master = true
processes = 5
​
socket = myproject.sock
chmod-socket = 660
vacuum = true
​
die-on-term = true

您可能已经注意到我们没有像命令行那样指定协议。这是因为默认情况下,uWSGI使用uwsgi协议,这是一种旨在与其他服务器通信的快速二进制协议。Nginx本身可以说这个协议,因此使用它比强制通过HTTP进行通信更好。

完成后,保存并关闭文件。

创建一个系统单元文件

我们需要处理的下一件事是Systemd服务单元文件。创建Systemd单元文件将允许CentOS的init系统在服务器启动时自动启动uWSGI并为Flask应用程序提供服务。

/etc/systemd/system目录创建一个单以.service为结尾的元文件以开始:

代码语言:javascript复制
sudo nano /etc/systemd/system/myproject.service

在里面,我们将从该[Unit]部分开始,该部分用于指定元数据和依赖关系。我们将在此处描述我们的服务并告诉init系统仅在达到网络目标后启动它:

代码语言:javascript复制
[Unit]
Description=uWSGI instance to serve myproject
After=network.target

接下来,我们将打开该[Service]部分。我们将指定我们希望在其下运行进程的用户和组。我们将为该流程提供常规用户帐户所有权,因为它拥有所有相关文件。我们将授予Nginx用户组所有权,以便它可以与uWSGI进程轻松通信。

然后,我们将映射工作目录并设置PATH环境变量,以便init系统知道进程的可执行文件所在的位置(在我们的虚拟环境中)。然后我们将指定命令启动服务。Systemd要求我们提供uWSGI可执行文件的完整路径,该文件安装在我们的虚拟环境中。我们将传递.ini我们在项目目录中创建的配置文件的名称:

代码语言:javascript复制
[Unit]
Description=uWSGI instance to serve myproject
After=network.target
​
[Service]
User=user
Group=nginx
WorkingDirectory=/home/user/myproject
Environment="PATH=/home/user/myproject/myprojectenv/bin"
ExecStart=/home/user/myproject/myprojectenv/bin/uwsgi --ini myproject.ini

最后,我们将添加一个[Install]部分。如果我们在启动时启动它,这将告诉Systemd将此服务链接到何处。我们希望在常规多用户系统启动并运行时启动此服务:

代码语言:javascript复制
[Unit]
Description=uWSGI instance to serve myproject
After=network.target
​
[Service]
User=user
Group=nginx
WorkingDirectory=/home/user/myproject
Environment="PATH=/home/user/myproject/myprojectenv/bin"
ExecStart=/home/user/myproject/myprojectenv/bin/uwsgi --ini myproject.ini
​
[Install]
WantedBy=multi-user.target

这样,我们的Systemd服务文件就完成了。立即保存并关闭它。

我们现在可以启动我们创建的uWSGI服务并启用它,以便它在启动时启动:

代码语言:javascript复制
sudo systemctl start myproject
sudo systemctl enable myproject

配置Nginx到代理请求

我们的uWSGI应用程序服务器现在应该启动并运行,等待项目目录中的套接字文件上的请求。我们需要配置Nginx以使用uwsgi协议将Web请求传递给该套接字。

首先打开Nginx的默认配置文件:

代码语言:javascript复制
sudo nano /etc/nginx/nginx.conf

在文件中已存在的另一个server {}块上方打开一个服务器块:

代码语言:javascript复制
http {
    . . .
​
    include /etc/nginx/conf.d/*.conf;
​
    server {
    }
​
    server {
        listen 80 default_server;
​
        . . .

我们将把Flask应用程序的所有配置放在这个新块中。我们将首先指定此块应该侦听默认端口80,并且它应该响应我们服务器的域名或IP地址:

代码语言:javascript复制
server {
    listen 80;
    server_name server_domain_or_IP;
}

我们需要添加的唯一其他内容是匹配每个请求的位置块。在此块中,我们将包含uwsgi_params指定需要设置的一般uWSGI参数的文件。然后我们将请求传递给我们使用该uwsgi_pass指令定义的套接字:

代码语言:javascript复制
server {
    listen 80;
    server_name server_domain_or_IP;
​
    location / {
        include uwsgi_params;
        uwsgi_pass unix:/home/user/myproject/myproject.sock;
    }
}

这实际上是我们为应用程序提供服务所需的全部内容。完成后保存并关闭文件。

nginx用户必须具有以便在那里访问套接字文件访问我们的应用程序目录。默认情况下,CentOS会严格限制每个用户的主目录,因此我们会将nginx用户添加到用户的组中,以便我们可以打开授予访问权限所需的最低权限。

您可以使用以下命令将nginx用户添加到用户组。用命令中的自己的用户名替换user

代码语言:javascript复制
sudo usermod -a -G user nginx

现在,我们可以在我们的主目录上为我们的用户组授予执行权限。这将允许Nginx进程输入和访问以下内容:

代码语言:javascript复制
chmod 710 /home/user

设置权限后,我们可以测试我们的Nginx配置文件是否存在语法错误:

代码语言:javascript复制
sudo nginx -t

如果返回没有指出任何问题,我们可以启动并启用Nginx进程,以便它在启动时自动启动:

代码语言:javascript复制
sudo systemctl start nginx
sudo systemctl enable nginx

您现在应该可以在Web浏览器中访问服务器的域名或IP地址,并查看您的应用程序:

结论

在本指南中,我们在Python虚拟环境中创建了一个简单的Flask应用程序。我们创建一个WSGI入口点,以便任何支持WSGI的应用程序服务器都可以与它进行交互,然后配置uWSGI应用程序服务器以提供此功能。之后,我们创建了Systemd服务单元文件,以便在启动时自动启动应用程序服务器。我们创建了一个Nginx服务器块,它将Web客户端流量传递给应用服务器,从而转发外部请求。

Flask是一个非常简单但非常灵活的框架,旨在为您的应用程序提供功能,而不会对结构和设计过于严格限制。您可以使用本指南中描述的常规堆栈来为您设计的烧瓶应用程序提供服务。

更多CentOS教程请前往腾讯云 社区学习更多知识。


参考文献:《How To Serve Flask Applications with uWSGI and Nginx on CentOS 7》

0 人点赞