vlambda博客
学习文章列表

Flask应用——我的发布&部署之道

今天又发布&部署了一个Flask应用,早些时候没有记录一下操作步骤,结果时间一长,就吃了“好记性不如烂笔头”的亏。值此之际,在之前经验教训的基础上,总结一下我最新的发布&部署Flask应用的操作步骤。
1. 打包Flask应用
  • Flask应用需要有一个入口文件。一般地,我定义该文件为app.py。在app.py中,引用定义了Flask实例的对象app(app=Flask(__name__)),通过执行app.run()方法来启动运行Flask应用。参考代码显示如下,就是这么简单!其中xxx是我定义了Flask实例的文件。
from xxx import app
if __name__ == "__main__":    app.run(port=5006)
  • 除了app.py之外,将Flask应用的其他文件打包成一个whl包。用到的工具是setuptools,这里就不展开介绍如何制作whl包了,可以查看我的另一篇文章: 。提醒:在制作whl包之前,先确保Flask应用可以正常运行(执行:python.exe app.py,不报错)。
  • 使用pipreqs工具,生成requirements.txt文件(pipreqs ./  --encoding utf-8  --force),该文件包含了整个Flask应用使用到的依赖包。
至此,一个Flask应用就打包完毕了,最终包含三样东西:app.py、requirements.txt和whl包。这里特别说明一下我的python开发环境是3.7.3版本,那么我在部署环境中使用的python版本也将是3.7.3。因为这里曾碰到过一个坑:在app.py中报“ImportError:bad magic number in xxx”的错误。根本原因就是开发环境和部署环境中的python版本不一致。由于在开发环境中制作的whl包里包含的是编译过的pyc文件,而pyc文件是区分python版本的,所以当部署环境中的python与发布whl包的python版本不一致时,只要调用就会报错。

2. 制作控制台程序

为什么会有这个玩意呢?因为我想通过一键执行exe程序,就自动准备好Flask应用所需的python环境(不想手动地在CMD里敲命令)。这里,我使用.net core来制作控制台程序,其功能大致分为如下几个部分:
  • 指定python环境

    通过Nuget引用“Python.Included”包,它包含了一个3.7.3版本的python压缩包。后面我们将指定使用它作为Flask应用运行的python环境。核心代码显示如下:

// 指定python压缩包的安装路径,为控制台程序的根目录Installer.InstallPath = AppDomain.CurrentDomain.BaseDirectory;// 解压python压缩包Installer.SetupPython();
  • 安装Flask应用的依赖包

    解压完python压缩包后,我们要先安装pip工具,然后用pip来安装requirements.txt里的依赖包、Flask应用的whl包和wfastcgi工具。核心代码显示如下:

private static void InstallPythonPackages(){ var type = typeof(Program); var tasks = new List<Task>(); var requirements = type.Assembly.GetManifestResourceNames().FirstOrDefault(x => x.Contains("requirements.txt")); if (requirements!=null) { var stream = type.Assembly.GetManifestResourceStream(requirements); if (stream != null) { using var sr = new StreamReader(stream); while (!sr.EndOfStream) { var content = sr.ReadLine(); if (content != null && content.Contains("==")) { tasks.Add(Task.Factory.StartNew(() => { CommonHelper.RunCommand($"{Path.Combine(Installer.EmbeddedPythonHome, "Scripts", "pip.exe")} install --target={Path.Combine(Installer.EmbeddedPythonHome, "Lib", "site-packages")} {content} -i https://pypi.tuna.tsinghua.edu.cn/simple"); })); } } } } tasks.Add(Task.Factory.StartNew(() => { CommonHelper.RunCommand($"{Path.Combine(Installer.EmbeddedPythonHome, "Scripts", "pip.exe")} install --target={Path.Combine(Installer.EmbeddedPythonHome, "Lib", "site-packages")} {Path.Combine(Installer.InstallPath, "xxx.whl")}"); }));
tasks.Add(Task.Factory.StartNew(() => { CommonHelper.RunCommand($"{Path.Combine(Installer.EmbeddedPythonHome, "Scripts", "pip.exe")} install --target={Path.Combine(Installer.EmbeddedPythonHome, "Lib", "site-packages")} wfastcgi -i https://pypi.tuna.tsinghua.edu.cn/simple"); }).ContinueWith(x => { if (x.IsCompletedSuccessfully) { CommonHelper.RunCommand(Path.Combine(Installer.EmbeddedPythonHome, "Scripts", "wfastcgi-disable.exe")); CommonHelper.RunCommand(Path.Combine(Installer.EmbeddedPythonHome, "Scripts", "wfastcgi-enable.exe")); } }));
Task.WhenAll(tasks).ContinueWith(x => { if (x.IsCompletedSuccessfully) Console.WriteLine("Python env is initialized."); });}
从上述代码中,可以看到几个细节:
    • 将requirements.txt作为嵌入的资源;

    • 在使用pip安装依赖包时,指定了安装路径和国内镜像源,可以确保安装位置没有问题(在指定python环境下的“Lib/site-packages”里),加快安装速度;

    • 在安装完wfastcgi(wfastcgi是IIS和python之间的桥梁,提供了通过IIS处理请求和处理池的有效方法)后,立即启用它;

  • 生成IIS的web.config文件

    由于我们要将Flask应用部署到IIS中,并且在IIS中也需要做一些配置,而这些配置最终都会体现在web.config文件中,所以我们事先准备好已配置完的web.config文件,这样待部署的时候,就省去手动再配置的操作。这里,在控制台程序中会有一个web.config的模板,内容显示如下:
<?xml version="1.0" encoding="UTF-8"?><configuration> <system.webServer> <handlers> <add name="FlaskFastCGI" path="*" verb="*" modules="FastCgiModule" scriptProcessor="c:\program files\anaconda3\python.exe|&quot;c:\program files\anaconda3\lib\site-packages\wfastcgi.py&quot;" resourceType="Unspecified" requireAccess="Script" /> </handlers> </system.webServer> <appSettings> <!-- Required settings --> <add key="WSGI_HANDLER" value="Flasktest.app" /> <add key="PYTHONPATH" value="~/" /> </appSettings></configuration
    • 在handlers标签里,配置FastCgiModule模块,其属性值与IIS中编辑模块映射的配置界面里的输入一一对应;


    • 在appSettings标签里,有两个配置项。一个是WSGI_HANDLER,其值是Flask应用的实例对象,例如上面模板里的值Flasktest.app,Flasktest是入口文件名,app是该文件里代表Flask实例的对象。另一个是PYTHONPATH,其值是Flasktest.py文件所在的路径。

  • 生成控制台程序发布包

    略。

3. IIS部署
  • 执行控制台程序发布包里的exe文件,准备好Flask应用的运行环境。

  • 点击网站的处理程序映射功能,看能否打开功能界面,这一步也是用来验证web.config文件里是否进行了正确的配置。如果能打开不报错,正常情况下,直接启动网站,在浏览器里就可以看到运行的Flask应用了。


备注:需要事先开启IIS的CGI功能!