FastAPI 工程管理(三) 工程部署
作者:麦克煎蛋 出处:https://www.cnblogs.com/mazhiyong/ 转载请保留这段声明,谢谢!
我们这里不使用容器进行部署。使用容器部署可参考:https://fastapi.tiangolo.com/deployment/
一、安装ASGI兼容Server
我们选择Uvicorn作为ASGI Server。
Uvicorn,是一个闪电般快速的ASGI服务器,基于uvloop和httptools构建。
pip install uvicorn
Uvicorn可按以下方式运行我们的应用:
uvicorn main:app --host 0.0.0.0 --port 80
INFO: Uvicorn running on http://0.0.0.0:80 (Press CTRL+C to quit)
二、使用进程管理器
pip install guvicorn
使用进程管理器确保以弹性方式运行运行多个进程。一个进程管理器将会处理套接字设置,启动多个服务器进程,监控进程活动,监听进程重启、关闭等信号。
Uvicorn 提供一个轻量级的方法来运行多个工作进程,比如 `--workers 4`,但并没有提供进程的监控。
Gunicorn 是成熟的,功能齐全的服务器,Uvicorn 内部包含有 Guicorn 的 workers 类,允许你运行 ASGI 应用程序,这些 workers 继承了所有 Uvicorn 高性能的特点。
使用 Guicorn 来进行进程管理,我们可以动态增加或减少进程数量,平滑地重启工作进程,或者升级服务器而无需停机。
在生产环境中,Guicorn 大概是最简单的方式来管理 Uvicorn 了,生产环境部署我们推荐使用 Guicorn 和 Uvicorn 的 worker 类:
gunicorn example:app -w 4 -k uvicorn.workers.UvicornWorker
执行上述命令将创建 4 个工作进程,其中 UvicornWorker的实现使用 uvloop 和httptools 实现。
Gunicorn 为 Uvicorn 提供了不同的配置选项集,但是一些配置暂不支持,如--limit-concurrency
。
三、部署实践
工程目录结构如下:
├── app │ ├── __init__.py (程序入口) │ └── routers │ ├── __init__.py │ ├── items.py │ └── users.py ├── run.py (服务器运行入口) ├── local.py (本地运行入口) ├── gunicorn.py (Gunicorn设置信息)
1、修改程序入口文件
将初始化代码放到app目录下的__init__.py文件中:
import os from fastapi import Depends, FastAPI, Header, HTTPException from .routers import items, users def create_app(): """Create and configure an instance of the Flask application.""" app = FastAPI() async def get_token_header(x_token: str = Header(...)): if x_token != "fake-super-secret-token": raise HTTPException(status_code=400, detail="X-Token header invalid") app.include_router(users.router) app.include_router( items.router, prefix="/items", tags=["items"], dependencies=[Depends(get_token_header)], responses={404: {"description": "Not found"}}, ) return app
2、添加启动文件
local.py
from app import create_app app = create_app()
在开发环境下,通过以下命令启动应用:
uvicorn local:app --reload
run.py
from app import create_app import logging from fastapi.logger import logger as fastapi_logger from logging.handlers import RotatingFileHandler app = create_app() # 将日志保存到文件中 formatter = logging.Formatter( "[%(asctime)s.%(msecs)03d] %(levelname)s [%(thread)d] - %(message)s", "%Y-%m-%d %H:%M:%S") handler = RotatingFileHandler('/data/log/abc.log', backupCount=0) logging.getLogger().setLevel(logging.NOTSET) fastapi_logger.addHandler(handler) handler.setFormatter(formatter) fastapi_logger.info('****************** Starting Server *****************')
Gunicorn配置文件(gunicorn.py)
# Gunicorn的配置可以参考:
# https://blog.csdn.net/y472360651/article/details/78538188
# https://docs.gunicorn.org/en/stable/settings.html#server-mechanics
debug = True daemon = True bind = '0.0.0.0:9000' # 绑定ip和端口号 # backlog = 512 # 监听队列 chdir = '/data/fastest' # gunicorn要切换到的目的工作目录 timeout = 30 # 超时 # worker_class = 'gevent' #使用gevent模式,还可以使用sync 模式,默认的是sync模式 work_class = 'uvicorn.workers.UvicornWorker' # workers = multiprocessing.cpu_count() * 2 + 1 # 进程数 # threads = 2 #指定每个进程开启的线程数 loglevel = 'debug' # 日志级别,这个日志级别指的是错误日志的级别,而访问日志的级别无法设置 access_log_format = '%(t)s %(p)s %(h)s "%(r)s" %(s)s %(L)s %(b)s %(f)s" "%(a)s"' # 设置gunicorn访问日志格式,错误日志无法设置 """ 其每个选项的含义如下: h remote address l '-' u currently '-', may be user name in future releases t date of the request r status line (e.g. ``GET / HTTP/1.1``) s status b response length or '-' f referer a user agent T request time in seconds D request time in microseconds L request time in decimal seconds p process ID """
# 如果使用service启动,这里的pid路径应与service的pid路径保持一致,否则无法启动 pidfile = "/data/log/fast.pid"
accesslog = "/data/log/gunicorn_fasttest_access.log" # 访问日志文件 errorlog = "/data/log/gunicorn_fasttest_error.log" # 错误日志文件
3、生产环境启动应用
通过脚本可以自动拉取或更新代码到部署目录,然后切换到部署目录下,即可通过以下命令管理应用:
systemctl start/stop/restart gunicorn_fast.service
gunicorn_fast.service内容如下:
[Unit] Description=Gunicorn fast After=syslog.target network.target remote-fs.target nss-lookup.target [Service] Type=forking PIDFile=/data/log/fast.pid
# 这里使用了虚拟环境下的Gunicorn ExecStart=/root/.virtualenvs/ppcms/bin/gunicorn -c /data/fastest/gunicorn.py run:app ExecReload=/bin/kill -s HUP $MAINPID ExecStop=/bin/kill -s QUIT $MAINPID PrivateTmp=true [Install] WantedBy=multi-user.target
4、nginx层
用户访问首先到达nginx层,然后再向后端转发,详细部署暂略。