当前位置:   article > 正文

Docker部署FastApi详解,这一篇就够了_uvicorn fastapi用于生产

uvicorn fastapi用于生产

首先废话一下,FastAPI是一种现代,快速(高性能)的Web框架,用于基于标准Python类型提示使用Python 3.6+构建API。据说是go+nodejs的竞争对手。

☞  FastAPI 官方文档

这里主要讲的是uvicorn-gunicorn-fastapi 这个Fastapi的官方镜像,主要的技术细节:

Uvicorn

Uvicorn是一款闪电般的“ ASGI”服务器。

它在单个过程中运行异步Python Web代码。

Gunicorn

您可以使用Gunicorn管理Uvicorn和运行多个这些并发进程。

这样,您将获得最佳的并发性和并行性。

FastAPI

FastAPI是一种现代,快速(高性能)的Web框架,用于使用Python 3.6+构建API。

反正主要使用的技术就是UvicornGunicorn官网介绍说其是站在巨人肩膀上的框架,也确实有其流弊之处吧。

这里主要介绍 tiangolo/uvicorn-gunicorn-fastapi ,适用于生产环境,官网的其他镜像也至少改变的操作系统的版本为了缩减体积。

git 传送 ☞    uvicorn-gunicorn-fastapi

用法:

  1. #Dockerfile
  2. FROM tiangolo/uvicorn-gunicorn-fastapi:python3.7
  3. COPY ./app /app

dockerfile的意思就是把你的代码(./app)复制到 /app文件夹中。

当然前提是至少需要一个main.py的配置文件下面是镜像能读取的两个默认位置,选择一个去放就好了。

/app/app/main.py

/app/main.py

main.py类似于这样:

  1. #这个其实就是镜像中自带的main.py 位置/app/main.py
  2. import sys
  3. from fastapi import FastAPI
  4. version = f"{sys.version_info.major}.{sys.version_info.minor}"
  5. app = FastAPI()
  6. @app.get("/")
  7. async def read_root():
  8. message = f"Hello world! From FastAPI running on Uvicorn with Gunicorn. Using Python {version}"
  9. return {"message": message}

你自己的目录结构大概就是这样:

  1. .
  2. ├── app
  3. │ └── main.py
  4. └── Dockerfile

然后就是构建镜像:

  1. # 在dockerfile的路径下执行 myimage 替换成自己的起的名字作为镜像名
  2. docker build -t myimage ./

然后你可以试着启动一下了:

docker run -d --name mycontainer -p 80:80 myimage

当然,上面讲的情况是把你自己代码放进去部署,如果只是想验证以下效果不用去看上面的直接执行:

  1. docker pull tiangolo/uvicorn-gunicorn-fastapi:python3.7
  2. docker run -d --name fastapidemo -p 80:80 tiangolo/uvicorn-gunicorn-fastapi:python3.7

然后用浏览器打开以下链接测试以下:

  1. http://127.0.0.1/
  2. #返回{"message":"Hello world! From FastAPI running on Uvicorn with Gunicorn. Using Python 3.7"}
  3. http://127.0.0.1/docs
  4. #API文档
  5. http://127.0.0.1/redoc
  6. # 备用API文档

API文档类似:

不用惊讶,FastApi内置了swgger文档 ,你只要正常写方法就可以了,但是类型还是要注意一下像下面这样是完全没用问题的:

  1. @app.get("/items/{item_id}")
  2. def read_item(item_id: int, q: str = None):
  3. return {"item_id": item_id, "q": q}

当然肯定也有更复杂的需求,比如:安装一个依赖管理工具 Poetry,你可以这样组织你的dockerfile:

  1. FROM tiangolo/uvicorn-gunicorn-fastapi:python3.7
  2. # Install Poetry
  3. RUN curl -sSL https://raw.githubusercontent.com/python-poetry/poetry/master/get-poetry.py | POETRY_HOME=/opt/poetry python && \
  4. cd /usr/local/bin && \
  5. ln -s /opt/poetry/bin/poetry && \
  6. poetry config virtualenvs.create false
  7. # Copy using poetry.lock* in case it doesn't exist yet
  8. COPY ./app/pyproject.toml ./app/poetry.lock* /app/
  9. RUN poetry install --no-root --no-dev
  10. COPY ./app /app

 

用法挺简单,但是里面包含的功能一点也不简单。

我们上面使用的镜像 tiangolo/uvicorn-gunicorn-fastapi:python3.7 如果追溯它的源镜像那就是下面这个:

  1. # DockerFile tiangolo/uvicorn-gunicorn-fastapi:python3.7
  2. FROM python:3.7
  3. LABEL maintainer="Sebastian Ramirez <tiangolo@gmail.com>"
  4. RUN pip install --no-cache-dir uvicorn gunicorn
  5. COPY ./start.sh /start.sh
  6. RUN chmod +x /start.sh
  7. COPY ./gunicorn_conf.py /gunicorn_conf.py
  8. COPY ./start-reload.sh /start-reload.sh
  9. RUN chmod +x /start-reload.sh
  10. COPY ./app /app
  11. WORKDIR /app/
  12. ENV PYTHONPATH=/app
  13. EXPOSE 80
  14. # Run the start script, it will check for an /app/prestart.sh script (e.g. for migrations)
  15. # And then will start Gunicorn with Uvicorn
  16. CMD ["/start.sh"]

git 地址我也贴一下 ☞ tiangolo/uvicorn-gunicorn-fastapi:python3.7 构建代码

下面重点来了 ,如何使用 环境变量 去更改默认的配置

(1)MODULE_NAME:

由Gunicorn导入的Python“模块”(文件),该模块将在变量中包含实际的应用程序,就是上面说的main.lpy

默认值:

如果你的main.py 是这个路径 /app/app/main.py  那么 值为 app.main

路径是 /app/main.py  值为main

在运行的时候这样就改变默认的值:

docker run -d -p 80:80 -e MODULE_NAME="custom_app.custom_main" myimage

(2)VARIABLE_NAME

默认: app

如果你的main文件是这样写的 你需要把它改成api

  1. from fastapi import FastAPI
  2. api = FastAPI()
  3. @api.get("/")
  4. def read_root():
  5. return {"Hello": "World"}
  1. docker run -d -p 80:80 -e VARIABLE_NAME="api" myimage
  2. # 运行时修改VARIABLE_NAME

(3)APP_MODULE

把上面两个变量结合起来就是这个变量

docker run -d -p 80:80 -e APP_MODULE="custom_app.custom_main:api" myimage

(4)GUNICORN_CONF

Gunicorn Python配置文件的路径。

默认:

  • /app/gunicorn_conf.py 如果存在
  • /app/app/gunicorn_conf.py 如果存在
  • /gunicorn_conf.py (包含的默认值)

设置方法:

docker run -d -p 80:80 -e GUNICORN_CONF="/app/custom_gunicorn_conf.py" myimage

(4)常用的 HOST(容器内使用)PORT BIND 

默认就是0.0.0.0:80  略。

(5)LOG_LEVEL Gunicorn日志级别

  • debug
  • info
  • warning
  • error
  • critical  

默认:info

docker run -d -p 80:8080 -e LOG_LEVEL="warning" myimage

(6)TIMEOUT 沉默(silent )了多少秒的Workers 被杀死并重新启动。

默认:120

像FastAPI这样的Uvicorn和ASGI框架是异步的,而不是同步的。因此,与同步工作器相比,拥有更高的超时可能是安全的。

您可以将其设置为:

docker run -d -p 80:8080 -e TIMEOUT="20" myimage

(7)GRACEFUL_TIMEOUT

正常工作人员的超时重新启动。Gunicorn文档中了解更多有关此内容的信息:graceful-timeout

默认:120

docker run -d -p 80:8080 -e GRACEFUL_TIMEOUT="20" myimage

(8)KEEP_ALIVE

等待“保持活动”连接上的请求的秒数。

Gunicorn docs:keepalive中阅读更多有关它的信息。

默认情况下,设置为2

您可以将其设置为:

docker run -d -p 80:8080 -e KEEP_ALIVE="20" myimage

 

(9)ACCESS_LOG

要写入的访问日志文件。

默认情况下"-",表示stdout(在Docker日志中打印)。

如果要禁用ACCESS_LOG,请将其设置为空值。

例如,您可以通过以下方式禁用它:

  1. docker run -d -p 80:8080 -e ACCESS_LOG= myimage
  2. #注意这里表示设置为空值
 

(10)ERROR_LOG

要写入的错误日志文件。

默认情况下"-",表示stderr(在Docker日志中打印)。

如果要禁用ERROR_LOG,请将其设置为空值。

例如,您可以通过以下方式禁用它:

docker run -d -p 80:8080 -e ERROR_LOG = myimage

(11)GUNICORN_CMD_ARGS

Gunicorn的任何其他命令行设置都可以在GUNICORN_CMD_ARGS环境变量中传递。

Gunicorn文档:设置中阅读更多相关信息。

这些设置将优先于其他环境变量和任何Gunicorn配置文件。

例如,如果您具有要使用的自定义TLS / SSL证书,则可以将其复制到Docker映像或将其安装在容器中,然后设置--keyfile--certfile文件的位置,例如:

docker run -d -p 80:8080 -e GUNICORN_CMD_ARGS = “” --keyfile = / secrets / key.pem --certfile = / secrets / cert.pem “ -e PORT = 443

注意:建议不要使用Traefik之类的“ TLS终止代理”,而是自己处理TLS / SSL并在容器中进行配置。您可以在有关HTTPSFastAPI文档中阅读有关它的更多信息。

 

(12)PRE_START_PATH

预启动脚本的路径

默认:/app/prestart.sh 

设置方法:

docker run -d -p 80:8080 -e PRE_START_PATH="/custom/script.sh" myimage

这个重点说一下默认的文件如下:

  1. #! /usr/bin/env sh
  2. # 文件路径:/app/prestart.sh 
  3. echo "Running inside /app/prestart.sh, you could add migrations to this file, e.g.:"
  4. echo "
  5. #! /usr/bin/env bash
  6. # Let the DB start
  7. sleep 10;
  8. # Run migrations
  9. alembic upgrade head
  10. "

启动时就是这样的,在这里加载一些需要的脚本就好,一般写等待10s是给数据库启动留下的时间。

 
 

像 /app/prestart.sh  还有gunicorn_conf.py这种开发常用的配置文件推荐的方法:

是写你自己的dockerfile的时候,编写命令把他们的从默认位置替换掉就好了。

  • /app/gunicorn_conf.py
  • /app/app/gunicorn_conf.py
  • /gunicorn_conf.py

当然,环境变量也不是必须在启动时从docker run 后面指定,使用dockerfile的ENV设置能获得更好的体验

其他功能 :开发时重载

基于 : /start-reload.sh

生产环境是默认使用的是  /start.sh

使用方法:

docker run -d -p 80:80 -v $(pwd):/app myimage /start-reload.sh
  • -v $(pwd):/app:表示该目录$(pwd)应作为卷挂载到位于的容器内/app
    • $(pwd):运行pwd(“打印工作目录”),并将其作为字符串的一部分。
  • /start-reload.sh/start-reload.sh在命令末尾添加一些内容(如),用此命令替换默认的“命令”。在这种情况下,它将/start.sh开发替代项替换为default()/start-reload.sh

由于/start-reload.sh不与Gunicorn一起运行,因此您放入gunicorn_conf.py文件中的任何配置都将不适用。

但是这些环境变量的工作原理与上述相同:

 

  • MODULE_NAME
  • VARIABLE_NAME
  • APP_MODULE
  • HOST
  • PORT
  • LOG_LEVEL

贴一下这俩文件代码:

  1. # /start.sh
  2. #! /usr/bin/env sh
  3. set -e
  4. if [ -f /app/app/main.py ]; then
  5. DEFAULT_MODULE_NAME=app.main
  6. elif [ -f /app/main.py ]; then
  7. DEFAULT_MODULE_NAME=main
  8. fi
  9. MODULE_NAME=${MODULE_NAME:-$DEFAULT_MODULE_NAME}
  10. VARIABLE_NAME=${VARIABLE_NAME:-app}
  11. export APP_MODULE=${APP_MODULE:-"$MODULE_NAME:$VARIABLE_NAME"}
  12. if [ -f /app/gunicorn_conf.py ]; then
  13. DEFAULT_GUNICORN_CONF=/app/gunicorn_conf.py
  14. elif [ -f /app/app/gunicorn_conf.py ]; then
  15. DEFAULT_GUNICORN_CONF=/app/app/gunicorn_conf.py
  16. else
  17. DEFAULT_GUNICORN_CONF=/gunicorn_conf.py
  18. fi
  19. export GUNICORN_CONF=${GUNICORN_CONF:-$DEFAULT_GUNICORN_CONF}
  20. export WORKER_CLASS=${WORKER_CLASS:-"uvicorn.workers.UvicornWorker"}
  21. # If there's a prestart.sh script in the /app directory or other path specified, run it before starting
  22. PRE_START_PATH=${PRE_START_PATH:-/app/prestart.sh}
  23. echo "Checking for script in $PRE_START_PATH"
  24. if [ -f $PRE_START_PATH ] ; then
  25. echo "Running script $PRE_START_PATH"
  26. . "$PRE_START_PATH"
  27. else
  28. echo "There is no script $PRE_START_PATH"
  29. fi
  30. # Start Gunicorn
  31. exec gunicorn -k "$WORKER_CLASS" -c "$GUNICORN_CONF" "$APP_MODULE"
  1. # /start-reload.sh
  2. #! /usr/bin/env sh
  3. set -e
  4. if [ -f /app/app/main.py ]; then
  5. DEFAULT_MODULE_NAME=app.main
  6. elif [ -f /app/main.py ]; then
  7. DEFAULT_MODULE_NAME=main
  8. fi
  9. MODULE_NAME=${MODULE_NAME:-$DEFAULT_MODULE_NAME}
  10. VARIABLE_NAME=${VARIABLE_NAME:-app}
  11. export APP_MODULE=${APP_MODULE:-"$MODULE_NAME:$VARIABLE_NAME"}
  12. HOST=${HOST:-0.0.0.0}
  13. PORT=${PORT:-80}
  14. LOG_LEVEL=${LOG_LEVEL:-info}
  15. # If there's a prestart.sh script in the /app directory or other path specified, run it before starting
  16. PRE_START_PATH=${PRE_START_PATH:-/app/prestart.sh}
  17. echo "Checking for script in $PRE_START_PATH"
  18. if [ -f $PRE_START_PATH ] ; then
  19. echo "Running script $PRE_START_PATH"
  20. . "$PRE_START_PATH"
  21. else
  22. echo "There is no script $PRE_START_PATH"
  23. fi
  24. # Start Uvicorn with live reload
  25. exec uvicorn --reload --host $HOST --port $PORT --log-level $LOG_LEVEL "$APP_MODULE"

 

 

 
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小蓝xlanll/article/detail/72157
推荐阅读
相关标签
  

闽ICP备14008679号