在uWSGI中嵌入一个应用¶
从uWSGI 0.9.8.2开始,你可以在服务器二进制中嵌入文件。这些可以是任何文件类型,包括配置文件。你也可以嵌入目录,因此,通过拦截Python模块加载器,你也可以明确导入包。在这个例子中,我们将嵌入一个完整的Flask项目。
第1步:创建构建配置文件¶
我们假设你已经准备好了uWSGI源代码。
在 buildconf
目录下,定义你的配置文件 —— 让我们称之为flask.ini:
[uwsgi]
inherit = base
main_plugin = python
bin_name = myapp
embed_files = bootstrap.py,myapp.py
myapp.py
是一个简单的flask应用。
from flask import Flask
app = Flask(__name__)
app.debug = True
@app.route('/')
def index():
return "Hello World"
bootstrap.py
在源代码发布版中。它会扩展python的import子系统,来使用内嵌在uWSGI中的文件。
现在,编译你饱含应用的服务器。文件将会作为可执行符号潜入。文件中的点和连接号等会被转换成下划线。
python uwsgiconfig.py --build flask
由于 bin_name
是 myapp
,现在你可以运行
./myapp --socket :3031 --import sym://bootstrap_py --module myapp:app
``sym://`` 伪协议让uWSGI能够访问二进制文件的嵌入符号和数据,在这种情况下,直接从二进制镜像中导入bootstrap.py。
第2步:嵌入配置文件¶
我们想要让我们的二进制文件自动加载我们的Flask应用,而无需传递一个长长地命令行。
让我们创建配置 – flaskconfig.ini:
[uwsgi]
socket = 127.0.0.1:3031
import = sym://bootstrap_py
module = myapp:app
然后将其作为一个配置文件添加到构建配置文件中。
[uwsgi]
inherit = default
bin_name = myapp
embed_files = bootstrap.py,myapp.py
embed_config = flaskconfig.ini
然后,在你重新构建服务器后
python uwsgiconfig.py --build flask
你现在可以简单加载
./myapp
# Remember that this new binary continues to be able to take parameters and config files:
./myapp --master --processes 4
第3步:嵌入flask自身¶
现在,我们准备好玩转uWSGI的忍者神功了。我们想要单个二进制文件,它嵌入所有的Flask模块,包括Werkzeug和Jinja2,Flask的依赖。我们需要拥有这些包的目录,然后在构建配置文件中指定它们。
[uwsgi]
inherit = default
bin_name = myapp
embed_files = bootstrap.py,myapp.py,werkzeug=site-packages/werkzeug,jinja2=site-packages/jinja2,flask=site-packages/flask
embed_config = flaskconfig.ini
注解
这次,我们使用了”name=directory”形式,来强制符号使用指定的名字,以避免获得像 site_packages_flask___init___py
这样恶心的名字。
重新构建并重新运行。当运行以向你展示加载嵌入模块时,我们添加了–no-site。
python uwsgiconfig.py --build flask
./myapp --no-site --master --processes 4
第4步:添加模板¶
仍然不满意?好吧,你也不应该满意。
[uwsgi]
inherit = default
bin_name = myapp
embed_files = bootstrap.py,myapp.py,werkzeug=site-packages/werkzeug,jinja2=site-packages/jinja2,flask=site-packages/flask,templates
embed_config = flaskconfig.ini
模板将会被添加到二进制文件中……但是我们会需要通过创建一个自定义的Jinja2模板加载器,指示Flask如何从二进制镜像中加载模板。
from flask import Flask, render_template
from flask.templating import DispatchingJinjaLoader
class SymTemplateLoader(DispatchingJinjaLoader):
def symbolize(self, name):
return name.replace('.','_').replace('/', '_').replace('-','_')
def get_source(self, environment, template):
try:
import uwsgi
source = uwsgi.embedded_data("templates_%s" % self.symbolize(template))
return source, None, lambda: True
except:
pass
return super(SymTemplateLoader, self).get_source(environment, template)
app = Flask(__name__)
app.debug = True
app.jinja_env.loader = SymTemplateLoader(app)
@app.route('/')
def index():
return render_template('hello.html')
@app.route('/foo')
def foo():
return render_template('bar/foo.html')
POW! BIFF! NINJA AWESOMENESS.