fastapi 项目部署的几种方式

准备

将要使用的FastAPI版本“固定”到特定的最新版本,该特定版本是您的应用程序正在使用的版本。

fastapi==0.45.0
# 版本固定在 0.45

当然,一般用 pip 命令导出的 requirements.txt都是固定版本的

pip freeze > requirements.txt
# 安装
pip install -r requirements.txt

开始部署

部署服务至服务器,有多种方式。下面则是官网介绍的几种的介绍

Deta

一种没有听说过的东西,应该是:一个简单部署工具,国内没有太多介绍或者使用者,或者说你不加 fastapi 关键字都搜索不倒它。不过看官方的示例使用它还是特别简单的。

官方文档找不到的介绍,在国内通过搜索也是找不到的

(它的 https 在 fastapi 官网据说是自动处理的,但是是如何处理的呢? deta 的文档也没看到此项说明)。

于此 暂不考虑此工具

Docker

Docker 是一个开源的应用容器引擎,基于 Go 语言 并遵从 Apache2.0 协议开源。

Docker 可以让开发者打包他们的应用以及依赖包到一个轻量级、可移植的容器中,然后发布到任何流行的 Linux 机器上,也可以实现虚拟化。

容器是完全使用沙箱机制,相互之间不会有任何接口(类似 iPhone 的 app ),更重要的是容器性能开销极低。

菜鸟教程

可以将 docker 简单理解成一个虚拟机,里面可以安装各种应用 python, nginx....

个人感觉它就是将你的项目(代码,数据库...)整合,方便迁移和管理。但是服务器本身也提供了快照,镜像等方式用于迁移,所以刚需性并没有那么强。(当然他还有整合许多其他东西,方便管理整个项目(如版本回退等)。

这些都是我个人的看法,我对它的并没有过多的了解。它对我并不是刚需。所以下文也只是简单的介绍

使用 Docker 进行部署。它具有一些优点,例如安全性,可复制性,开发简单等。

它里面使用的 ASGI(异步网关协议接口, WSGI Web 服务器网关接口)也是 Uvicorn

看样子也是挺简单方便的。

同时如果是使用官方的 cli 工具生成的项目,本身就是基于 Docker. 那么 Docker 应该是最好的选择。(官网的 cli 甚至继承的 vue 前端,太过臃肿了吧)。 后续我会试一下使用 这个 cli 构建项目。

手动部署 uvicorn + nginx

这才是我的部署方式,这个站点 www.hcuan.top (用的是 flask + uwsgi +nginx) 现在还是有点后悔的,因为后续管理啥的还是有点麻烦:更新需要手动 push, 管理日志也要手动配置,等等。而宝塔这些东西感觉听上去好美好(但还是坚持手动部署吧,还年轻没到享乐的时候🙃

uvicorn

是一款如闪电般快速的 ASGI 服务器,基于 uvloop 和 httptools 构建。

uvloop 用于替换标准库 asyncio 中的事件循环,使用 Cython 实现,它非常快,可以使 asyncio 的速度提高 2-4 倍。

httptools 是 nodejs HTTP 解析器的 Python 实现。

fastapi 一般是使用 uvicorn 启动的,所以你应该早已安装了它

使用

uvicorn main:app --host 0.0.0.0 --port 80
# 注意去除了,开发环境时的 --reload 

注意如果启动到后台在外部是没有关闭它的接口的,但可以通过杀进程等方式

Uvicorn 为单进程的 ASGI server ,而 Gunicorn 是管理运行多个 Uvicorn ,以达到并发与并行的最好效果。

Gunicorn 对其包装

Gunicorn 是成熟的,功能齐全的服务器, Uvicorn 内部包含有 Guicorn 的 workers 类,允许你运行 ASGI 应用程序,这些 workers 继承了所有 Uvicorn 高性能的特点,并且给你使用 Guicorn 来进行进程管理。

其实这里就又有选择了 uWSGI vs Gunicorn :(gunicorn 很火, uwsgi 以前用的人多 ) gunicorn 配置简单一点,我使用的是 uWSGI. 此处主要是官网介绍的是 Gunicorn

使用应该是这样的,但这显然不太优雅:

gunicorn -w 2 -b 0.0.0.0:8000 -k uvicorn.workers.UvicornWorker --access-logfile log/access.log main:app

通过 gunicorn -h 可以看到它有非常多的配置项,所以我们可以通过配置文件启动:

# gun.py
import multiprocessing

# 协程需要此补丁
# form gevent import monkey
# monkey.patch_all()
# 其他非uvicorn需打开此配置 
# worker_class = "gevent"

# ip + port
bind = "127.0.0.1:8001"
# 超时时间
timeout = 40

# 并行工作进程数
workers = multiprocessing.cpu_count() * 2 + 1
# 每个进程开启的线程数
threads = 2
#服务器中在pending状态的最大连接数 (建议 64-2048)
backlog = 2048


# sync(同步, eventlet(并发), gevent(协程, tornado, gthread,此处使用
worker_class = "uvicorn.workers.UvicornWorker"

# 客户端同时最大连接数,适用于 gevent eventlet
worker_connections = 1000

# 以守护进程形式运行:后台运行
daemon = True

loglevel = 'debug'
pidfile = 'log/gunicorn.pid'
accesslog = 'log/gun-access.log'
errorlog = 'log/gun-error.log'

# reload=true 自动重启
# chdir = '/path/' 指定它的工作路径

使用:

gunicorn -c gconfig.py main:app

此时停止或重启服务也是使用 kill 进程的方式,

tips :这是使用 guicorn 启动服务,并在里面继承了 Uvicorn 高性能的特点。其实这已经不叫包装了。

nginx

如果你没有 nginx 的配置部署经验,建议自己百度。此处仅为了说明他与一般 python web 项目接入 nginx 的方式大致相同

# nginx-conf

server {
    listen    80;
    # 域名
    server_name api.test.com;

    location / {
        # 非必需,设置以便 程序识别出真正的客户端信息,如 IP 地址,scheme 等。
        proxy_redirect off;
        proxy_buffering off;
        proxy_set_header Host $http_host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        # 必要
        proxy_pass http://127.0.0.1:8001; #gunicorn运行的端口            
    }
    location /static {
      # path for static files
      root /path/to/app/static;
    }
}

关于 https 证书,本身在 uvicorn 或者 Gunicorn 都是可以设置证书的,但是不知道中间隔一层 nginx 是否可以生效。所以最好还是直接在 nginx 里设置证书,都是挺简单的。


管理服务/进程

如果服务器重启,或者程序因为意外而被关闭。那么我们的服务显然不会再重新启动。如果需要使得服务随系统启动,并且程序意外关闭自动开启,那么可以引入 进程管理软件来管理我们的软件。

supervisor 管理进程,是通过 fork/exec 的方式将这些被管理的进程当作 supervisor 的子进程来启动,所以我们只需要将要管理进程的可执行文件的路径添加到 supervisor 的配置文件中就好了。

这并不是我要使用的,因为他还需要安装。下面我们使用的是 linux 自带的 systemd

systemd Systemd 是一个系统管理守护进程、工具和库的集合,用于取代 System V 初始进程。Systemd 的功能是用于集中管理和配置类 UNIX 系统. Systemd 并不是一个命令,而是一组命令,涉及到系统管理的方方面面。

注意一些软件在

管理 nginx

1 在/lib/systemd/system/ 下编写配置文件

# /lib/systemd/system/nginx.service

# 启动顺序与依赖关系。
[Unit] 
Description=nginx - web server
After=network.target remote-fs.target nss-lookup.target

# 如何启动当前服务
[Service]
# 定义启动类型 simple(默认值:启动的进程为主进程) forKing(以fork()方式启动,...) ...
Type=forking

ExecStart=/usr/local/nginx/sbin/nginx -c /...你的配置文件地址/
ExecReload=/usr/local/nginx/sbin/nginx -s reload
ExecStop=/usr/local/nginx/sbin/nginx -s quit

# 是否使用私有的tmp目录(默认所有 systemd启动的服务共用一个/temp目录)
PrivateTmp=true

# 如何安装这个配置文件,即怎样做到开机启动。
[Install]
# 定义该服务所在的 target(服务组)
WantedBy=multi-user.target

tips: ExecReload 和 Execstop 项不写也可以停止服务,原理是: 没有配置 ExecStop , Systemd 默认将发送SIGTERM信号到主进程,并等待 TimeoutStopSec 配置的时间后查看进程是否已终止,如果没配置这个时间默认是 90s。

90s 以后, systemd 会检查进程有没有停止成功,如果还没停止,则 systemd 会发送SIGKILL信号来强杀进程完成该任务。如果主进程 fork 了其他子进程,则 systemd 也会一并停止它们,因为它们都位于同一个 cgroup 中。

ExecStop=除非您有其他关闭服务的方法,否则您无需指示。

将此服务添加到开启自启:

systemctl enable nginx.service
# 当前如果是为启动状态,则通过下命令启动
systemctl start nginx.service

管理 gunicorn

也是 也是使用 systemd

# vi /usr/lib/systemd/system/gunicorn.service
[Unit]
Description=gunicorn-fastapi project
After=network.target

[Service]
Type=forking
ExecStart=/python虚拟环境路径/python gunicorn -c /配置文件路径/gun.py /项目文件路径/main:app
PrivateTmp=true

Restart=always
# 程序退出后的等待秒数
RestartSec=42s

[Install]
WantedBy=multi-user.target

Restart= 定义了程序退出后的重启方式,支持的值

  • no 退出后不会重启(默认值)
  • on-success :只有正常退出时(退出状态码为 0 ),才会重启
  • on-failure :非正常退出时(退出状态码非 0 ),包括被信号终止和超时,才会重启
  • on-abnormal :只有被信号终止和超时,才会重启
  • on-abort :只有在收到没有捕捉到的信号终止时,才会重启
  • on-watchdog :超时退出,才会重启
  • always : 只要不是通过 systemctl stop 来停止服务,总是重启

注意 .service 文件中的注释不是 '#', 如需使用请删除注释.

使用

systemctl enable gunicorn
# .service 可省略 centos7
systemctl start gunicorn

systemd 常用命令

管理服务

# 立即启动一个服务
$ sudo systemctl start apache.service

# 立即停止一个服务
$ sudo systemctl stop apache.service

# 重启一个服务
$ sudo systemctl restart apache.service

# 将服务添加到开机自启
$ systemctl enable mysqld

# 移除开机启动
$ systemctl disable mysqld

# 杀死一个服务的所有子进程
$ sudo systemctl kill apache.service

# 重新加载一个服务的配置文件
$ sudo systemctl reload apache.service

# 重载所有修改过的配置文件
$ sudo systemctl daemon-reload  

查询单个

# 显示系统状态
$ systemctl status

# 显示单个 Unit 的状态
$ sysystemctl status bluetooth.service

# 显示某个 Unit 的所有底层参数
$ systemctl show httpd.service

# 显示某个 Unit 是否正在运行
$ systemctl is-active application.service

# 显示某个 Unit 是否处于启动失败状态
$ systemctl is-failed application.service

# 显示某个 Unit 服务是否建立了启动链接
$ systemctl is-enabled application.service

查询所有

# 列出正在运行的 Unit
$ systemctl list-units

# 列出所有Unit,包括没有找到配置文件的或者启动失败的
$ systemctl list-units --all

# 列出所有没有运行的 Unit
$ systemctl list-units --all --state=inactive

# 列出所有加载失败的 Unit
$ systemctl list-units --failed

# 列出所有正在运行的、类型为 service 的 Unit
$ systemctl list-units --type=service

Systemd 可以管理所有系统资源。不同的资源统称为 Unit (单位)。

这里的命令归纳来自于 csdn, 只应用了感兴趣的部分,剩余还有关于系统相关的命令,及配置文件的介绍。同时阮一峰的网络日志 也有关于此的介绍。


嗯,阿里云的主机. 之前的活动没有了。现在新买了一个轻量服务器,安装了宝塔,确实很方便啊。不过其对 python 项目的(项目管理器),不太友好!


相关推荐:

来自系列:fastapi

分类 python下文章:

1.0 爬虫的介绍,和requests模块的简单使用

1.1 数据解析的三种方式。正则表达式, bs4, xpath

2.0 多任务(进程,协程,线程)爬虫:验证码识别,返回头储存,ip代理 介绍。 异步是什么,爬虫异步的方式。线程,进程,介绍

2.0.1 协程的 async/await 实现 爬虫 单线程 + 异步协程的实现

3.0 基于selenium 模块的 爬虫操作。 selenium 是一个用于Web应用程序测试的工具。Selenium测试直接运行在浏览器中,就像真正的用户在操作一样。

更多...

aid 加一试试->

评论([[comments.sum]])

发表

加载更多([[item.son.length - 2]])...

发表

2020-11 By Hchuan.

flask & bootstrap-flask

© 2021 HChuan. All rights reserved.

随机占位图来自:fghrsh

互联网ICP备案号:蜀ICP备2020031846号