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应用使用到的依赖包。
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功能!