CentOS 7如何设置uWSGI和Nginx提供Python应用服务

介绍

在本指南中,我们将设置一个由uWSGI提供服务的简单WSGI应用程序。我们将使用Nginx Web服务器作为应用程序服务器的反向代理,以提供强大的连接处理。我们将在CentOS 7服务器上安装和配置这些组件,没有服务器的用户可以购买和使用腾讯云服务器或者直接使用腾讯云实验室CentOS服务器

定义和概念

先声明一些专业术语

在我们学习之前,我们应该了解一下概念相关的令人困惑的术语。这三个单独的术语看似可以互换,但实际上有不同的含义:

  • WSGIPython规范,定义了应用程序或框架与应用程序/Web服务器之间通信的标准接口。这是为了简化和标准化这些组件之间的通信以实现一致性和可互换性而创建的。这基本上定义了可以在其他协议上使用的API接口。
  • uWSGI:一个应用程序服务器容器,旨在为开发和部署Web应用程序和服务提供完整的环境。主要组件是可以处理不同语言的应用程序服务器。它使用WSGI规范定义的方法与应用程序通信,并通过各种其他协议与其他Web服务器通信。它将来自传统Web服务器的请求转换为应用程序可以处理的格式。
  • uwsgi:由uWSGI服务器实现的快速二进制协议,用于与功能更全面的Web服务器通信。这是有线协议,而不是传输协议。这是与代理uWSGI请求的Web服务器对话的首选方式。

WSGI应用程序要求

WSGI规范定义了Web服务器和堆栈的应用程序部分之间的接口。在此文中,“Web服务器”指的是uWSGI服务器,它负责使用WSGI规范将客户端请求转换为应用程序。这简化了通信过程并创建了松散耦合的组件,因此您可以轻松地更换而不会有太多麻烦。

Web服务器(uWSGI)必须能够通过触发定义的“可调用”来向应用程序发送请求。可调用只是应用程序的入口点,Web服务器可以使用某些参数调用函数。预期参数是环境变量的字典和web服务器(uWSGI)组件提供的。

作为响应,应用程序返回一个迭代,该迭代将用于生成客户端响应的主体。还将调用它作为参数接收的Web服务器组件。触发Web服务器可调用时的第一个参数是HTTP状态代码,第二个参数是元组列表,每个元组定义一个响应头和值以发送回客户端。

通过uWSGI在此实例中提供的交互“Web服务器”组件,我们只需要确保我们的应用程序具有上述能力。我们还将设置Nginx来处理实际的客户端请求并将它们代理到uWSGI服务器。

安装组件

首先,我们需要在CentOS 7服务器上安装必要的组件。我们主要可以使用yumpip

首先,我们需要安装EPEL存储库,以便我们可以访问更多的软件包。我们可以通过输入yum命令轻松完成:

sudo yum install epel-release

现在,我们可以安装我们的组件。我们需要获得Python开发库和头文件,pipPython包管理器以及Nginx

Web服务器和反向代理。我们还需要一个编译器来暂时构建uWSGI二进制文件:

sudo yum install python-pip python-devel nginx gcc

程序包安装完成后,您将可以访问pipPython程序包管理器。我们可以使用它来安装virtualenv包,我们将用它来隔离我们的应用程序的Python环境与系统上可能存在的任何其他环境:

sudo pip install virtualenv

一旦完成,我们就可以开始为我们的应用程序创建一般结构。我们将创建上面讨论的虚拟环境,并将在此环境中安装uWSGI应用程序服务器。

设置App Directory和Virtualenv

我们将首先为我们的应用程序创建一个文件夹。这可以在更完整的应用程序中保存包含实际应用程序代码的嵌套文件夹。出于我们的目的,这个目录将简单地保存我们的虚拟环境和WSGI入口点:

mkdir ~/myapp/

接下来,进入目录,以便我们可以为我们的应用程序设置环境:

cd ~/myapp

使用该virtualenv命令创建虚拟环境。我们将myappenv简单地称之为:

virtualenv myappenv

将在名为myappenv的目录下设置新的Python环境。我们可以通过输入以下命令激活此环

source myappenv/bin/activate

您的提示应更改为表明您现在正在虚拟环境中运行。它看起来像这样:

(myappenv)username@host:~/my_app$

如果您希望离开此环境,只需键入:

deactivate

如果您已停用环境,请重新将其重新激活以继续使用指南。

在此环境处于活动状态时,安装的任何Python包都将包含在此目录层次结构中。它们不会干扰系统的Python环境。考虑到这一点,我们现在可以使用pip将uWSGI服务器安装到我们的环境中。调用uwsgi包(这仍然是uWSGI服务器而不是uwsgi协议):

pip install uwsgi

您可以通过键入以下内容来验证它现在是否可用:

uwsgi --version

如果它返回版本号,则uWSGI服务器可供使用。

创建WSGI应用程序

接下来,我们将使用前面讨论过的WSGI规范要求创建一个非常简单的WSGI应用程序。重申一下,我们必须提供的应用程序组件应具有以下属性:

  • 它必须通过可调用(可以调用的函数或其他语言结构)提供接口
  • 必须将包含类似环境变量的键值和可在服务器上访问的可调用字符(uWSGI)作为参数。
  • 应用程序的可调用应该返回一个迭代,它将生成发送客户端的主体。
  • 应用程序应使用HTTP状态和请求标头调用Web服务器的可调用对象。

我们将在应用程序目录调用的wsgi.py文件中编写应用程序:

nano ~/myapp/wsgi.py

在这个文件中,我们将创建最简单的WSGI兼容应用程序。与所有Python代码一样,请务必注意缩进:

def application(environ, start_response):
    start_response('200 OK', [('Content-Type', 'text/html')])
    return ["<h1 style='color:blue'>Hello There!</h1>"]

上面的代码构成了一个完整的WSGI应用程序。默认情况下,uWSGI将查找被调用的application对象,这就是我们调用application函数的原因。application函数它需要两个参数。

environ是一个像环境变量一样的键值字典。第二个被调用的start_response,是应用程序将在内部使用的名称,用于引用发送的Web服务器(uWSGI)可调用。这两个参数名称都需要被选择,因为它们用于定义的PEP 333规范中的示例WSGI交互。

我们的应用程序必须获取此信息并执行两项操作。首先,它必须使用HTTP状态代码和它想要发回的任何头来调用它收到的可调用对象。在这种情况下,我们发送“200 OK”并将Content-Type标头设置为text/html

其次,它需要返回一个迭代来用作响应体。在这里,我们刚刚使用了一个包含单个HTML字符串的列表。字符串也是可迭代的,但是在列表内部,uWSGI将能够通过一次迭代处理整个字符串。

在现实世界中,此文件可能会用作其他应用程序代码的链接。例如,Django项目wsgi.py默认包含一个文件,用于将来自Web服务器(uWSGI)的请求转换为应用程序(Django)。无论实际应用程序代码有多复杂,简化的WSGI接口都保持不变。这是优势之一。

完成后保存并关闭文件。

要测试代码,我们可以启动uWSGI。我们将告诉它暂时使用HTTP并监听端口8080。我们将传递脚本(后缀已删除):

uwsgi --socket 0.0.0.0:8080 --protocol=http -w wsgi

现在,如果您在Web浏览器中访问服务器的IP地址或域名:8080,则应该看到我们在wsgi.py文件中作为正文传递的第一级标题文本:

WSGI兼容应用程序

验证确实有效后,使用CTRL-C停止服务器。

我们已完成设计我们的实际应用程序。如果您愿意,可以停用我们的虚拟环境:

deactivate

配置uWSGI配置文件

在上面的示例中,我们手动启动了uWSGI服务器并在命令行上传递了一些参数。我们可以通过创建配置文件来避免这种情况。uWSGI服务器可以读取各种格式的配置,但为简单起见,我们将使用.ini格式。

我们将调用myapp.ini文件并将其放在我们的应用程序文件夹中:

nano ~/myapp/myapp.ini

我们需要建立一个名为[uwsgi]的部分。此部分是我们所有配置项的存储块。我们首先要确定我们的应用程序。uWSGI服务器需要知道应用程序的可调用位置。我们可以给出文件和函数:

[uwsgi]
module = wsgi:application

我们希望将初始uwsgi进程标记为主进程,然后再生成其他工作进程。我们将从五个进程开始:

[uwsgi]
module = wsgi:application

master = true
processes = 5

我们实际上将改变uWSGI用于与外界交谈的协议。当我们测试我们的应用程序时,我们指定了--protocol=http以便我们可以从Web浏览器中看到它。由于我们将在uWSGI前将Nginx配置为反向代理,因此我们可以对此进行更改。Nginx实现了一种uwsgi代理机制,这是一种快速的二进制协议,uWSGI可以使用它与其他服务器进行通信。该uwsgi协议实际上是uWSGI的默认协议,因此只需省略协议规范,它就会回归到uwsgi

由于我们正在设计此配置以与Nginx一起使用,我们还将通过改变使用Unix套接字代替网络端口。这更安全,更快捷。

我们将指定自己的用户名来运行uwsgi服务器并拥有套接字文件。我们将在下面创建一个目录/run来放置套接字文件,以便uWSGI和Nginx都可以访问它。我们将调用套接字myapp.sock本身。我们将权限更改为“664”,以便Nginx可以写入它(我们将使用Nginx的组www-data启动uWSGI。我们还将添加vacuum选项,这将在进程停止时删除套接字:

[uwsgi]
module = wsgi:application

master = true
processes = 5

uid = user
socket = /run/uwsgi/myapp.sock
chown-socket = user:nginx
chmod-socket = 660
vacuum = true

我们需要一个最终选项,因为我们将创建一个systemd文件来启动我们的应用程序。Systemd和uWSGI对SIGTERM信号怎样处理应用程序有不同的方式。为了解决这种差异,以便可以使用die-on-termSystemd

按预期处理进程,我们只需要添加一个调用的选项,以便uWSGI终止进程而不是重新加载它:

[uwsgi]
module = wsgi:application

master = true
processes = 5

uid = user
socket = /run/uwsgi/myapp.sock
chown-socket = user:nginx
chmod-socket = 660
vacuum = true

die-on-term = true

完成后保存并关闭文件。此配置文件现在设置为与Upstart脚本一起使用。

创建一个Systemd单元文件来管理应用程序

我们可以在启动时开启uWSGI实例,以便我们的应用程序始终可用。为此,我们可以创建一个systemd单元文件。我们将它放在用户创建的单元文件的/etc/systemd/system目录中。我们将调用单元文件uwsgi.service

sudo nano /etc/systemd/system/uwsgi.service

首先,我们从[Unit]章节开始,我们可以在这里调整元数据。我们唯一要放在这里的是对我们服务的描述:

[Unit]
Description=uWSGI instance to serve myapp

接下来,我们将打开该[Service]部分。因为我们使用的是虚拟环境,所以我们的服务启动命令将比传统命令更复杂。我们将使用一个ExecStartPre命令来确保我们的套接字目录是正确的。这将被允许失败(通过在等号后面加上-)以防它们已经被设置过。这将被传递到一个单独调用的bash

我们也将ExecStart启动uWSGI的实际命令传递给bash。这允许我们执行一些不同的命令,因为bash只能运行一个命令。我们将使用它来更改我们的应用程序目录,激活虚拟环境,并使用我们创建的.ini文件启动uWSGI:

[Unit]
Description=uWSGI instance to serve myapp

[Service]
ExecStartPre=-/usr/bin/bash -c 'mkdir -p /run/uwsgi; chown user:nginx /run/uwsgi'
ExecStart=/usr/bin/bash -c 'cd /home/user/myapp; source myappenv/bin/activate; uwsgi --ini myapp.ini'

剩下要做的就是制定[Install]部分。这将决定我们激活单元时会发生什么。基本上,它指定了单元应自动启动的状态。我们要指定启用时,只要服务器处于多用户模式,该单元就应该自动启动:

[Unit]
Description=uWSGI instance to serve myapp

[Service]
ExecStartPre=-/usr/bin/bash -c 'mkdir -p /run/uwsgi; chown user:nginx /run/uwsgi'
ExecStart=/usr/bin/bash -c 'cd /home/user/myapp; source myappenv/bin/activate; uwsgi --ini myapp.ini'

[Install]
WantedBy=multi-user.target

完成上述配置后,保存并关闭文件。

现在,我们可以通过键入以下命令启动服务:

sudo systemctl start uwsgi

键入以下命令检查它是否开始没有问题:

systemctl status uwsgi

如果没有错误,请通过键入以下内容启用该服务:

sudo systemctl enable uwsgi

您可以通过键入以下内容随时停止服务:

sudo systemctl stop uwsgi

将Nginx配置为代理到uWSGI

我们有WSGI应用程序,并已验证uWSGI可以读取和提供它。我们已经创建了一个配置文件和Systemd单元文件。我们的uWSGI进程将侦听套接字并使用uwsgi协议进行通信。

我们现在需要将Nginx配置为反向代理。Nginx能够使用uwsgi协议代理与uWSGI进行通信。这是一种比HTTP更快的协议,性能更好。

我们将要设置的Nginx配置非常简单。我们将修改现有nginx.conf文件并添加新的服务器块。打开文件sudo进行编辑:

sudo nano /etc/nginx/nginx.conf

在默认服务器块之前,我们将添加自己的服务器块:

http {

    . . .

    include /etc/nginx/conf.d/*.conf;

    server {
    }

    server {
        listen 80 default_server;
        server_name localhost;

        . . .

我们创建的块将保存uWSGI代理的配置。以下配置项的其余部分会放在此块中。服务器块应侦听端口80并响应服务器的域名或IP地址:

server {
    listen 80;
    server_name server_domain_or_IP;
}

之后,我们可以打开一个可以处理所有请求的位置块。在这个块中,我们将包含/etc/nginx/uwsgi_params文件中的uwsgi参数,我们将流量传递给uWSGI正在侦听的套接字:

server {
    listen 80;
    server_name server_domain_or_IP;

    location / {
        include uwsgi_params;
        uwsgi_pass unix:/run/uwsgi/myapp.sock;
    }
}

对于更完整的应用程序,我们可以进行一些改进。例如,我们可能会在此块之外定义许多上游uWSGI服务器,然后将它们传递给它。我们可能会包含更多uWSGI参数。我们也可以直接处理来自Nginx的任何静态文件,并将动态请求传递给uWSGI实例。

我们的三行应用程序中不需要任何这些功能,因此我们可以保存并关闭该文件。

您可以通过键入以下内容进行测试以确保您的Nginx配置有效:

sudo nginx -t

如果返回没有任何错误,请键入以下命令启动服务:

sudo systemctl start nginx

启动服务时开启Nginx:

sudo systemctl enable nginx

您应该能够访问服务器的域名或IP地址并查看您配置的应用程序

结论

您已经创建了一个简单的WSGI应用程序,并且可以深入了解如何设计更复杂的应用程序。我们已将uWSGI应用程序容器/服务器安装到专用虚拟环境中,以便为我们的应用程序提供服务。我们制作了一个配置文件和一个Systemd单元文件来自动执行此过程。在uWSGI服务器的前面,我们设置了一个Nginx反向代理,它可以使用uwsgi有线协议与uWSGI进程通信。

在设置实际生产环境时,您可以轻松了解如何扩展它。例如,uWSGI能够使用“emperor模式”管理多个应用程序。您可以扩展Nginx配置以在uWSGI实例之间进行负载平衡,或者为您的应用程序处理静态文件。在为多个应用程序提供服务时,根据您的需要,可以全局安装uWSGI来代替虚拟环境可能更好一些。这些组件都非常灵活,因此您能够调整其配置以适应许多不同的场景。


参考文献:《How To Set Up uWSGI and Nginx to Serve Python Apps on CentOS 7》

原创声明,本文系作者授权云+社区发表,未经许可,不得转载。

如有侵权,请联系 yunjia_community@tencent.com 删除。

编辑于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏小程序之家

如何在小程序中实现文件上传下载

在如何实现小程序登录鉴权这篇文章中,我们实现了小程序的wx.request请求操作,除了request之外,小程序还有文件下载wx.downloadFile和文...

12.6K7
来自专栏老马寒门IT

08Vue.js快速入门-Vue综合实战项目

8.1. 前置知识学习 npm 学习 官方文档 推荐资料 npm入门 npm介绍 需要了解的知识点 package.json 文件相关配置选项 ...

4147
来自专栏搞前端的李蚊子

Vue.js实现一个SPA登录页面的过程

技术栈 vue.js 主框架 vuex 状态管理 vue-router 路由管理 一般过程 在一般的登录过程中,一种前端方案是: 检查状态:进入页面时或者路...

1.1K12
来自专栏云计算教程系列

如何在CentOS 7上使用InfluxDB分析系统指标

InfluxDB是一个时间序列,指标和分析数据库。时间序列数据库旨在解决存储在一段时间内进行的连续测量所产生的数据的问题。此数据可能包含系统指标(如CPU和内存...

3343
来自专栏云计算教程系列

如何使用Prometheus监视您的Ubuntu 14.04服务器

Prometheus是由SoundCloud开发的开源监控系统。与其他监控系统(如InfluxDB和Graphite)一样,Prometheus将其所有数据存储...

1920
来自专栏云计算教程系列

如何在CentOS 7上使用InfluxDB分析系统指标

InfluxDB是一个时间序列,指标和分析数据库。时间序列数据库旨在解决存储在一段时间内进行的连续测量所产生的数据的问题。此数据可能包含系统指标(如CPU和内存...

1641
来自专栏Samego开发资源

Linux自定义命令指令 | alias

2027
来自专栏王小雷

React-Native-Android-Studio整合开发+环境配置+官方实例

linux下React Native开发环境搭建,使用Android-studio工具进行React Native整合开发。 参考React Native的...

5159
来自专栏云计算教程系列

如何在Ubuntu 14.04上设置uWSGI和Nginx以服务Python应用程序

在本教程中,我们将设置一个由uWSGI提供服务的简单WSGI应用程序。我们将使用Nginx Web服务器作为应用程序服务器的反向代理,以提供更强大的连接处理。我...

2050
来自专栏云计算教程系列

如何使用Prometheus监控CentOS 7服务器

Prometheus是由SoundCloud开发的开源监控系统。与其他监控系统(如InfluxDB和Graphite)一样,Prometheus将其所有数据存储...

7860

扫码关注云+社区

领取腾讯云代金券