「FastAPIで作ったAPIを、ちゃんとDockerで動かせるようにしたい」という動機で調べはじめました。Lambda関数としてデプロイする機会が多かったんですが、コンテナイメージとして動かす構成も覚えておきたくて。
この記事では、FastAPIアプリのDockerfile作成からdocker-composeでの起動、開発環境でのホットリロード設定やTipsをまとめています。
この記事でわかること
- FastAPIのDockerコンテナ化の基本
- 効率的なDockerfileの書き方(レイヤーキャッシュを活用した高速ビルド)
docker-composeでの開発環境構築- 開発時のホットリロード設定
- 本番環境を意識した設定(ワーカー数など)
FastAPIとDockerを組み合わせる理由
FastAPIはそのままuvicornコマンドで起動できますが、チームで使ったり本番環境にデプロイするとなると「どの環境でも同じように動く」保証が欲しくなります。Dockerはそこを解決してくれます。
それと、AWS LambdaもECRのコンテナイメージから関数を作成してデプロイできるようになっていて、「Lambdaもコンテナも同じDockerfileで」という開発スタイルが増えてきた印象です。コンテナイメージとして動かせるようにしておくと、ECS・Lambda・Lightsailなど選択肢が広がるのでやっておいて損はないかなと。
最小構成のFastAPIアプリを作る
最初はシンプルに。以下のディレクトリ構成で進めます。
my-api/
├── app/
│ └── main.py
├── requirements.txt
└── Dockerfile
app/main.pyはこんな感じです。
from fastapi import FastAPI
app = FastAPI()
@app.get("/")
def read_root():
return {"message": "Hello, World!"}
@app.get("/health")
def health_check():
return {"status": "ok"}
requirements.txtは最小限で。
fastapi[standard]
余談ですが、fastapi[standard]と書くとuvicornなど必要なものがまとめてインストールされるようです。地味に便利です。
Dockerfileを書く
ここが本題です。よく見かける古い書き方と、今の書き方の違いを意識しながら書きました。
FROM python:3.12-slim
WORKDIR /code
COPY ./requirements.txt /code/requirements.txt
RUN pip install --no-cache-dir --upgrade -r /code/requirements.txt
COPY ./app /code/app
CMD ["fastapi", "run", "app/main.py", "--port", "80", "--host", "0.0.0.0"]
以前は起動コマンドが uvicorn app.main:app --host 0.0.0.0 --port 80 みたいな書き方が主流でしたが、fastapi run コマンドが使えるようになってかなりシンプルになりました。fastapi run は内部でuvicornを使って動いてくれます。
ポイントをいくつか書いておきます。
- python:3.12-slimを使う。
python:3.12(フル版)より小さくできることが多いです - COPYの順番が大事。
requirements.txtを先にコピーしてpip installしてから、ソースコードをコピーする。こうすることでコードだけ変更したときにpipのレイヤーキャッシュが使われてビルドが速くなる --no-cache-dirをつけてイメージサイズを削減
レイヤーキャッシュの順番については最初わかってなくて「なんかビルド遅いな」ってなってました。COPY . .を先に書くとコード変更のたびにpipが全部走るので地味につらいです。
ビルドして動かす
Dockerfileが書けたら、ビルドして起動します。
# イメージのビルド
docker build -t my-fastapi-app .
# コンテナの起動(ポート8000→80にマッピング)
docker run -p 8000:80 my-fastapi-app
http://localhost:8000にアクセスして{"message": "Hello, World!"}が返ってくれば成功です。FastAPIの自動生成ドキュメントはhttp://localhost:8000/docsで確認できます。Swagger UIが表示されるので、これを見るたびにちょっとテンション上がります。
docker-composeで管理する
実際の開発ではdocker composeを使うことが多いです。DBを一緒に立ち上げたり、環境変数を管理したりが楽になります。
シンプルなcompose.yamlはこんな感じです(docker composeは既定でcompose.yamlやdocker-compose.yamlなどを探索してくれます)。
services:
api:
build: .
ports:
- "8000:80"
volumes:
- ./app:/code/app # 開発時:ホットリロード用にマウント
environment:
- ENV=development
起動は docker compose up でOKです。ログを見ながら動かしたいときは docker compose up、バックグラウンドで動かすときは docker compose up -d。
ただ、上のvolumesの設定はあくまで開発時用です。本番ではvolumesを外してイメージに焼き込む運用が正しいはず。この使い分けをちゃんと意識するようになったのは割と最近です。
開発環境でホットリロードを使う
コードを変更するたびにコンテナを再起動するのは面倒なので、開発中はホットリロードを使います。
compose.yamlのcommandを上書きする方法が一番シンプルです。
services:
api:
build: .
ports:
- "8000:80"
volumes:
- ./app:/code/app
command: ["fastapi", "dev", "app/main.py", "--host", "0.0.0.0", "--port", "80"]
fastapi devコマンドがホットリロードモードで起動してくれます。--reloadフラグを自分で渡さなくていいのが地味に便利です。ファイルを変更するとコンテナ内でも自動的に反映されます。
本番を意識するなら:uvicornワーカー数の設定
EC2やLightsailに乗せるような場合、複数ワーカーを動かしたほうがスループットが上がることがあります。fastapi runに--workersオプションを渡すだけです。
CMD ["fastapi", "run", "app/main.py", "--port", "80", "--host", "0.0.0.0", "--workers", "4"]
ただしLambdaでの挙動や、ECSなどのオーケストレーション環境で「ワーカーを増やす」か「コンテナを増やす」かの考え方は、要件や構成によって変わります。正直このあたりの正解はまだ自分の中で消化しきれていないので、もう少し実戦で試したいところです。
最終的なファイル構成まとめ
整理するとこんな構成になります。
my-api/
├── app/
│ └── main.py
├── compose.yaml
├── requirements.txt
└── Dockerfile
最終的なDockerfile(本番用):
FROM python:3.12-slim
WORKDIR /code
COPY ./requirements.txt /code/requirements.txt
RUN pip install --no-cache-dir --upgrade -r /code/requirements.txt
COPY ./app /code/app
CMD ["fastapi", "run", "app/main.py", "--port", "80", "--host", "0.0.0.0"]
開発用compose.yaml:
services:
api:
build: .
ports:
- "8000:80"
volumes:
- ./app:/code/app
command: ["fastapi", "dev", "app/main.py", "--host", "0.0.0.0", "--port", "80"]
このセットがあれば「ローカルで開発→イメージをビルドして本番へ」という流れが一通りできるようになります。
※この記事にはプロモーションが含まれます
ちなみに、お名前.com レンタルサーバー(WordPressに特化した高速レンタルサーバー。月額990円〜、独自ドメイン実質0円)も気になっています。お名前.com レンタルサーバー![]()
まとめ
- FastAPIはDockerコンテナ化することで、環境の差異をなくして本番デプロイがしやすくなる
- Dockerfileはレイヤーキャッシュを活用するために、
requirements.txtを先にコピーすることが重要 fastapi runはuvicornより簡潔で、新しいバージョンではこちらが推奨されるdocker composeで開発環境と本番環境の設定を分けると、管理しやすくなる- 開発時は
fastapi devでホットリロード、本番時はfastapi runで起動することで、開発体験と本番の安定性の両立が可能

