Flask应用——我的发布&部署之道
-  
  
Flask应用需要有一个入口文件。一般地,我定义该文件为app.py。在app.py中,引用定义了Flask实例的对象app(app=Flask(__name__)),通过执行app.run()方法来启动运行Flask应用。参考代码显示如下,就是这么简单!其中xxx是我定义了Flask实例的文件。  
from xxx import appif __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应用使用到的依赖包。 
 
2. 制作控制台程序
指定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的模板,内容显示如下: 
<configuration><system.webServer><handlers><add name="FlaskFastCGI" path="*" verb="*" modules="FastCgiModule" scriptProcessor="c:\program files\anaconda3\python.exe|"c:\program files\anaconda3\lib\site-packages\wfastcgi.py"" 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文件所在的路径。
生成控制台程序发布包
略。
执行控制台程序发布包里的exe文件,准备好Flask应用的运行环境。
点击网站的处理程序映射功能,看能否打开功能界面,这一步也是用来验证web.config文件里是否进行了正确的配置。如果能打开不报错,正常情况下,直接启动网站,在浏览器里就可以看到运行的Flask应用了。
备注:需要事先开启IIS的CGI功能!
