使用 Flask Nginx Gunicorn 和 Supervisor 部署一个简单的 Restful API 接口服务器
引言
刚刚开始接触 Python Web 服务开发的开发者,通常对 Python 本身语法、代码编写、框架使用等问题都有较多可以参考的文档教程,但一旦涉及到要将所编写的服务部署到实际环境中去,需要考虑到的问题范围往往要远远大于学习 Python 和 Web 服务框架本身。相比于编写 Python Web 服务,部署 Web 服务涉及到服务器管理运维、代码管理、反向代理的使用、进程管理工具、系统服务管理以及服务器安全等诸多方面,当然这里面许多工作内容在较成熟的技术团队里通常会有专门的小伙伴帮忙解决,但随着行业对技术和人本身要求的不断提高,以及 DevOps 开发文化、极客文化的普及,更多的开发者逐渐要求自己具备从服务开发、服务器管理、服务部署和维护甚至是用户端开发的全栈开发能力,这对于许多入门 Python Web 开发的童鞋,往往没那么容易迅速解决,而是需要相当长时间的工作经验积累和自我学习提升才能实现。针对这一问题,本文使用 Flask 框架、Gunicorn WSGI 服务器、Supervisor 进程管理工具和 nginx 反向代理服务器,对 Python Web 服务部署进行一次较为精简手动部署操作说明和记录,尽量在每一步操作中通俗的介绍对应概念,让更多开发者通过本文对服务开发部署运维整套流程具备一个基础认识。
第一步代码部署
服务器账户 SSH 密钥管理
这一步默认读者拥有一台 Centos、Ubuntu 或其他发行版的 Linux 服务器环境,可以是阿里云、腾讯云和华为云的云环境,也可以是自己电脑上的虚拟机环境,甚至是一个简单的具备代码部署能力的 Docker 容器环境(Docker 中的部署本文不涉及、后面会开新的文章供大家参考),通常的 Linux 发行版都默认开启了 SSH 服务,在使用 root 账号登陆或者普通用户账号登陆后,生成服务器专属的 ssh 密钥对。
对于使用 root 账号还是普通账号生成密钥对来管理代码部署,后面会新开文章给大家分析优缺利弊,这里我们不做过多讨论,上面是生成登陆账号对应 ssh 密钥对的简单使用方法,ssh 工具的理解和使用也是服务器管理和全栈开发说必不可少的技能,后面会开新的文章给大家介绍,这里只需跟着命令执行就可以了。生成的密钥对会保存在~/.ssh/文件夹中,有兴趣的读者可自行前往查看。
紧接着,就是将我们生成的密钥对中公钥(~/.ssh/id_rsa.pub)上传到你编写的 web 服务代码所托管的平台,可以是你自己部署 gitea、gogs 或者是 github 和 gitee 都可以,这里我们以 github 为例进行说明,如果大家对不同代码管理工具的对比甚至是 git 工具本身的使用感兴趣也可以在本文评论区留言,后面开新的文章为大家说明。
上传公钥到 Github
如图所示,进入 github 登陆后,点击图片后进入 settings
在 settings 页面点击 SSH and GPG keys 之后,点击 New SSH key,按照表单将公钥复制进去就可以啦。这里要说明一点,settings 添加的公钥是具备该账户 github 平台所有代码仓库操作权限的,如果只想添加对某个具体仓库的部署公钥,可以在对应代码仓库中进行设置,两者区别这里不展开说明了,有疑问的读者可以评论区留言。
克隆代码到部署服务环境
在添加完部署公钥后,在服务部署环境,可以直接使用代码的 SSH 协议地址(通常代码管理平台支持 HTTPS 和 SSH 两种方式,这里使用 SSH 方式)进行代码克隆。
上面的 project_url 为对应的 github 仓库地址,project_folder 为本地仓库克隆地址,project_folder 可缺省,默认为当前目录加代码仓库名称。
配置 python 虚拟环境并安装依赖
如果使用的是最新的 Ubuntu 和 Centos 发行版的化,默认 python3.8 是系统自带的,如果你的服务需要其他版本的 python,可去 python 官网根据相应环境的安装说明去安装对应版本的 python(这一步也有许多坑,如果这里面也遇到疑问,也欢迎评论区留言)。python 版本没有问题后,以 ubuntu 为例根据如下步骤安装虚拟环境:
这里使用的是 python3 自带的虚拟环境模块,python 虚拟环境的使用方式也有很多种,本文推荐使用官方模块。接下来就是使用 pip 安装服务需要的依赖了。
这一步相信很多 python 开发者就不陌生了。等待依赖安装完成,如果对安装速度不满意也可使用清华、中科大、网易等国内 pypi 镜像源,这里不赘述。
配置 gunicorn
对于大部门使用 flask 作为 python 下 web 开发框架的小伙伴来说,一个简单的 flask run 命令就足以在本地开发环境下将编写好的服务运行起来了,但是要知道在服务器上部署服务和在本地开发服务程序时调试并不是一回事,无论是 flask 还是 django 的文档中都清楚说明了,开发使用的服务工具不适合在服务器端部署使用。开源社区中有许多成熟的服务端部署工具比如 uwsgi、asgi 和 gunicorn 等,它们无论是从安全性、效率和可靠性来讲都是比框架本身使用的测试服务器更优的选择,这里我们选择使用 gunicorn 来部署我们的服务。
这里假定服务已经具备了 wsgi 协议的入口文件 wsgi.py(如何编写配置 wsgi 入口文件以及 wsgi 协议相关内容后面会另开文章介绍),安装并使用 gunicorn 运行一个 flask 应用的方法相对简单:
当然在这一步服务启动时,需要若干服务器配置变量,通常的做法是通过环境变量将 flask 和 gunicorn 的配置变量动态加载,实现这一功能通常使用的 python 包是 dotenv,关于 dotenv 的使用和环境变量与服务之间的关系如果有读者感兴趣会再开文章与大家分享。
上面启动 gunicorn 的方式是从命令行直接加载配置参数启动,通常生产环境不会直接使用这种较为临时的方式启动服务,gunicorn 文档中启动服务的不同方式有详细的说明,常用的启动方式为加载配置文件启动,一个简单的 gunicorn 配置文件如下所示:
gunicorn 配置文件的详细用法和测试后面专文为大家介绍测试和分析,这里不展开。接下来使用如下命令使用配置文件启动 gunicorn:
Supervisor 使用
有了 gunicorn 之后,我们便能使用较为成熟和完善的服务程序来启动 flask,但是直接在命令行上使用 disown 来将 gunicorn 从 shell 进程下 detach 掉,这也不是一个很成熟的 gunicorn 服务使用方法,通常的做法是使用一个工具来将 gunicorn 进程管理起来,一般可以使用发行版自带的系统服务来管理,这里就涉及到编写 system service 配置文件,对这块如果有小伙伴感兴趣后面再开专文介绍。这里我们选择使用 supervisor 进程管理工具来管理 gunicorn 进程:
加下来创建 web 服务程序对应的 supervisor 配置:
将如下配置写入文件中:
上面的配置文件中使用来 run.sh,原因是我们的服务是运行在 python3 的虚拟环境中,我们需要的启动服务前确保虚拟环境被加载,所以在 run.sh 中写入如下脚本:
这个时候,我们 gunicorn 进程管理的 supervisor 配置就已经完成了,下面列出几条 supervisor 管理进程的几条命令:
nginx 使用
接下来我们要做的是把 gunicorn 进程和 nginx 对接起来,即让用户请求通过 nginx 反向代理进 gunicorn,并将响应 response 也通过 nginx 返回给用户,下面先安装 nginx(不同 linux 发行版安装方式略有差别):
安装完 nginx 后,apt 服务会在系统中安装好对应的系统服务,通常安装完成后这个服务也已经被启动起来了,可以通过`systemctl status nginx`命令查看服务状态,接下来就是配置 nginx 连接 gunicorn 的过程了,在 nginx 配置文件中写入如下配置:
这样启动 nginx 之后,我们的服务到 gunicorn 到 nginx 再到用户端的请求的完整链路就彻底打通啦,当然只通过本文是不可能彻底了解 flask、gunicorn、supervisor 和 nginx 的使用和原理的所有细节的,它们每一个的学习和使用都有许多坑在等着各位小伙伴哦,大家也不用担心,这些都是每一个开发者打怪升级路上的必经过程,本文的介绍就到这里,各位小伙伴有问题欢迎评论区留言。
版权声明: 本文为 InfoQ 作者【Langer】的原创文章。
原文链接:【http://xie.infoq.cn/article/5674f3bbfcec4ad92a3bb1f59】。文章转载请联系作者。
评论