Flask部署

之前的Flask应用都是直接用自带的server跑的,本身业务对性能也没什么要求,就没做production的部署。但是最近觉得很麻烦的是,每次server端代码改变,都得跑去服务器上pull代码,然后重启flask server,太麻烦了,还是弄成自动部署方便多了。

安装uwsgi

我这边服务器系统是ubuntu 16.04的,仓库里本身有uwsgi包,除了安装uwsgi之外,我们还需要安装对应的python插件

sudo apt install uwsgi
# 如果你使用的python是2.x版本的话,就安装uwsgi-plugin-python
sudo apt install uwsgi-plugin-python3

安装uwsig-plugin-python3的过程中会出现下面错误

/var/lib/dpkg/info/uwsgi-plugin-python3.postinst: 61: [: Illegal number:

修改下对应文件uwsig-plugin-python3.postinst中60行

grep -c '/uwsgi_python3$' | true => grep -c '/uwsgi_python3$' || true

配置

uwsgi作为服务启动

ubuntu 16.04系统下,使用systemd来管理服务启动,其他系统参考对应文档

禁止LSB启动

apt安装后,uwsgi会在init.d目录下有个uwsgi文件,这个对应着LSB服务启动方式,Systemd兼容LSB方式,因为准备使用Systemd方式来管理,所以先要将LSBuwsgi服务禁用

sudo update-rd.d uwsgi remove

配置service文件

目录/lib/systemd/system下创建emperor.uwsgi.service文件

[Unit]
Description=uWSGI Emperor
After=syslog.target

[Service]
ExecStart=/usr/bin/uwsgi --ini /etc/uwsgi/emperor.ini
# Requires systemd version 211 or newer
RuntimeDirectory=uwsgi
Restart=always
KillSignal=SIGQUIT
Type=notify
StandardError=syslog
NotifyAccess=all

[Install]
WantedBy=multi-user.target

激活服务

新增service文件后,需要进行下面操作才能让systemd将服务管理起来

# systemd自身reload,这样才能发现新增的service文件
sudo systemctl daemon-reload
# 确认systemd发现了service文件
sudo systemctl list-unit-files | grep emp
# 激活service
sudo systemctl enable emperor.uwsgi.service
# 启动service
sudo systemctl start emperor.uwsgi.service
# 查下下服务启动状态,确认正常启动
sudo systemctl status emperor.uwsig.service

部署应用

这里举例部署一个测试应用

首先在/etc/uwsgi/vassals下新建test_app.ini文件,内容如下

[uwsgi]
chdir=/home/pzx/projects/meson-webviewer-server
; http-to=/tmp/%n.sock
http-socket=0.0.0.0:8376
plugin=python35
module=test_app:app
processes=4
master=true
;python虚拟环境
venv=/home/pzx/projects/meson-webviewer-server/.venv

对应/home/pzx/projects/meson-webviewer-server/test_app.py文件内容如下

from flask import Flask
app = Flask(__name__)

@app.route("/")
def hello():
return "Hello World! i am app1"

访问http://ip:8376就会在页面上看到Hello world! i am app1

配合gitlab-ci

下面是.gitlab-ci.yml的示例

stages:
- build
- test
- deploy

variables:
GIT_SUBMODULE_STRATEGY: recursive

deploy tools:
stage: deploy
only:
- master
tags:
- linux-runner
script:
- cp -rf * /home/gitlab-runner/meson/meson-webviewer-server
- cd /home/gitlab-runner/meson/meson-webviewer-server
- source .venv/bin/activate
- pip install -r pyrequirements.txt
- sudo touch /etc/uwsgi/vassals/meson-webviewer-server.ini

最重要的语句就是最后一句touch了,会导致配置文件时间戳的更新,进而uwsgi会自动重启对应应用。

这样以后在代码push到远端后,对应应用的服务端会自动更新重启,再也不需要跑到服务器上手动更新重启了,真Happy!

Emperor方式

上面uwsgi用的部署方式是Emperor方式(一个服务管理多个应用),Emperor是君王的意思,vassals是臣子的意思。君王管理所有的臣子,臣子就是具体部署的应用,来处理用户的请求。需要部署多个应用,就在/etc/uwsgi/vassals目录下创建新的应用的配置文件,君王会自动方式新的配置文件,然后按照配置文件的配置去启动对应的应用。

君王不关有自动发现臣子(新应用配置)的能力,同时君王会在应用配置有更新的时候,优雅的重启臣子(旧的worker处理完请求后关闭,同时启动新的worker);另外还包括负载均衡、挂掉重启等功能,简直完美的解决了自动部署的问题

另外uwsgi也支持一个应用一个服务的配置方式,这种适合一个机器就只跑一个应用的情况,具体配置可以参考文档

感受

flask的部署方式有很多,但是我不想弄复杂,再搞个Nginx在前面。 uwsgi不关支持请求的转发,同时还支持静态文件服务,对于一个简单的应用妥妥的够了,不想再耗费精力去部署的复杂(也没有什么用)

但是uwsgi的文档真的写的太乱了,好多东西都不知道去哪里查,要试验好久才能配置正确!比如关于http端口的绑定,需要用到http-socket选项,但是在文档里找不到对应说明,还有关于python插件的配置等等。

清楚的文档还是很重要的,要不然以后有其他选择了,妥妥的不用这个了。