Skip to content

デプロイ

本番環境にデプロイする時に FastAPI アプリを起動する方法とかデプロイの自動化とか。

Info

uv のインストールが完了した Rocky Linux 9 にデプロイする前提で。


Uvicorn と Gunicorn

FastAPI をインストールしてれば、 Uvicorn も入ってるはず。

Note

fastapi dev コマンドと fastapi run コマンドは Uvicorn で FastAPI アプリを起動する。

ただ、 Uvicorn の公式ドキュメントで

Run gunicorn -k uvicorn.workers.UvicornWorker for production.

https://uvicorn.dev/deployment/ より

とあるので、 Gunicorn を使う。
さらに、 Uvicorn の公式ドキュメントには gunicorn で uvicorn ワーカーを使うときは、 uvicorn-worker を使うべきって書いてある。

Warning

The uvicorn.workers module is deprecated and will be removed in a future release. You should use the uvicorn-worker package instead.

python -m pip install uvicorn-worker

https://uvicorn.dev/deployment/#gunicorn より

uvicorn-worker を PyPI で検索すると、 gunicorn コマンドで使う時の例が書かれてる。

Deployment

For production environments, it's recommended to utilize Gunicorn with the Uvicorn worker class. Below is an example of how to do this:

gunicorn example:app -w 4 -k uvicorn_worker.UvicornWorker

https://uvicorn.dev/deployment/#gunicorn より

Gunicorn を uvicorn-worker で動かすために uv コマンドでインストールしておく。

uv add gunicorn uvicorn-worker


Gunicorn の起動設定

gunicorn コマンドで FastAPI アプリを起動する。

uv run gunicorn -w 3 -k uvicorn_worker.UvicornWorker -b 0.0.0.0:8000 main:app

毎回このコマンドを打つのはめんどい・・・コンフィグファイルを作成して、起動時に読み込ませることができる。

# gunicorn_config.py
import multiprocessing

worker_class = "uvicorn_worker.UvicornWorker" 
workers = multiprocessing.cpu_count() * 2 + 1
bind = "0.0.0.0:8000" 

Info

FastAPI Cookbook (by Giunio De Luca, 2024) には、

A common heuristic is to use the formula workers = (2 x cores) + 1 , where cores means the number of CPU cores on the server.
— p.313 とあるので、 multiprocessing を使って自動で計算させるといいかも。

gunicorn コマンドで gunicorn_config.py を読み込んでFastAPI アプリを起動する。

uv run gunicorn -c gunicorn_config.py main:app

Gunicorn はデーモンモード( -D, daemon = True)で起動することもできるけど、停止する時に kill コマンドを使う方法しか分からなくて微妙。 systemd で起動・停止できるようにも設定できるので、 systemd の設定ファイルを作成する。

[root@test ~]# vi /etc/systemd/system/fastapi-app.service
[Unit]
Description=Gunicorn instance to serve FastAPI App
After=network.target

[Service]
User=test
Group=test
WorkingDirectory=/home/test/my-fastapi-app
ExecStart=/home/test/.local/bin/uv run gunicorn -c gunicorn_config.py app.main:app
Restart=always
RestartSec=5

[Install]
WantedBy=multi-user.target

[root@test ~]# systemctl daemon-reload

これで、 systemctl コマンドで fastapi-app サービスを起動・停止できるようになる。


GitHub Actions を使った CD (Continuous Deploy) 実装

プロジェクトを GitHub でバージョン管理してるなら、 GitHub Actions を使ってデプロイの自動化ができる。
必要なのは YAML ファイルとローカルサーバーの設定、 YAML ファイルは .github/workflows/my-actions.yml のように作成する。

Warning

バグった状態でデプロイしないためにも、デプロイの前に pytest でテストを実行して成功したらデプロイするっていう自動化プロセスにするべき。

Warning

GitHub Actionsを狙った攻撃も実際にあった( https://tanstack.com/blog/npm-supply-chain-compromise-postmortem )ので、自動化するならプライベートリポジトリでやる方がいいはず。

  • YAMLファイル

    # (YAMLファイルの例)
    name: CD without CI
    
    on:
    push:
        branches: [ "main" ]
    
    jobs:
    deploy:
        name: Deploy to Production
        runs-on: self-hosted
    
        steps:
        - name: Deploy checked commit
            run: |
            cd /home/test/my-fastapi-app
            previous_sha=$(git rev-parse HEAD)
            echo "PREVIOUS_SHA=${previous_sha}" >> "$GITHUB_ENV"
            git fetch origin main
            git checkout --detach "${{ github.sha }}"
            uv sync --frozen
    
        - name: Restart FastAPI Service
            run: sudo systemctl restart fastapi-app
    
  • ローカルサーバーの設定

    GitHubリポジトリ > Settings > Actions > Runners で表示される通りに設定を進める。