目标
-
使用docker-compose通过Nginx反向代理在http上发布FastAPI(由uvicorn启动)应用
- 首次发布在http(80端口)上,未经身份验证
文件组织
外壳(重击等)
1 2 3 4 5 6 7 8 9 10 11 12 13 | $ tree . ├── app │ ├── Dockerfile │ ├── app │ │ ├── __init__.py │ │ └── main.py │ ├── poetry.lock │ └── pyproject.toml ├── docker-compose.yml └── web └── conf.d └── app.conf |
-
FastAPI应用程序使用
app/Dockerfile 创建图像-
源代码存储在
app/app 中 -
Python软件包管理在必要时使用
pyproject.toml 和poetry.lock (使用Poetry)-
(没有深层的原因,因此我认为有多种方法可以轻松实现此目的,例如使用
pip + requirements.txt 或使用Pipenv 或miniconda 。)
-
(没有深层的原因,因此我认为有多种方法可以轻松实现此目的,例如使用
-
源代码存储在
-
Nginx使用
web/conf.d/app.conf 设置
docker-compose.yml
- 关于系统配置概述
docker-compose.yml
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 36 37 | version: '3' services: web: container_name: web image: nginx:alpine depends_on: # `app`サービス(コンテナ)が先に起動している必要があるので`depends_on`を指定しておく - app ports: # ポートマッピング: "ホストOSのポート:コンテナ(Nginx)のポート" - "80:80" volumes: # volumeマウント: "ホストOSのパス:コンテナにおけるパス" - ./web/conf.d:/etc/nginx/conf.d networks: - nginx_network app: container_name: app image: test_fastapi_app # ビルドされるDockerイメージ名を指定 build: context: ./app dockerfile: Dockerfile expose: - 8000 networks: - nginx_network # 例えばソースコードをリアルタイムに編集したいときは`volumes`でマウントすると便利 # volumes: # - ./app/app:/app/app # appコンテナの`CMD`を上書きするには`command`を使う # command: "uvicorn app.main:app --reload --host 0.0.0.0" networks: nginx_network: driver: bridge |
-
分别创建Nginx容器
web 和FastAPI应用容器app ,并将它们与docker-compose网络:nginx_network 连接。 - Nginx图像使用轻量级高山版本
稍后将描述
app (快速API应用程序主体)
Dockerfile
Docker文件
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 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 | ARG BASE_IMAGE=python:3.8-slim-buster FROM $BASE_IMAGE # system update & package install RUN apt-get -y update && \ apt-get install -y --no-install-recommends \ build-essential \ openssl libssl-dev \ && apt-get clean \ && rm -rf /var/lib/apt/lists/* # Add Tini ENV TINI_VERSION v0.19.0 ADD https://github.com/krallin/tini/releases/download/${TINI_VERSION}/tini /tini RUN chmod +x /tini ENTRYPOINT ["/tini", "--"] # 一般ユーザーアカウントを追加 ARG USER_NAME=app ARG USER_UID=1000 ARG PASSWD=password RUN useradd -m -s /bin/bash -u $USER_UID $USER_NAME && \ gpasswd -a $USER_NAME sudo && \ echo "${USER_NAME}:${PASSWD}" | chpasswd && \ echo "${USER_NAME} ALL=(ALL) ALL" >> /etc/sudoers # FastAPIのソースコードなどをコンテナ内へCOPY COPY ./app /app/app COPY ./pyproject.toml /app/pyproject.toml # local環境で使用しているpoetry.lockファイルがあればそれも追加する # COPY ./poetry.lock /app/poetry.lock RUN chown -R ${USER_NAME}:${USER_NAME} /app USER $USER_NAME WORKDIR /app # pip & poetry ENV PATH $PATH:/home/${USER_NAME}/.local/bin RUN python3 -m pip install --user --upgrade pip && \ python3 -m pip install poetry --user && \ poetry config virtualenvs.in-project true && \ poetry install && \ rm -rf ~/.cache/pip/* && \ rm -rf ~/.cache/pypoetry/* # Poetryで作った仮想環境にPATHを通しておく(予めpoetryのconfigを設定して仮想環境のPATHを一意にしておく) ENV PATH=/app/.venv/bin:$PATH # Configration EXPOSE 8000 # Execute CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0"] |
-
暂时使用Python版本3.8(使用官方图像的
slim-buster 系列(基于debian的)标签) -
由于
apt 是基于Debian的,因此需要安装它 - 我个人不想以root用户身份启动它,所以我创建了一个用户来启动应用程序
-
tini 可以在没有它的情况下工作,但是启动容器时似乎最好使用它,因此请根据GitHub上的说明进行放置。 -
FastAPI应用程序的一组文件存储在容器的
/app 目录中,并用作工作空间。-
源代码的主体为
/app/app
-
源代码的主体为
-
您正在使用具有本地用户特权的
Poetry 来安装所需的软件包-
poetry config virtualenvs.in-project true 在/app/.venv 中创建虚拟环境 -
如果您有
poetry.lock 文件要在本地环境中进行开发,则可以通过取消注释# COPY ./poetry.lock /app/poetry.lock 来修复要安装的软件包。
-
pyproject.toml
-
有关要安装的软件包等的信息
-
tool.poetry.dependencies 中描述了所需的最少软件包信息,而其他信息则适当。 - (根据需要参考正式文件等进行补充或更正)
-
pyproject.toml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | [tool.poetry] name = "test_fastapi_app" version = "0.1.0" description = "just for test" authors = ["Your Name <[email protected]>"] [tool.poetry.dependencies] python = "^3.8" uvicorn = "*" fastapi = "*" [build-system] requires = ["poetry>=0.12"] build-backend = "poetry.masonry.api" |
FastAPI应用程序
- 这次只有最低限度的准备
main.py
1 2 3 4 5 6 7 8 9 10 11 12 13 | """ app main """ from fastapi import FastAPI app = FastAPI() @app.get('/') async def site_root(): """root""" return {"message": "Hello, WORLD!"} |
-
(
app/app/__init__.py 是一个空文件)
uvicorn
h5>
使用
1 | uvicorn app.main:app --host 0.0.0.0 |
像
。 (请注意,如果目录名或文件名更改,则
可选:
uvicorn服务器默认在端口8000上启动,
如果添加
web (Nginx的Web服务器)
-
app 在容器中运行的uvicorn服务器的反向代理 -
通过在
/etc/nginx/conf.d/***.conf 中写入设置可以进行各种设置-
看来
***.conf 的名称可以是任何东西(这次是app.conf )。
-
app.conf
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | upstream backend { server app:8000; } server { listen 80; # server_name localhost; location / { proxy_pass http://backend; } # log # access_log /var/log/nginx/access.log; # error_log /var/log/nginx/error.log; } |
-
app:8000 的反向代理设置为upstream 。-
我觉得这里的
app 对应于docker-compose.yml 上面写的服务名称(如果不一样,我很抱歉) -
在
location / ,app:8000 的内容发布在Nginx的/ 下。- 结果,如果访问Nginx的端口80,则可以看到FastAPI(uvicorn)的端口8000发布的内容。
-
我觉得这里的
-
如果需要
server_name 或日志输出,请适当地注释掉相关部分。
跑
- 常用物品:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | # `app`のイメージをビルド docker-compose build # サービス全体の起動 docker-compose up -d # 終了時 docker-compose down # コンソール出力の確認 docker-compose logs docker-compose logs app # appサービスのログのみ確認 # appコンテナの中に入る docker-compose run app bash |
如果设置正确,则执行
-
http://本地主机(在本地环境中运行时)
-
http://本地主机/ docs(在本地环境中运行时)
您会看到类似
的屏幕。
在AWS上的EC2之类的远程环境中运行时,如果将其替换为运行
概要
我制作了一个标题类似的结构,内容尽可能少。
这次我还没有完成,但是您可以将Nginx用于SSL(HTTPS通信)和BASIC身份验证。
→另外,使用Jinja2的模板功能时,我非常沉迷于SSL转换(https变为http,使用默认端口以外的端口时端口号信息丢失,并且链接功能不可用。效果很好),所以我将分别计划 del>。 (↓以下)