自从我第一次浪漫地接触 Python 已经过去了大约十年。这部特别的浪漫喜剧不知何故完全错过了“一见钟情”的比喻——我发现学习 Python 的过程令人愤怒。我担心的不是语言本身,而是地球上每个活着的软件开发人员。

从我的角度来看,“软件”中的人似乎只有两种原型,两者都不是特别可口。光谱的一端被我的新手占据,他们似乎很高兴地被限制在可爱的 REPL 环境中编程,无论哪个训练营为他们提供了阻止他们提问的蓝色药丸。在光谱的另一端是其他人:有能力的工程师在我眼中也可能是天才。我知道这些人有知识回答我能提出的每一个问题,但不知何故被证明完全无能以任何身份有用。当时我并不清楚经验丰富的工程师是否是故意的精英混蛋,或者新人是否真的无助。我唯一清楚的是,这两个人口都不会为我的近期目标提供价值。回想起来,这种挫败感可能是推动这个博客存在的原因)。

我确信没有什么值得构建的,除非它运行在 Linux 服务器上,在一个真实的域后面,全世界都可以访问。这在 2020 年听起来可能是一个合理的观点,但这是 2010 年:没有 Docker,没有 Heroku,没有 DigitalOcean。Nginx 主要是由“俄罗斯的一些家伙”创建的边缘网络服务器,为互联网上 10% 的网站提供动力,而 Apache 则为 90%。基于 Web 的 Python 以前依赖于一个名为mod-python 的 Apache 模块。Mod-python 突然(并且任意地?)被认为是“死的”,取而代之的是一个名为mod-wsgi 的未记录的 Apache 模块。这是 Graham Dumpleton 的创意,除了我自己之外,他也可能是世界上唯一一个试图运行该死的 Python 网络应用程序的人. 我能成功地做到这一点真是一个奇迹。

输入 uWSGI

首字母缩略词“WSGI”代表Web 服务器网关接口,这是一种深奥的说法,即“网络服务器如何与 Python 通信”。uWSGI 及其前身是一种中间件形式,供 Nginx 等网络服务器为 Python 应用程序提供服务。

在 2020 年,有很多选择可以为 Python Web 应用程序提供服务,但 uWSGI 在客观上比 Gunicorn 等替代方案要好。如果你对我们为什么要使用 uWSGI有任何疑问,我从这个人的博客中偷来的这些精心挑选的图表肯定会解决问题:

正在上传…重新上传取消​

网关接口的性能比较。

在我们开始之前,我要对你说实话:这些东西有时会让人觉得很深奥。当有一键式解决方案可以完全避免所有这些时,看着这个过程并说“去他的”是很诱人的,但我要告诉你一个秘密:这些解决方案很糟糕。Heroku 是一个糟糕的 AWS 经销商,它销售具有更友好界面的垃圾 EC2 实例。Docker 是开发人员躲避 Linux 细微差别的一种手段,以至于我们会安装整个虚拟机,而不是学习。我已经准备好对这些言论嗤之以鼻,但我的观点仍然存在:如果您有兴趣超越供应商锁定并构建运行速度更快的应用程序,那么您来对地方了。

开始设置

我们需要在 Ubuntu(或其他)上安装一堆 Python 开发包才能使 uWSGI 工作。即使这条线看起来很熟悉,也不要跳过这部分(就像我一样)。几乎可以肯定,您缺少以下至少一个包:

<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code>$ apt update
$ apt upgrade -y
$ sudo apt install python3.8 python3.8-dev python3-distutils uwsgi uwsgi-src uuid-dev libcap-dev libpcre3-dev python3-pip python3.8-venv
</code></span></span>

安装所有 Python 开发依赖项。

安装uwsgi-plugin-python3是一个重要的步骤,值得特别注意。uWSGI 传统上是一个Python 包,因此您可能希望我们运行它pip install uWSGI。如果我们要通过 pip 安装 uWSGI,uWSGI 将是一个 Python 包,属于我们机器上碰巧安装的 Python3 的系统默认版本。我们的项目可能会使用Python 3.6.9以外的 Python 版本(Ubuntu 18.04 默认),因此我们需要一个超越 Python 版本的 uWSGI 版本。这就是uwsgi-plugin-python3 的用武之地:

安装uwsgi-plugin-python3是一个重要的步骤,值得特别注意。uWSGI 传统上是一个Python 包,因此您可能希望我们pip install uWSGI在某个时候运行。相反,如果我们通过 pip 安装 uWSGI,uWSGI 将是一个 Python 包,属于我们机器上碰巧安装的 Python3 的系统默认版本。我们的项目可能会使用Python 3.6.9以外的 Python 版本(Ubuntu 18.04 默认)。因此,我们需要一个超越 Python 版本的 uWSGI 版本。这就是uwsgi-plugin-python3 的用武之地:

<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code>$ apt-get install uwsgi-plugin-python3
</code></span></span>

安装 uWSGI Python 插件。

我们最后一点 Ubuntu 配置是打开端口 5000:

<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code>$ ufw allow 5000
</code></span></span>

打开 5000 端口。

准备你的项目

接下来,我们只需要确保您的 Flask 应用程序在您的远程服务器上并准备好执行操作。将您的项目克隆到您的 VPS 上,并确保您的项目有一个正确的wsgi.py文件作为应用程序的入口点:

<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-error-color)">from</span> <span style="color:var(--syntax-text-color)">myapp</span> <span style="color:var(--syntax-error-color)">import</span> <span style="color:var(--syntax-text-color)">create_app</span><span style="color:var(--syntax-text-color)">app</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">create_app</span><span style="color:var(--syntax-text-color)">()</span><span style="color:var(--syntax-declaration-color)">if</span> <span style="color:var(--syntax-text-color)">__name__</span> <span style="color:var(--syntax-error-color)">==</span> <span style="color:var(--syntax-string-color)">" __main__"</span><span style="color:var(--syntax-text-color)">:</span><span style="color:var(--syntax-text-color)">app</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-text-color)">run</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">host</span><span style="color:var(--syntax-error-color)">=</span><span style="color:var(--syntax-string-color)">'0.0.0.0'</span><span style="color:var(--syntax-text-color)">)</span>
</code></span></span>

wsgi.py

不用我告诉你,你已经知道使用虚拟环境,但我们需要在这里专门使用virtualenv——而不是 Pipenv 或任何其他替代方案。uWSGI 出于某种原因对此很挑剔。省去你的麻烦并使用 virtualenv,即使它在原则上有点糟糕:

<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code>$ python3.8 -m venv myenv
$ source myenv/bin/activate
$ pip install -r requirements.txt
</code></span></span>

创建和构建您的虚拟环境。

我们已经安装了所有依赖项,安装了 uWSGI,我们的项目看起来不错……我们应该准备好测试这个东西了,对吧?

<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code>uwsgi --http-socket :5000 --plugin python3 --module wsgi:app
</code></span></span>

uWSGI 命令行尝试。

惊喜,惊喜!

<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code>Python version: 3.6.9 (default, Nov 7 2019, 10:44:02) [GCC 8.3.0] ***Python threads support is disabled. You can enable it with --enable-threads*** Python main interpreter initialized at 0x55721b8125c0dropping root privileges after plugin initializationuWSGI running as root, you can use --uid/--gid/--chroot options***WARNING: you are running uWSGI as root !!! (use the --uid flag)*** your server socket listen backlog is limited to 100 connectionsyour mercy for graceful operations on workers is 60 secondsmapped 72768 bytes (71 KB) for 1 cores ***Operational MODE: single process*** Traceback (most recent call last): File "wsgi.py", line 1, in <module> from pythonmyadmin import create_app File "./pythonmyadmin/ __init__.py", line 1, in <module> from flask import FlaskModuleNotFoundError: No module named 'flask'unable to load app 0 (mountpoint='') (callable not found or import error) ***no app loaded. going in full dynamic mode***
</code></span></span>

我们的 WSGI 测试的输出。

您也许能够辨别上面发生的事情;uWSGI 的输出表明我们正在使用 Python 3.6.9(不是我们想要的)并且找不到与我们激活的虚拟环境关联的包。当我们--plugin python3在之前的行中指定时,我们太笼统了:我们需要一个专门针对我们的版本的 uWSGI 插件,称为python38

安装 uWSGI Python 3.8 插件

感谢我们之前安装的 uwsgi -plugin-python3库,安装特定版本的 uWSGI 插件很容易:

<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code>$ export PYTHON=python3.8
$ uwsgi --build-plugin "/usr/src/uwsgi/plugins/python python38"
</code></span></span>

构建 uWSGI python38 插件。

你应该看到这样的输出:

<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code>***uWSGI building and linking plugin from /usr/src/uwsgi/plugins/python*** [x86_64-linux-gnu-gcc -pthread] python38_plugin.so/usr/src/uwsgi/plugins/python/python_plugin.c: In function ‘uwsgi_python_post_fork’:/usr/src/uwsgi/plugins/python/python_plugin.c:394:3: warning: ‘PyOS_AfterFork’ is deprecated [-Wdeprecated-declarations] PyOS_AfterFork(); ^~~~~~~~~~~~~~In file included from /usr/include/python3.8/Python.h:144:0, from /usr/src/uwsgi/plugins/python/uwsgi_python.h:2, from /usr/src/uwsgi/plugins/python/python_plugin.c:1:/usr/include/python3.8/intrcheck.h:18:37: note: declared here Py_DEPRECATED(3.7) PyAPI_FUNC(void) PyOS_AfterFork(void); ^~~~~~~~~~~~~~/usr/src/uwsgi/plugins/python/python_plugin.c: In function ‘uwsgi_python_worker’:/usr/src/uwsgi/plugins/python/python_plugin.c:1957:3: warning: ‘PyOS_AfterFork’ is deprecated [-Wdeprecated-declarations] PyOS_AfterFork(); ^~~~~~~~~~~~~~In file included from /usr/include/python3.8/Python.h:144:0, from /usr/src/uwsgi/plugins/python/uwsgi_python.h:2, from /usr/src/uwsgi/plugins/python/python_plugin.c:1:/usr/include/python3.8/intrcheck.h:18:37: note: declared here Py_DEPRECATED(3.7) PyAPI_FUNC(void) PyOS_AfterFork(void); ^~~~~~~~~~~~~~build time: 6 seconds ***python38 plugin built and available in python38_plugin.so***
</code></span></span>

python38插件安装成功。

这会将名为python38_plugin.so的文件下载到您的当前文件夹。我们需要把它移到它所属的地方,并设置一些权限:

<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code>$ sudo mv python38_plugin.so /usr/lib/uwsgi/plugins/python38_plugin.so
$ sudo chmod 666 /usr/lib/uwsgi/plugins/python38_plugin.so
</code></span></span>

移动 uWSGI python38 插件。

让我们再试一次

这一次,我们将指定--plugin python38专门使用 Python 3.8 运行 uWSGI。我们还将添加另一个名为 的标志--virtualenv,它定义了 Python 库的安装路径。杀死之前的 uWSGI 进程并再试一次:

<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code>$ pkill -9 uwsgi
$ uwsgi --http-socket :5000 --plugin python38 --module wsgi:app --virtualenv /var/www/pythonmyadmin/myenv/
</code></span></span>

开始了...

<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code>***Python threads support is disabled. You can enable it with --enable-threads*** Python main interpreter initialized at 0x55daa18a3e40dropping root privileges after plugin initializationuWSGI running as root, you can use --uid/--gid/--chroot options***WARNING: you are running uWSGI as root !!! (use the --uid flag)*** your server socket listen backlog is limited to 100 connectionsyour mercy for graceful operations on workers is 60 secondsmapped 72768 bytes (71 KB) for 1 cores ***Operational MODE: single process*** WSGI app 0 (mountpoint='') ready in 1 seconds on interpreter 0x55daa18a3e40 pid: 28434 (default app)dropping root privileges after application loadinguWSGI running as root, you can use --uid/--gid/--chroot options***WARNING: you are running uWSGI as root !!! (use the --uid flag)***  ***uWSGI is running in multiple interpreter mode*** spawned uWSGI worker 1 (and the only) (pid: 28434, cores: 1)
</code></span></span>

产生了成功的 uWSGI 工作者

这是个好消息!在端口 5000 访问您服务器的 IP 地址并报告。它在工作吗?它工作正常!好的!!!

uWSGI 有一个很棒的地方,那就是通过指定我们想要使用多少线程和进程,在我们的机器中使用多个内核是多么容易。如果您的机器配备了多个 CPU 内核,那么使用它们是多么容易:

<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code>$ pkill -9 uwsgi
$ uwsgi --http-socket :5000 --plugin python38 --module wsgi:app --virtualenv /var/www/pythonmyadmin/myenv/ --processes 2 --threads 4
</code></span></span>

利用多线程启动 uWSGI。

这将输出创建的每个工人以及使用的核心:

<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code>***uWSGI is running in multiple interpreter mode*** spawned uWSGI worker 1 (pid: 28688, cores: 2)spawned uWSGI worker 2 (pid: 28690, cores: 2)spawned uWSGI worker 3 (pid: 28691, cores: 2)spawned uWSGI worker 4 (pid: 28692, cores: 2)
</code></span></span>

与 uWSGI 的并发性。

请记住,uWSGI 进程不会被终端中的Control+Ci ng 简单地杀死。请记住使用pkill -9 uwsgi.

通过配置文件运行 uWSGI

我们已经证明我们可以通过 uWSGI CLI 为我们的应用程序提供服务,但我们希望我们的应用程序在注册域名之后永远存在。我们需要一种方法让 Nginx 使用我们通过 CLI 传递的所有标志(例如要使用的 uWSGI 插件、我们的虚拟环境位置等)挂钩到我们的 uWSGI 进程。幸运的是,我们可以将传递给 CLI 的标志/值保存到具有相同命名约定的.ini文件中:

<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code>[uwsgi]
chdir = /var/www/myapp/
module = wsgi:appprocesses = 4
threads = 2
plugin = python38
virtualenv = /var/www/myapp/myappenvmaster = true
socket = myapp.sock
chmod-socket = 666
vacuum = truedie-on-term = true
</code></span></span>

我的应用程序.ini

我们没有在此处指定http-socket,而是设置socketmyapp.sock。Nginx 将处理我们的 HTTP 请求,但它需要一种将传入请求与我们正在运行的应用程序相关联的方法。我们通过创建一个套接字来处理这个问题:每次我们使用这个配置运行 uWSGI 时,都会在我们的项目目录中创建一个名为myapp.sock的文件。所有 Nginx 需要担心的是指向此套接字以获取传入流量。

现在我们可以使用正确的配置有效地运行我们的应用程序:

<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code>$ uwsgi myapp.ini
</code></span></span>

那好多了。作为一个额外的好处,为了方便起见die-on-term = true,我们的配置中的存在意味着我们的 uWSGI 进程在我们Control+C时结束。

uWSGI & Nginx 4 Eva

假设你已经安装了 Nginx,在sites-available中为我们的应用创建一个配置:

<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code>$ sudo vim /etc/nginx/sites-available/myapp.conf
</code></span></span>

创建

这可能是您必须创建的最简单的 Nginx 配置之一。在端口 80 上侦听您的域,并将此流量(带参数)转发到我们在myapp.ini中指定的套接字文件的位置:

<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code>server {listen 80;server_name example.com www.example.com; location / {include uwsgi_params;uwsgi_pass unix:///var/www/myapp/myconf.sock; }
}
</code></span></span>

myapp.conf

uwsgi_pass请注意URI中的三斜杠。

让我们将此配置符号链接到sites-enabled

<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code>$ ln -s /etc/nginx/sites-available/myapp.conf /etc/nginx/sites-enabled/myapp.conf
</code></span></span>

重启Nginx生效:

<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code>$ sudo service nginx restart
</code></span></span>

耽误

您只需一条命令就可以永远向世界公开您的应用程序部署。在你扣动扳机之前,为你在这里成功而感到自豪。整个云计算行业都从“无服务器”微服务范式中获益良多,因为大多数人不像你。大多数人宁愿以牺牲性能为代价来为共享资源付费,以免阅读这样的教程。你解脱了。你很美丽。你是蝙蝠侠。

<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code>$ cd /var/www/myapp$ nohup uwsgi myapp.ini &
</code></span></span>

现在去自由吧。世界是你的牡蛎。


PS:经历了这个,设置uWSGI突然看起来并不那么复杂。现在这一切似乎都很明显,但实际上,我花了一年的时间多次失败的启动才能让 uWSGI 正常工作。尝试阅读任何其他 uWSGI 教程,您很快就会明白原因:工程师在解释这些概念方面显然仍然很糟糕。我不会轻易做出这些概括,但是,嘿,对我来说更多的流量。

吐槽完了,教程完了。直到下一次。如果对Python有兴趣,想了解更多的Python以及AIoT知识,解决测试问题,以及入门指导,帮你解决学习Python中遇到的困惑,我们这里有技术高手。如果你正在找工作或者刚刚学校出来,又或者已经工作但是经常觉得难点很多,觉得自己Python方面学的不够精想要继续学习的,想转行怕学不会的, 都可以加入我们,可领取最新Python大厂面试资料和Python爬虫、人工智能、学习资料!微信公众号【Python大本营】等你来玩奥~

使用 uWSGI 和 Nginx 部署 Flask 应用程序相关推荐

  1. nginx部署与小程序配置

    nginx部署与小程序配置说明 1.安装nginx $ sudo apt-get update $ sudo apt-get install nginx 2.配置https: 查看: https:// ...

  2. 用uwsgi和nginx 部署 django和vue打造的前后端分离项目

    用uwsgi和nginx 部署 django和vue打造的前后端分离项目 前言 由于现在没有彻底掌握nginx的使用,部署起来有点磕磕绊绊,为了防止以后再次需要部署的时候无法快速找到适合的资料,以此文 ...

  3. 百度云服务器BCC安装ubuntu16.04 +python3.6配置uWSGI和Nginx 部署Django项目

    题外话 最近也不开学不开工,闲着没事在做一个python+Django的项目.正好域名之前刚审核通过.开始着手在百度云部署自己的项目,记录一下过程中踩过的坑. 简介 Django是一个功能强大的Web ...

  4. heroku搭建mysql_在heroku上部署Flask应用程序并将其连接到颚数据库mysql数据库

    heroku搭建mysql By: Edward Krueger Data Scientist and Instructor and Douglas Franklin Teaching Assista ...

  5. nginx 部署flask应用

    nginx 部署项目不要想的太过复杂,直接上手操作,遇到问题再逐个击破 编程语言:python 项目后端:flask 前端:vue 2.x 准备工作 需要掌握的命令 sudo nginx -c ngi ...

  6. centOS+uwsgi+nginx 部署flask项目,问题记录

    用flask做的项目想要部署到centOS系统上,填了一些坑,终于成功了,记录一下遇到的问题: 此次部署主要是按照这个博客进行的 https://www.cnblogs.com/Ray-liang/p ...

  7. Flask部署| gunicorn、nginx部署flask项目,并用supervisor来管理进程

    本科的时候做公众号,开始提供学生教务查询服务,后端从PHP转到Python,无论是使用django还是flask,部署都没PHP那么方便,每次修改程序完,都是ps ax,然后再kill,再run.em ...

  8. 怎么抓python程序的包_如何在AWS上部署python应用程序

    如何在AWS上部署python应用程序,学姐呕心沥血亲自总结,亲测有效,比网上看网上大把大把的文档要快得多! 作者:蕾学姐 亚马逊云计算服务(Amazon Web Services,缩写为AWS),由 ...

  9. python3 supervisor_python3-django+uwsgi+supervisor+nginx跳坑指南(记录)

    首先运行django项目:在项目目录内: python manage.py runserver 0.0.0.0:8000 外部服务器访问:http://www.xxx.com:8000/ 可以正常运行 ...

最新文章

  1. java求婚代码_屌丝程序员的求婚道具--内含视频
  2. nyoj A+B Problem IV
  3. python easy install_Python 安装easy_install详解
  4. search-guard 在 Elasticsearch 2.3 上的运用
  5. 求java简单计算器源代码_java简单计算器源代码
  6. SVN:通过命令行只提交目录,并忽略其中的文件
  7. polycom安卓手机客户端_安卓 emoji 表情:全变了
  8. c++ 如何将输入的内容输出到文本文件 要建立文本文件嘛_python如何学习
  9. 让英文版的LINUX 支持中文显示
  10. 网络管理与维护作业10
  11. [python] 将一个序列的排序方式扩展到其他序列
  12. 博弈论-共有知识与共同知识
  13. [leetcode]Unique Paths
  14. 图论及其应用 2011年 期末考试 答案总结
  15. 纯CSS打造淘宝导航菜单栏
  16. 下载知乎等网站视频小技巧
  17. mysql oob_mysql 读写文件特性和OOB注入
  18. 数说CS|中国人民大学高瓴人工智能学院保研生源大起底!
  19. ARC 101 E - Ribbons on Tree
  20. 大商创如何重置或修改商家店铺登录密码?

热门文章

  1. 逆变电源的计算机控制系统,一种专用三相逆变电源控制系统研究
  2. mkvtool-cmd批处理之视频混流辅助工具
  3. subline3 macos 10.13 命令 subl快捷键
  4. 【JAVA软件开发】
  5. R语言——在linux环境下如何画图或保存图片
  6. 按照省市区分割地址 java_省市区地区分割,注意地址里面包括两个区的(比如有:市区和小区)...
  7. 【计算机毕业设计】Java 基于微信小程序的高校游泳馆管理系统
  8. MPEG4、XVID、AVC有什么区别
  9. javaee中forward /redirect核心区别
  10. 主流液晶显示器尺寸参数