🫥

DockerでFastAPI環境構築(HelloWorldまで)

2024/05/15に公開

FastAPI環境構築


リンク

チュートリアル - ユーザーガイド - FastAPI

使用技術

環境

  • Docker
  • Python 3.12.3(執筆時最新)
  • nginx(webサーバー)

DB

  • MySQL 8系
  • SQLModel(ORマッパー)
  • alembic(マイグレーション管理)

ライブラリ管理

  • poetry

構成はシンプルでnginxをwebサーバーとして配置して、Uvicormをアプリケーションサーバーにします。

ディレクトリ作成

最低限のディレクトリを作成していきます。

project_root
├── _docker
│   ├── nginx
│   │   └── nginx.conf
│   └── python
│       └── Dockerfile
├── src
│   └── main.py
├── .env
├── pyproject.toml
└── docker-compose.yml

/_docker/python/Dockerfile(仮なので最後に再編集します)

pythonのDockerfileです。ライブラリ管理にpoetryを使用するのと、テストDBにsqliteを使用するので、ここでインストールしています。

FROM python:3.12.3

SHELL ["/bin/bash", "-c"]

# 作業ディレクトリの設定
WORKDIR /src

RUN apt-get update && \
    apt-get install -y build-essential libffi-dev && \
    apt-get install -y sqlite3

RUN pip install --upgrade pip

# 必要なファイルのコピー
COPY ./pyproject.toml /src/pyproject.toml

# Poetryのインストール
RUN curl -sSL https://install.python-poetry.org | python -

ENV PATH="/root/.local/bin:$PATH"

# Poetryの設定と依存関係のインストール
RUN poetry config virtualenvs.create false && \
    poetry install --no-interaction --no-root

# アプリケーションの起動コマンドを設定
ENTRYPOINT ["uvicorn", "src.main:app", "--host", "0.0.0.0", "--reload"]

/_docker/nginx/nginx.conf

FastAPIへ繋ぐためのプロキシ設定です。

events {}

http {
    server {
        listen 80;

        location / {
            proxy_pass http://fastapi:8000;
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header X-Forwarded-Proto $scheme;
        }
    }
}

/docker-compose.yml

特段、普通の設定かと思います。volumeを使用して永続化を行なったり、MySQLのDBを作成したりしています。

version: '3.8'
services:
  fastapi:
    build:
      context: .
      dockerfile: _docker/python/Dockerfile
    volumes:
      - .:/src
      - bash-data:/root/.local/bin
      - python-lib-data:/usr/local/lib/
    ports:
      - "8000:8000"
    depends_on:
      - mysql

  nginx:
    image: nginx:latest
    ports:
      - "80:80"
    volumes:
      - ./_docker/nginx/nginx.conf:/etc/nginx/nginx.conf
    depends_on:
      - fastapi

  mysql:
    image: mysql:latest
    command: --default-authentication-plugin=mysql_native_password
    restart: always
    environment:
      MYSQL_DATABASE: 'fastapi_db'
      MYSQL_USER: 'user'
      MYSQL_PASSWORD: 'password'
      MYSQL_ROOT_PASSWORD: 'password'
    ports:
      - "3334:3306"
    volumes:
      - mysql-data:/var/lib/mysql

volumes:
  mysql-data:
  bash-data:
  python-lib-data:

/src/main.py

とりあえず疎通確認ができるように公式のコードをコピペ

from fastapi import FastAPI

app = FastAPI()

.get("/")
async def root():
    return {"message": "Hello World"}

/pyproject.toml

poetry initで自動作成できるが、dockerでやるのも手間なので手動で作成しておくのが無難だと思います。今回も手動で作成します。(最低限のライブラリのみ記載)

[tool.poetry]
name = "my_project"
version = "0.1.0"
description = ""
authors = ["Your Name <you@example.com>"]

[tool.poetry.dependencies]
python = "^3.12"
fastapi = "^0.111.0"
uvicorn = "^0.29.0"

[tool.poetry.dev-dependencies]

[build-system]
requires = ["poetry-core"]
build-backend = "poetry.core.masonry.api"

ビルドと起動

docker compose up --build -d

下記にアクセスして、接続できたら環境の構築は完了です。

http://localhost:8000/

このままだとライブラリのバージョンが環境によって不揃いになってしまいます。

なので、poetry.lockファイルを生成しましょう。

コンテナに入る

docker compose exec -it fastapi /bin/bash

コンテナ内でロックファイルを生成
root:/src# poetry lock

ルートにロックファイルが生成されます。

project_root
├── _docker
│   ├── nginx
│   │   └── nginx.conf
│   └── python
│       └── Dockerfile
├── src
│   └── main.py
├── .env
├── pyproject.toml
├── poetry.lock <-これが作成されます。
└── docker-compose.yml

ビルドする際にもlockファイルをコンテナにコピーするようにします。

FROM python:3.12.3

SHELL ["/bin/bash", "-c"]

# 作業ディレクトリの設定
WORKDIR /src

RUN apt-get update && \
    apt-get install -y build-essential libffi-dev && \
    apt-get install -y sqlite3

RUN pip install --upgrade pip

# 必要なファイルのコピー
COPY ./pyproject.toml /src/pyproject.toml
COPY ./poetry.lock /src/poetry.lock // 追加

# Poetryのインストール
RUN curl -sSL https://install.python-poetry.org | python -

ENV PATH="/root/.local/bin:$PATH"

# Poetryの設定と依存関係のインストール
RUN poetry config virtualenvs.create false && \
    poetry install --no-interaction --no-root

# アプリケーションの起動コマンドを設定
ENTRYPOINT ["uvicorn", "src.main:app", "--host", "0.0.0.0", "--reload"]

再ビルド

docker compose build --no-cache
docker compose up -d

キャッシュあってもいいなら
docker compose up --build -d

再度、コンテナを起動してlocalhost:8000にアクセス
ブラウザに下記が表示されればOKです。

{"message":"Hello World"}

これで基本的な環境はできたかと思います。

コマンドの簡略化

怠惰なので、長いコマンドをいちいち打ちたくないです。

例えばコンテナ内に入るときも

docker compose exec -it fastapi /bin/bash

だるすぎます。

なので、makeコマンドで下記のように簡略化します。

make api

まずはmakeコマンドをローカルとコンテナ内で使用することを考えます。

makefileにはincludeが備わっていることに加え、条件分岐も使用できます。

この辺を応用して、ローカルとコンテナ内でmakeコマンドを別管理していきます。

まずは本体のmakeファイルの作成をローカルで行います。

/makefile

ifeq ($(MAKE_ENV), container)
    include makefile.container
else
    include makefile.local
endif

環境変数MAKE_ENVに値を持たせて、環境によってinclude先を分けます。

Dockerfileの修正

FROM python:3.12.3

SHELL ["/bin/bash", "-c"]

# 作業ディレクトリの設定
WORKDIR /src

RUN apt-get update && \
    apt-get install -y build-essential libffi-dev && \
    apt-get install -y sqlite3

RUN pip install --upgrade pip

# 必要なファイルのコピー
COPY ./pyproject.toml /src/pyproject.toml
COPY ./poetry.lock /src/poetry.lock

# Poetryのインストール
RUN curl -sSL https://install.python-poetry.org | python -

# 環境変数の設定
ENV MAKE_ENV=container // 追加
ENV PATH="/root/.local/bin:$PATH"

# Poetryの設定と依存関係のインストール
RUN poetry config virtualenvs.create false && \
    poetry install --no-interaction --no-root

# アプリケーションの起動コマンドを設定
ENTRYPOINT ["uvicorn", "src.main:app", "--host", "0.0.0.0", "--reload"]

ここからは実際のコマンドが記載されたmakeファイルを環境ごとに作成します。

  • makefile.local
  • makefile.container

/makefile.local

.PHONY: help print build-local up down api
.DEFAULT_GOAL := help

print: ## 分岐テスト用
	echo "ローカル"

build: ## Build docker image to local
	docker compose build --no-cache

up: ## Start docker container
	docker compose up -d

down: ## Stop docker container
	docker compose down

api: ## Run python container
	docker compose exec -it fastapi /bin/bash

/makefile.container

.PHONY: help print
.DEFAULT_GOAL := help

print: ## 分岐テスト用
	echo "コンテナ"

これで完了です。

再ビルドしましょう

make build

下記のように環境によって同じコマンドでも分けて使用できれば完了です。

ローカル

make print
//出力
echo "ローカル"
ローカル

コンテナ

make api
//出力
docker compose exec -it fastapi /bin/bash

make print
// 出力
echo "コンテナ"
コンテナ

poetryやこの後(記載予定)のマイグレーションコマンドなど真価を発揮するのでmakeファイルは作成しておいて損はないと思います。

Discussion