首先废话一下,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。
反正主要使用的技术就是Uvicorn和Gunicorn,官网介绍说其是站在巨人肩膀上的框架,也确实有其流弊之处吧。
这里主要介绍 tiangolo/uvicorn-gunicorn-fastapi ,适用于生产环境,官网的其他镜像也至少改变的操作系统的版本为了缩减体积。
git 传送 ? uvicorn-gunicorn-fastapi
用法:
1 2 3 4 5 | #Dockerfile FROM tiangolo/uvicorn-gunicorn-fastapi:python3.7 COPY ./app /app |
dockerfile的意思就是把你的代码(./app)复制到 /app文件夹中。
当然前提是至少需要一个main.py的配置文件下面是镜像能读取的两个默认位置,选择一个去放就好了。
/app/app/main.py
/app/main.py
main.py类似于这样:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | #这个其实就是镜像中自带的main.py 位置/app/main.py import sys from fastapi import FastAPI version = f"{sys.version_info.major}.{sys.version_info.minor}" app = FastAPI() @app.get("/") async def read_root(): message = f"Hello world! From FastAPI running on Uvicorn with Gunicorn. Using Python {version}" return {"message": message} |
你自己的目录结构大概就是这样:
1 2 3 4 | . ├── app │ └── main.py └── Dockerfile |
然后就是构建镜像:
1 2 | # 在dockerfile的路径下执行 myimage 替换成自己的起的名字作为镜像名 docker build -t myimage ./ |
然后你可以试着启动一下了:
1 | docker run -d --name mycontainer -p 80:80 myimage |
当然,上面讲的情况是把你自己代码放进去部署,如果只是想验证以下效果不用去看上面的直接执行:
1 2 3 | docker pull tiangolo/uvicorn-gunicorn-fastapi:python3.7 docker run -d --name fastapidemo -p 80:80 tiangolo/uvicorn-gunicorn-fastapi:python3.7 |
然后用浏览器打开以下链接测试以下:
1 2 3 4 5 6 7 8 | http://127.0.0.1/ #返回{"message":"Hello world! From FastAPI running on Uvicorn with Gunicorn. Using Python 3.7"} http://127.0.0.1/docs #API文档 http://127.0.0.1/redoc # 备用API文档 |
API文档类似:

不用惊讶,FastApi内置了swgger文档 ,你只要正常写方法就可以了,但是类型还是要注意一下像下面这样是完全没用问题的:
1 2 3 | @app.get("/items/{item_id}") def read_item(item_id: int, q: str = None): return {"item_id": item_id, "q": q} |

当然肯定也有更复杂的需求,比如:安装一个依赖管理工具 Poetry,你可以这样组织你的dockerfile:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | FROM tiangolo/uvicorn-gunicorn-fastapi:python3.7 # Install Poetry RUN curl -sSL https://raw.githubusercontent.com/python-poetry/poetry/master/get-poetry.py | POETRY_HOME=/opt/poetry python && \ cd /usr/local/bin && \ ln -s /opt/poetry/bin/poetry && \ poetry config virtualenvs.create false # Copy using poetry.lock* in case it doesn't exist yet COPY ./app/pyproject.toml ./app/poetry.lock* /app/ RUN poetry install --no-root --no-dev COPY ./app /app |
用法挺简单,但是里面包含的功能一点也不简单。
我们上面使用的镜像 tiangolo/uvicorn-gunicorn-fastapi:python3.7 如果追溯它的源镜像那就是下面这个:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | # DockerFile tiangolo/uvicorn-gunicorn-fastapi:python3.7 FROM python:3.7 LABEL maintainer="Sebastian Ramirez <[email protected]>" RUN pip install --no-cache-dir uvicorn gunicorn COPY ./start.sh /start.sh RUN chmod +x /start.sh COPY ./gunicorn_conf.py /gunicorn_conf.py COPY ./start-reload.sh /start-reload.sh RUN chmod +x /start-reload.sh COPY ./app /app WORKDIR /app/ ENV PYTHONPATH=/app EXPOSE 80 # Run the start script, it will check for an /app/prestart.sh script (e.g. for migrations) # And then will start Gunicorn with Uvicorn CMD ["/start.sh"] |
git 地址我也贴一下 ? tiangolo/uvicorn-gunicorn-fastapi:python3.7 构建代码
下面重点来了 ,如何使用 环境变量 去更改默认的配置:
由Gunicorn导入的Python“模块”(文件),该模块将在变量中包含实际的应用程序,就是上面说的main.lpy
默认值:
如果你的main.py 是这个路径 /app/app/main.py 那么 值为 app.main
路径是 /app/main.py 值为main
在运行的时候这样就改变默认的值:
1 | docker run -d -p 80:80 -e MODULE_NAME="custom_app.custom_main" myimage |
(2)
默认: app
如果你的main文件是这样写的 你需要把它改成api
1 2 3 4 5 6 7 8 | from fastapi import FastAPI api = FastAPI() @api.get("/") def read_root(): return {"Hello": "World"} |
1 2 | docker run -d -p 80:80 -e VARIABLE_NAME="api" myimage # 运行时修改VARIABLE_NAME |
(3)APP_MODULE
把上面两个变量结合起来就是这个变量
1 | docker run -d -p 80:80 -e APP_MODULE="custom_app.custom_main:api" myimage |
(4)
Gunicorn Python配置文件的路径。
默认:
/app/gunicorn_conf.py 如果存在/app/app/gunicorn_conf.py 如果存在/gunicorn_conf.py (包含的默认值)
设置方法:
1 | docker run -d -p 80:80 -e GUNICORN_CONF="/app/custom_gunicorn_conf.py" myimage |
(4)常用的
默认就是0.0.0.0:80 略。
(5)
debug info warning error critical
默认:info
1 | docker run -d -p 80:8080 -e LOG_LEVEL="warning" myimage |
默认:120
像FastAPI这样的Uvicorn和ASGI框架是异步的,而不是同步的。因此,与同步工作器相比,拥有更高的超时可能是安全的。
您可以将其设置为:
1 | docker run -d -p 80:8080 -e TIMEOUT="20" myimage |
(7)
正常工作人员的超时重新启动。在Gunicorn文档中了解更多有关此内容的信息:graceful-timeout。
默认:120
1 | docker run -d -p 80:8080 -e GRACEFUL_TIMEOUT="20" myimage |
等待“保持活动”连接上的请求的秒数。
在Gunicorn docs:keepalive中阅读更多有关它的信息。
默认情况下,设置为
您可以将其设置为:
1 | docker run -d -p 80:8080 -e KEEP_ALIVE="20" myimage |
要写入的访问日志文件。
默认情况下
如果要禁用
例如,您可以通过以下方式禁用它:
1 2 | docker run -d -p 80:8080 -e ACCESS_LOG= myimage #注意这里表示设置为空值 |
1 | <wyn> |
(10)
要写入的错误日志文件。
默认情况下
如果要禁用
例如,您可以通过以下方式禁用它:
1 | docker run -d -p 80:8080 -e ERROR_LOG = myimage |
Gunicorn的任何其他命令行设置都可以在
在Gunicorn文档:设置中阅读更多相关信息。
这些设置将优先于其他环境变量和任何Gunicorn配置文件。
例如,如果您具有要使用的自定义TLS / SSL证书,则可以将其复制到Docker映像或将其安装在容器中,然后设置
1 | 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并在容器中进行配置。您可以在有关HTTPS的FastAPI文档中阅读有关它的更多信息。
(12)
预启动脚本的路径
默认:/app/prestart.sh
设置方法:
1 | docker run -d -p 80:8080 -e PRE_START_PATH="/custom/script.sh" myimage |
这个重点说一下默认的文件如下:
1 2 3 4 5 6 7 8 9 10 11 12 | #! /usr/bin/env sh # 文件路径:/app/prestart.sh echo "Running inside /app/prestart.sh, you could add migrations to this file, e.g.:" echo " #! /usr/bin/env bash # Let the DB start sleep 10; # Run migrations alembic upgrade head " |
启动时就是这样的,在这里加载一些需要的脚本就好,一般写等待10s是给数据库启动留下的时间。

像 /app/prestart.sh 还有
/app/gunicorn_conf.py /app/app/gunicorn_conf.py /gunicorn_conf.py
当然,环境变量也不是必须在启动时从docker run 后面指定,使用dockerfile的ENV设置能获得更好的体验
其他功能 :开发时重载
基于 : /start-reload.sh
生产环境是默认使用的是 /start.sh
使用方法:
1 | 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 。
由于
但是这些环境变量的工作原理与上述相同:
MODULE_NAME VARIABLE_NAME APP_MODULE HOST PORT LOG_LEVEL
贴一下这俩文件代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | # /start.sh #! /usr/bin/env sh set -e if [ -f /app/app/main.py ]; then DEFAULT_MODULE_NAME=app.main elif [ -f /app/main.py ]; then DEFAULT_MODULE_NAME=main fi MODULE_NAME=${MODULE_NAME:-$DEFAULT_MODULE_NAME} VARIABLE_NAME=${VARIABLE_NAME:-app} export APP_MODULE=${APP_MODULE:-"$MODULE_NAME:$VARIABLE_NAME"} if [ -f /app/gunicorn_conf.py ]; then DEFAULT_GUNICORN_CONF=/app/gunicorn_conf.py elif [ -f /app/app/gunicorn_conf.py ]; then DEFAULT_GUNICORN_CONF=/app/app/gunicorn_conf.py else DEFAULT_GUNICORN_CONF=/gunicorn_conf.py fi export GUNICORN_CONF=${GUNICORN_CONF:-$DEFAULT_GUNICORN_CONF} export WORKER_CLASS=${WORKER_CLASS:-"uvicorn.workers.UvicornWorker"} # If there's a prestart.sh script in the /app directory or other path specified, run it before starting PRE_START_PATH=${PRE_START_PATH:-/app/prestart.sh} echo "Checking for script in $PRE_START_PATH" if [ -f $PRE_START_PATH ] ; then echo "Running script $PRE_START_PATH" . "$PRE_START_PATH" else echo "There is no script $PRE_START_PATH" fi # Start Gunicorn exec gunicorn -k "$WORKER_CLASS" -c "$GUNICORN_CONF" "$APP_MODULE" |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | # /start-reload.sh #! /usr/bin/env sh set -e if [ -f /app/app/main.py ]; then DEFAULT_MODULE_NAME=app.main elif [ -f /app/main.py ]; then DEFAULT_MODULE_NAME=main fi MODULE_NAME=${MODULE_NAME:-$DEFAULT_MODULE_NAME} VARIABLE_NAME=${VARIABLE_NAME:-app} export APP_MODULE=${APP_MODULE:-"$MODULE_NAME:$VARIABLE_NAME"} HOST=${HOST:-0.0.0.0} PORT=${PORT:-80} LOG_LEVEL=${LOG_LEVEL:-info} # If there's a prestart.sh script in the /app directory or other path specified, run it before starting PRE_START_PATH=${PRE_START_PATH:-/app/prestart.sh} echo "Checking for script in $PRE_START_PATH" if [ -f $PRE_START_PATH ] ; then echo "Running script $PRE_START_PATH" . "$PRE_START_PATH" else echo "There is no script $PRE_START_PATH" fi # Start Uvicorn with live reload exec uvicorn --reload --host $HOST --port $PORT --log-level $LOG_LEVEL "$APP_MODULE" |