如何使用uWSGIWeb服务器和Nginx部署PythonWSGI应用程序
介绍
正如我们在 Python Web 服务器比较 文章中介绍的那样,uWSGI 是一个庞大的项目,它能够做的不仅仅是服务于 Web 应用程序。 然而,它广泛的功能,加上相对易于配置,使其成为满足许多部署需求的绝佳选择——尤其是当它与 Nginx 结合使用时。
在这篇 DigitalOcean 文章中,我们旨在深入讨论 uWSGI,并介绍不仅安装服务器,而且实际部署基于各种框架的 Python 应用程序的必要步骤,涵盖了小型、中型甚至相对大型应用程序的每个重要步骤。生产。
我们还将讨论在此设置中使用 Nginx(以及为什么),因为 Nginx 和 uWSGI 是原生构建的,可以相互协作,形成适合大多数部署的完美堆栈。
词汇表
1. 理解 uWSGI 和使用 Nginx
- uWSGI 简介
- 使用 Nginx 部署 Web 应用程序
- 使用 Nginx 作为 uWSGI 的反向代理
2. 为生产准备 Droplet
- 更新默认操作系统
- 设置 Python、pip 和 virtualenv
- 创建虚拟 (Python) 环境
- 下载和安装 uWSGI
- 下载和安装 Nginx
3. 使用 uWSGI 服务 Python WSGI 应用程序
- WSGI
- WSGI 应用程序对象(可调用):
wsgi.py
- 运行服务器
- 配置 uWSGI
- uWSGI 的常用配置
- 使用信号管理 uWSGI 服务器和进程
4. 配置 Nginx
5. 配置 uWSGI
6. 生产服务器的其他提示、建议和设置
理解 uWSGI 和使用 Nginx
uWSGI 是一个雄心勃勃的项目。 它的工具集允许您做的不仅仅是托管 Web 应用程序。 由于它以如此出色的方式完成了这项工作,因此多年来它已被证明是许多系统管理员和开发人员在部署应用程序时不可或缺的工具。
Nginx,从 0.8.40 版本开始支持 uwsgi 协议(uWSGI 自己的)。 这使得在 uWSGI 上运行的 WSGI 应用程序能够以最佳方式与 Nginx 进行通信。 这对您来说意味着非常易于配置的部署的可能性,这些部署具有高度的灵活性(和功能性),并受益于随之而来的许多底层优化。 总之,这使得 uWSGI 与 Nginx 结合成为许多部署场景的绝佳选择。
uWSGI 简介
以下是上述 DigitalOcean Python 服务器比较 文章的摘录:
“尽管命名约定非常混乱,uWSGI 本身是一个包含许多组件的庞大项目,旨在为构建 托管服务 提供完整的软件堆栈。 这些组件之一,uWSGI 服务器,运行 Python WSGI 应用程序。 它能够使用各种协议,包括它自己的uwsgi 有线协议,它与SCGI 准相同。 为了满足在应用程序服务器前使用独立 HTTP 服务器的可理解需求,NGINX 和 Cherokee Web 服务器被模块化以支持 uWSGI [自己的] 性能最佳的 uwsgi 协议,以直接控制其进程。”
uWSGI 亮点
- uWSGI 带有一个 WSGI 适配器,它完全支持在 WSGI 上运行的 Python 应用程序。
- 它与 libpython 链接。 它在启动时加载应用程序代码,并充当 Python 解释器。 它解析传入的请求并调用 Python 可调用对象。
- 它直接支持流行的 NGINX Web 服务器(以及 Cherokee+ 和 lighttpd)。
- 它是用 C 编写的。
- 它的各种组件可以做的不仅仅是运行一个应用程序,这对于扩展来说可能很方便。
- 目前(截至 2013 年底),它正在积极开发并具有快速的发布周期。
- 它具有用于运行应用程序(异步和同步)的各种引擎。
- 这可能意味着运行时内存占用更少。
使用 Nginx 部署 Web 应用程序
Nginx 是一个非常高性能的 Web 服务器/(反向)代理。 由于重量轻、相对容易使用和易于扩展(使用附加组件/插件),它已经流行起来。 由于其架构,它能够处理 很多 的请求(几乎无限制),这取决于您的应用程序或网站负载 - 使用其他一些较旧的替代方案可能真的很难解决。
记住:“处理”连接在技术上意味着不丢弃它们,并且能够使用 something 为它们服务。 您仍然需要您的应用程序和数据库运行良好,以便 Nginx 为客户端提供非错误消息的响应。
使用 Nginx 作为 uWSGI 的反向代理
许多框架和应用程序服务器可以提供静态文件(例如 javascript、css、图像等)以及来自实际应用程序的响应。 但是,更好的做法是让(反向代理)服务器(例如 Nginx)处理提供这些文件和管理连接的任务(requests)。 这减轻了应用程序服务器的大量负载,为您提供了更好的整体性能。
随着应用程序的增长,您将希望对其进行优化,并在时机成熟时将其分布在服务器 (VPS) 上,以便能够同时处理更多连接并拥有通常更健壮的架构。 在您的应用程序服务器前面有一个反向代理可以从一开始就帮助您解决这个问题。
Nginx 的可扩展性(例如 本机缓存以及故障转移和其他机制)也是一项伟大的壮举,与(更简单的)应用程序服务器不同,它有利于 Web 应用程序。
基本服务器架构示例:
Client Request ----> Nginx (Reverse-Proxy) | /|\ | | `-> App. Server I. 127.0.0.1:8081 | `--> App. Server II. 127.0.0.1:8082 `----> App. Server III. 127.0.0.1:8083
注意: 当应用程序设置为侦听 127.0.0.1
上的传入连接时,只能在本地访问它。 但是,如果您使用 0.0.0.0
,它也会接受来自外部的连接。
为生产准备 Droplet
在本节中,我们将为生产准备我们的虚拟服务器(即 用于部署我们的应用程序)。
我们将从:
- 更新默认操作系统
- 下载和安装常用的 Python 工具(即 点,虚拟环境)
- 创建一个包含应用程序的虚拟环境(其依赖项,例如 uWSGI 驻留在其中)
注意: 此处给出的说明保持简短。 要了解更多信息,请查看我们关于 pip 和 virtualenv 的操作指南文章:常用 Python 工具:使用 virtualenv、使用 Pip 安装和管理包。
更新默认操作系统
注意: 我们将使用最新版本的操作系统在新 VPS 上执行以下设置和准备工作。 理论上,在服务器上尝试它们应该不会有问题。 但是,如果您已经在积极使用它,我们强烈建议您在尝试之前切换到新系统。
为确保我们拥有最新可用版本的默认应用程序,我们需要更新我们的系统。
对于基于 Debian 的系统(即 Ubuntu、Debian),运行以下命令:
aptitude update aptitude -y upgrade
对于基于 RHEL 的系统(即 CentOS),运行以下命令:
yum -y update
设置 Python、pip 和 virtualenv
CentOS / RHEL 用户注意事项:
CentOS / RHEL,默认情况下,作为一个非常精简的服务器。 它的工具集很可能已经过时以满足您的需求,它不是用来运行您的应用程序,而是为服务器的系统工具(例如 百胜)。
为了准备你的 CentOS 系统,需要设置 Python(即 从源代码编译)和 pip / virtualenv 需要使用该解释器安装。
要了解 如何在 CentOS 6.4 和 5.8 上使用 pip 和 virtualenv 设置 Python 2.7.6 和 3.3.3,请参阅:如何设置 Python 2.7.6 和 3.3。 3 在 CentOS 上。
在 Ubuntu 和 Debian 上,默认提供最新版本的 Python 解释器,您可以使用它。 它使我们只需要安装有限数量的附加软件包:
- python-dev(开发工具)
- pip(管理包)
- virtualenv(创建隔离的虚拟环境)
蟒蛇开发:
python-dev 是一个操作系统级别的包,其中包含用于构建 Python 模块的扩展开发工具。
运行以下命令以使用 aptitude 安装 python-dev:
aptitude install python-dev
点:
pip 是一个包管理器,它将帮助我们安装我们需要的应用程序包。
运行以下命令安装 pip:
curl https://bitbucket.org/pypa/setuptools/raw/bootstrap/ez_setup.py | python - curl https://raw.github.com/pypa/pip/master/contrib/get-pip.py | python - export PATH="/usr/local/bin:$PATH"
您可能需要 sudo 权限。
虚拟环境:
最好在自己的 环境 中包含 Python 应用程序及其所有依赖项。 可以将环境最好(简单地说)描述为所有内容所在的隔离位置(目录)。 为此,使用了一个名为 virtualenv 的工具。
运行以下命令以使用 pip 安装 virtualenv:
sudo pip install virtualenv
创建自包含的虚拟 (Python) 环境
准备好所有必要的工具供我们使用,我们可以创建一个环境来部署我们的应用程序。
记住: 如果您的项目的开发(本地)机器上没有 virtualenv,您应该考虑创建一个并将您的应用程序(及其依赖项)移动到其中。
让我们首先创建一个文件夹,其中将包含 虚拟环境 和 您的应用程序模块 :
您可以在此处使用任何名称以满足您的需要。
mkdir my_app
我们可以继续进入这个文件夹并在里面创建一个新的虚拟环境:
您还可以为您的虚拟环境选择任何您喜欢的名称。
cd my_app virtualenv my_app_venv
让我们在那里创建一个新文件夹来包含您的 Python 应用程序模块:
这是您的应用程序模块所在的文件夹。
mkdir app
并激活虚拟环境中的解释器以使用它:
如果您选择“my_app_venv”以外的名称,请确保使用您为虚拟环境选择的名称。
source my_app_venv/bin/activate
最后,您的主应用程序部署目录应如下所示:
my_app # Main Folder to Contain Everything Together | |=== my_app_venv # V. Env. folder with the Python Int. |=== app # Your application module |.. |.
下载和安装 uWSGI
将所有与应用程序相关的元素尽可能多地包含在虚拟环境中始终是推荐的方式。 所以我们将下载并安装uWSGI。
如果你不在环境中工作,uWSGI 将被安装 globally(即 全系统可用)。 不建议这样做。 始终选择使用 virtualenv。
要使用 pip 安装 uWSGI,请运行以下命令:
pip install uwsgi
记住:要了解更多关于pip的用法和功能,请参考以下文章常用Python工具:使用virtualenv,使用pip安装,管理包[X201X ]。
下载和安装 Nginx
CentOS / RHEL 用户注意事项:
以下说明不适用于 CentOS 系统。 请在此处 参阅 CentOS 的说明 。
运行以下命令以使用默认系统包管理器 aptitude 安装 Nginx:
sudo aptitude install nginx
要运行 Nginx,您可以使用以下命令:
sudo service nginx start
要停止 Nginx,您可以使用以下命令:
sudo service nginx stop
要重启 Nginx,可以使用以下命令:
每次重新配置 Nginx 后,都需要重新启动或重新加载才能使新设置生效。
sudo service nginx restart
注意:想了解更多关于Ubuntu上的Nginx,请参考我们的文章:如何在Ubuntu 12.04上安装Nginx。
使用 uWSGI 服务 Python WSGI 应用程序
在本节中,我们将看到 Python WSGI 应用程序如何与 uWSGI Web 服务器一起工作。 使用 uWSGI 服务 Python WSGI 应用程序与其他应用程序容器没有什么不同。 与其他服务器一样,uWSGI 需要的是为您的应用程序提供一个入口点( 可调用的)。 在启动期间,这个可调用对象连同配置变量一起被传递给 uWSGI 并开始执行其工作。 当请求到达时,它会对其进行处理并将其传递给应用程序的控制器进行处理。
建筑学:
........ /|\ | | `-> App. Server I. 127.0.0.1:8080 <--> Application | `--> App. Server II. 127.0.0.1:8081 <--> Application .....
WSGI
简而言之,WSGI 是 Web 服务器和应用程序本身之间的接口。 它的存在是为了确保各种服务器和应用程序(框架)之间以标准化的方式相互工作,在必要时允许互换性(例如 从开发环境切换到生产环境),这是当今的必备需求。
注意:如果您有兴趣了解更多关于WSGI和Python Web服务器的知识,请查看我们的文章:基于Python的Web服务器比较网络应用程序。
WSGI 应用程序对象(可调用):“wsgi.py”
如上所述,在 WSGI 上运行的 Web 服务器需要一个应用程序对象(即 您的应用程序的)。
对于大多数框架和应用程序,这包括一个 wsgi.py 来包含和提供一个应用程序对象(或可调用)以供服务器使用。
我们将从创建一个示例性的 wsgi.py 开始,然后将其导入并由 uWSGI 用于运行应用程序。
您可以选择任何名称而不是 wsgi.py。 但是,这些是常用的(例如 由姜戈)。
让我们开始创建一个 wsgi.py 文件来包含一个基本的 WSGI 应用程序。
运行以下命令以使用文本编辑器 nano 创建 wsgi.py:
nano wsgi.py
让我们继续移动(复制/粘贴)内部的基本 WSGI 应用程序代码(应该替换为您自己的应用程序的生产可调用代码):
def application(env, start_response): start_response('200 OK', [('Content-Type', 'text/html')]) return ["Hello!"]
这是服务器包含的文件,每次请求到来时,服务器使用此应用程序可调用来运行应用程序的请求处理程序(即 controllers) 在解析 URL 时(例如 mysite.tld/控制器/方法/变量)。
放入应用程序代码后,按 CTRL+X,然后按 Y 确认,将此文件保存在虚拟环境和包含实际应用程序的应用程序模块旁边的“my_app”文件夹中。
注意: 这个 WSGI 应用程序是同类中最基本的示例。 您将需要替换此代码块以包含应用程序模块中您自己的应用程序对象。
完成后,您的主应用程序部署目录应如下所示:
my_app # Main Folder to Contain Everything Together | |=== my_app_venv # V. Env. folder with the Python Int. |=== app # Your application module | |--- wsgi.py # File containing application callable |.. |.
运行服务器
由于它的灵活性,uWSGI 有很多选项和配置以及许多可能的使用方式。 在不让事情从一开始就复杂化的情况下,我们将尽可能简单地使用它,然后继续使用更高级的方法。
简单的使用示例:
uwsgi [option] [option 2] .. -w [wsgi file with app. callable]
要简单地运行 uWSGI 以从 wsgi.py 开始为应用程序提供服务,请运行以下命令:
uwsgi --socket 127.0.0.1:8080 --protocol=http -w wsgi
这将在前台运行服务器。 如果要停止它,请按 CTRL+C。
要在后台运行服务器,请运行以下命令:
uwsgi --socket 127.0.0.1:8080 --protocol=http -w wsgi &
[!] 重要提示: 当您使用 配置 Nginx 部分中的配置运行服务器以使用 Nginx 时,请确保从参数链中删除 --protocol=http
,否则 Nginx 和 uWSGI 将无法相互通信。
当您在后台运行应用程序时,您将需要使用进程管理器(例如 htop) 杀死(或停止)它。 有关详细信息,请参阅以下部分。
使用信号管理 uWSGI 服务器和进程
管理 uWSGI 包括在运行时执行的操作。 为此任务设置了各种命令来操作该过程:
- SIGHUP
-HUP
gracefully reloads the workers and the application - SIGTERM
-TERM
“brutally” reloads - 信号情报
-INT
and SIGQUIT-QUIT
kills all the workers immediately - SIGUSR1
-USR1
prints statistics (stdout) - SIGUSR2
-USR2
prints worker status - 西格
-URG
restores a snapshot - SIGTSTP
-TSTP
pauses, suspends or resumes an instance - 信号机
-WINCH
wakes up a worker blocked in a 系统调用
带有信号的示例管理:
使用 SIGHUP 重启服务器
此命令优雅地重新启动服务器。 这意味着,它等待当前工作人员的工作完成,然后在再次生成它们之前终止它们,并继承其设置。
用法:kill -HUP [PID]
如果您不想指定 PID,可以使用
pidfile
选项让 uWSGI 将其写入文件,然后您可以使用该文件来管理进程。
使用 SIGINT 停止服务器
要停止服务器及其进程,您需要使用 -INT
信号。 这将终止后台的所有内容。
示例:kill -INT [PID]
配置 Nginx
在设置好 uWSGI 来运行我们的应用程序之后,我们现在需要对 Nginx 做同样的事情,以便它与 uWSGI 服务器通信。 为此,我们需要修改 Nginx 的配置文件:nginx.conf
运行以下命令打开 nginx.conf
并使用 nano 文本编辑器进行编辑:
sudo nano /etc/nginx/nginx.conf
之后,您可以将文件替换为以下示例配置,以使 Nginx 作为反向代理工作,与您的应用程序对话。
注意:要了解加入SSL支持,请先阅读这篇文章:在Nginx上创建SSL证书。
Web 应用程序的示例配置:
worker_processes 1; events { worker_connections 1024; } http { sendfile on; gzip on; gzip_http_version 1.0; gzip_proxied any; gzip_min_length 500; gzip_disable "MSIE [1-6]\."; gzip_types text/plain text/xml text/css text/comma-separated-values text/javascript application/x-javascript application/atom+xml; # Configuration containing list of application servers upstream uwsgicluster { server 127.0.0.1:8080; # server 127.0.0.1:8081; # .. # . } # Configuration for Nginx server { # Running port listen 80; # Settings to by-pass for static files location ^~ /static/ { # Example: # root /full/path/to/application/static/file/dir; root /app/static/; } # Serve a static file (ex. favico) outside static dir. location = /favico.ico { root /app/favico.ico; } # Proxying connections to application servers location / { include uwsgi_params; uwsgi_pass uwsgicluster; proxy_redirect off; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Host $server_name; } } }
完成修改配置后,按 CTRL+X 并按 Y 确认保存并退出。 您需要重新启动 Nginx 才能使更改生效。
运行以下命令重启 Nginx:
sudo service nginx stop sudo service nginx start
注意:想了解更多关于Nginx的知识,请参考我们的文章:如何在VPS上配置Nginx Web服务器。
配置 uWSGI
当启动 uWSGI 为应用程序提供服务时,有几种方法可以为其提供必要的配置,例如要运行的套接字、进程数、主进程设置等。 在本节中,我们将讨论其中的三个:
- 将配置作为参数传递
- 使用
.ini
文件进行配置 - 使用
.json
文件进行配置
注意: uWSGI支持各种协议和方法来获取这些配置文件,例如stdin和HTTP。
选项 #1:将配置作为参数传递:
尽管有时很容易让人感到困惑和难以管理,但运行 uWSGI 的最基本方式就像任何其他 shell 脚本一样——通过为其提供必要的配置作为参数。
使用示例:
# uwsgi [option] [option 2] .. -w [wsgi.py with application callable] # Simple server running *wsgi* uwsgi --socket 127.0.0.1:8080 -w wsgi # Running Pyramid (Paster) applications uwsgi --ini-paste production.ini # Running web2py applications uwsgi --pythonpath /path/to/app --module wsgihandler # Running WSGI application with specific module / callable names uwsgi --module wsgi_module_name --callable application_callable_name uwsgi -w wsgi_module_name:application_callable_name
有关如何运行 uWSGI 的更多示例,请考虑访问其文档以获取 示例配置 。
选项 #2:使用 .ini
文件进行配置
为 uWSGI 提供配置的另一种(并且可能)更好的方法是通过 .ini
文件。 这些文件具有简单的结构(参见下面的示例),并且需要在每次执行 uWSGI 启动脚本时显式传递。
示例 .ini
结构(example_config.ini):
[uwsgi] # ------------- # Settings: # key = value # Comments >> # # ------------- # socket = [addr:port] socket = 127.0.0.1:8080 # Base application directory # chdir = /full/path chdir = /my_app # WSGI module and callable # module = [wsgi_module_name]:[application_callable_name] module = app:application # master = [master process (true of false)] master = true # processes = [number of processes] processes = 5 ..
使用示例:
uwsgi --ini example_config.ini
选项 #3:使用 .json
文件进行配置
除了结构之外,使用 .json
文件与上面显示的示例相同。
示例 .json
结构(example_config.json):
{ "uwsgi": { "socket": ["127.0.0.1:8080"], "module": "my_app:app", "master": true, "processes": 5, } }
使用示例:
uwsgi --json example_config.json
要了解有关配置 uWSGI 的更多信息,请考虑阅读其有关 配置 的文档。
uWSGI 的常用配置
默认情况下,此服务器默认设计为与框架/应用程序/平台无关。 尽管它可能支持您可能需要的任何东西,但需要明确设置某些选项以符合您的要求。
正如其自己的文档中所述,配置 uWSGI 的可能方法的数量几乎是无限的。 在本节中,我们将尝试回顾最常用或最关键的部分并解释其实现,当与上一节结合使用时,将使您能够让 uWSGI 以您需要的方式运行。
有关优化,请参阅本节之后的下一节。
以下示例中使用的语法针对 .ini
文件。 您可以根据需要修改它们以满足您的特定需求(例如 用于基于 .json
的配置,如上一节所述)。
插座
http-socket
将 uWSGI 设置为绑定到某个 HTTP 套接字。
示例:http-socket = :8080
插座
将 uWSGI 设置为使用默认协议绑定到指定的套接字。
示例:socket = 127.0.0.1:8080
进程(工人)
这两个术语都可以用来指代同一件事:为接受 请求 而产生的进程数量。
示例:processes = 5
协议
默认情况下,uWSGI 运行在它自己的 uwsgi 协议上。 此属性允许您更改它。
示例:protocol = http
管理
掌握
此选项用于启用或禁用主 uWSGI 进程。 这些进程用于管理接受和处理传入请求的工作人员。 优点很多,包括在不接触套接字的情况下优雅地重新启动工作人员,这将允许您在不停机的情况下进行升级。
示例:master = true
最大请求数
如果您担心内存泄漏并且想不出更可靠的方法来处理它,此选项将允许您在处理指定的请求数量后自动重新启动进程。
示例:max-requests = 1001
线程
在重新线程模式下使用指定数量的线程运行每个进程的设置。 可以将此选项与 processes 结合使用,以获得不同程度的并发性。
示例:threads = 2
日志记录
禁用日志记录
用于禁用日志记录功能。
示例:disable-logging = true
uWSGI 进程
程序名
允许您将进程名称设置为您选择的名称。
示例:procname = My Application
uid
将 uWSGI 服务器用户 uid
设置为指定的用户。
示例:uid = 1001
吉德
将 uWSGI 服务器 gid
设置为指定的。
示例:gid = 555
真空
退出时删除所有生成的 pidfiles / sockets。
守护进程
此设置 守护 uWSGI 并将消息写入提供的参数(日志文件)。
示例:daemonize = /tmp/uwsgi_daemonize.log
pid文件
设置 uWSGI 将进程 PID 写入选项指定的文件。 此选项对于管理正在运行的 uWSGI 进程非常方便(有关更多信息,请参阅 管理 uWSGI 部分)。
示例:pidfile = /tmp/proj_pid.pid
各种各样的
原切
此设置用于设置进程在被杀死和回收 以用于内存/管理之前允许完成其任务 的最长时间。
示例:harakiri = 30
要了解有关数百种可用配置的所有信息,您应该阅读位于官方 配置选项 文档中的完整列表。
其他提示和建议
防火墙:
保护 SSH:
创建警报:
每天监控和观察服务器访问日志: