2
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【環境構築】FastAPI + Docker + PostgreSQL

Last updated at Posted at 2025-10-26

概要

RESTful API開発を想定したFastAPIバックエンド環境の構築手順をまとめました。

PostgreSQL + SQLModel、uvパッケージマネージャやRuffなど、モダンなPython開発で標準的に使われる技術を組み合わせた実用的な構成を紹介します。

この記事で学べること

  • モダンな技術スタックの選定理由: ビジネス観点と技術観点から各技術を選ぶ根拠
  • uvによる高速な環境構築: 次世代パッケージマネージャの活用
  • Ruffによるコード品質管理: フォーマッターとリンターの統合設定
  • Dockerによる開発環境: ローカルとコンテナ環境の両立
  • PostgreSQL + SQLModelの連携: 非同期ORMの基本セットアップ

想定読者

  • Pythonの基本文法を理解している方
  • FastAPIでバックエンド開発を始めたい方
  • モダンな開発環境の構築方法を学びたい方
  • チーム開発を見据えた環境設定を知りたい方

本記事では、パッケージマネージャのインストールから、Docker環境での起動確認まで、段階的に解説していきます。
実装編では、この環境を使って実際のAPIエンドポイントを構築します。

ご指摘やご質問等ありましたら、コメントをお願いいたします。

動作環境

OS macOS Tahoe 26.0.1
Python 3.13系
エディタ VSCode

本記事は上記環境を前提とした内容です。

技術選定

フレームワーク FastAPI
パッケージマネージャー uv
DB PostgreSQL
ORM SQLModel
ツール Ruff

これらが選定される具体的なシチュエーションを、下記にビジネス観点(顧客都合)と技術観点(開発者都合)での必要性に分けてまとめました。

FastAPI

選定理由

ビジネス観点での必要性

  • 高速なレスポンス:
    API応答速度が速いことで、サービス全体のパフォーマンスが向上
  • 短期間での市場投入:
    開発速度が速く、機能追加やピボットが容易なため、ビジネス変化に素早く対応可能
  • API仕様書の自動生成:
    外部パートナーやフロントエンド開発者との連携がスムーズになり、統合コストを削減
  • 将来的な拡張性:
    非同期処理により、ユーザー数増加に対応しやすく、サーバーコストの最適化が可能

技術観点での必要性

  • モダンなPython機能の活用:
    型ヒント、async / awaitなど最新機能を使用でき、コード品質が向上
  • 優れた開発者体験:
    IDEの補完が効き、デバッグが容易で、開発ストレスが少ない
  • 豊富なエコシステム:
    プラグインやミドルウェアが充実しており、車輪の再発明を避けられる
  • 学習リソースの豊富さ:
    ドキュメントが充実し、コミュニティが活発で、問題解決が迅速

PostgreSQL

選定理由

ビジネス観点での必要性

  • データの安全性と信頼性:
    ACID特性によりデータ損失リスクが極小。ビジネスの根幹であるデータを確実に保護
  • コスト効率:
    オープンソースでライセンス費用不要。商用DBへの移行コストも発生しない
  • 長期的な安定性:
    30年以上の実績があり、突然のサポート終了リスクが低い
  • スケーラビリティ:
    事業成長に応じて段階的に拡張可能で、初期投資を抑えられる

技術観点での必要性

  • 豊富な機能セット:
    JSON型、配列型、全文検索など、アプリケーション層での実装が不要
  • SQL標準への準拠:
    他のDBからの移行や、開発者の学習転用がしやすい
  • 拡張機能の充実:
    PostGIS、pg_trgmなど、特殊要件にも対応可能
  • デバッグのしやすさ:
    EXPLAINによるクエリ分析、詳細なログ出力で性能チューニングが容易

SQLModel

選定理由

ビジネス観点での必要性

  • 開発スピードの向上:
    コード量が削減され、新機能のリリースサイクルが短縮
  • バグの減少:
    型安全性により実行時エラーが減り、サービス品質が向上
  • メンテナンスコストの削減:
    コードの可読性が高く、将来的な機能追加や修正が容易

技術観点での必要性

  • DRY原則の徹底:
    モデル定義の重複を排除し、コード保守性が向上
  • FastAPIとのシームレスな連携:
    同一作者のライブラリで設計思想が統一されており、学習コストが低い
  • 型チェックの恩恵:
    IDE補完とmypyによる静的解析で、開発時のエラー発見が容易
  • SQLAlchemyの機能を継承:
    複雑なクエリや高度な機能も利用可能で、技術的な制約が少ない

uv

選定理由

ビジネス観点での必要性

  • CI/CD時間の短縮:
    デプロイ時間が短縮され、障害対応やリリース頻度が向上
  • 開発コストの削減:
    セットアップ時間が短縮され、新メンバーのオンボーディングが迅速
  • 環境の再現性:
    本番と開発環境の差異が減り、「ローカルでは動く」問題が減少

技術観点での必要性

  • 圧倒的な速度:
    依存関係のインストールが高速で、開発イテレーションが快適
  • シンプルな操作性:
    既存のpip知識が活用でき、チーム全体での採用障壁が低い
  • 仮想環境管理の一元化:
    複数ツールの使い分けが不要で、環境構築の認知負荷が低い
  • モダンな依存解決:
    ロックファイルによる厳密なバージョン管理で、デバッグが容易

Ruff

選定理由

ビジネス観点での必要性

  • コード品質の担保:
    自動チェックにより、ヒューマンエラー起因のバグが減少
  • レビュー時間の短縮:
    スタイルの議論が不要になり、本質的なロジックレビューに集中可能
  • チーム間の一貫性:
    コードスタイルが統一され、メンテナンス引き継ぎが円滑

技術観点での必要性

  • 高速な実行:
    リアルタイムでのリンティングが可能で、開発フローが中断されない
  • オールインワン:
    複数ツールの設定・管理が不要で、ツールチェインがシンプル
  • 既存ツールとの互換性:
    段階的な移行が可能で、既存プロジェクトへの導入リスクが低い
  • 設定の簡潔さ:
    pyproject.toml一つで管理でき、プロジェクト設定が見通しやすい

導入手順

1. パッケージマネージャーの設定

FastAPIやSQLModelを扱うために、パッケージマネージャーとしてuvをインストールします。

Terminal
# インストール
curl -LsSf https://astral.sh/uv/install.sh | sh

# バージョン確認
uv self version
>>> uv 0.9.5 (d5f39331a 2025-10-21)

バージョンが出力されていればインストール完了です。
uvを使って初期環境の構築を行います。

Terminal
# プロジェクトディレクトリの作成
mkdir myproject

# sampleディレクトリに移動
cd myproject

# ソース格納用ディレクトリの作成
mkdir -p src/app

# uvの初期処理
uv init

# main.pyの移動
mv main.py src/app

myproject部分は任意のプロジェクト名です。

ディレクトリ構成は下記のようになっているはずです。
プロジェクト内で統一したいパッケージの依存関係やFormat / Lintの設定はpyproject.toml に追記します。

myproject/
    ├─ .gitignore
    ├─ .python-version
    ├─ pyproject.toml
    ├─ README.md
    └─ src/
        └─ app/
            └─ main.py

2. フォーマッターとリンターの設定

フォーマッター兼リンターとしてRuffの設定を行います。
下記のVSCode拡張機能をインストールしてください。

Ruff:
https://marketplace.visualstudio.com/items?itemName=charliermarsh.ruff)

pyproject.toml に下記設定を追記します。

pyproject.toml
[tool.ruff]
line-length = 120
target-version = "py313"
src = ["src"]

[tool.ruff.format]
indent-style = "space"
line-ending = "lf"
quote-style = "double"
skip-magic-trailing-comma = false

[tool.ruff.lint]
exclude = [
    ".venv",
]
ignore = [
    "B008",
    "E501",
]
select = [
    "B",
    "C4",
    "E",
    "F",
    "I",
    "T20",
    "W",
]

[tool.ruff.isort]
combine-as-imports = true
force-sort-within-sections = true
lines-after-imports = 2
known-first-party = ["src"]

設定内容はプロジェクトに合わせて変更してください。

.vscode/settings.json に下記を追記し、ファイル保存時に強制的にフォーマットされるようにします。

.vscode/settings.json
{
    "editor.codeActionsOnSave": {
        "source.organizeImports.ruff": "always"
    },
    "editor.defaultFormatter": "charliermarsh.ruff",
    "editor.formatOnSave": true,
    "python.analysis.typeCheckingMode": "basic",
    "ruff.configuration": "pyproject.toml",
    "ruff.format.enable": true,
    "ruff.lint.enable": true
}

src/app/main.py などを好きに編集し、Ruffが機能することを確認してください。

動作しない場合は、VSCodeを再起動してください。

3. ローカル環境の構築

ローカルでの開発環境を構築します。
パッケージの依存関係を pyproject.toml に設定します。

選定したフレームワークやORMは、ここに記載します。

pyproject.toml
dependencies = [
    "fastapi>=0.115.5",
    "uvicorn[standard]>=0.32.1",
    "sqlmodel>=0.0.22",
    "sqlalchemy[asyncio]>=2.0.44",
    "asyncpg>=0.30.0",
    "pydantic>=2.10.3",
]

下記コマンドを実行し、上記のパッケージ群を仮想環境にインストールします。

Terminal
uv sync

プロジェクトルートに .venv が作成されていることを確認してください。
下記コマンドで仮想環境を起動します。

Terminal
source .venv/bin/activate

アプリケーションを起動するための導線を src/main.py に作成します。

src/main.py
from fastapi import FastAPI


app = FastAPI(
    title="MyProject API",
    description="A FastAPI application with PostgreSQL",
    version="0.1.0",
)

仮想環境上でアプリケーションを実行してみます。

Terminal
uvicorn src.app.main:app --reload --host 0.0.0.0 --port 8000

下のようなログが出力されていればローカル環境での起動が成功しています。
CTRL+C でuvicornを停止してください。

INFO:     Uvicorn running on http://0.0.0.0:8000 (Press CTRL+C to quit)
INFO:     Started reloader process [.....] using WatchFiles
INFO:     Started server process [.....]
INFO:     Waiting for application startup.
INFO:     Application startup complete.

ここまでで、フレームワークやORMをローカル環境で扱う準備が整いました。
このままでも開発を進めることはできますが、Dockerコンテナ上での開発の方が何かと便利なため、続いて同様の環境をDocker上に構築していきます。

これ以降、上記ローカル実行用のコマンドを使うことは基本的にありません。

4. Docker環境の構築

ルート直下に Dockerfile を作成し、下記のように記述します。

Dockerfile
FROM ghcr.io/astral-sh/uv:python3.13-bookworm-slim

ENV PYTHONUNBUFFERED=1 \
    PYTHONDONTWRITEBYTECODE=1 \
    UV_SYSTEM_PYTHON=1 \
    TZ=UTC

WORKDIR /code

RUN apt-get update && apt-get install -y --no-install-recommends \
    libpq-dev \
    && rm -rf /var/lib/apt/lists/*

COPY pyproject.toml uv.lock README.md ./
RUN uv sync --frozen --no-cache

COPY ./src /code/src

RUN useradd -m -u 1000 appuser && \
    chown -R appuser:appuser /code
USER appuser

EXPOSE 8000

CMD ["uv", "run", "uvicorn", "src.app.main:app", "--host", "0.0.0.0", "--port", "8000"]

この Dockerfile をコンテナとして立ち上げるために docker-compose.yml を作成します。

docker-compose.yml
services:
  db:
    image: postgres:16.6-alpine
    container_name: myproject_postgres
    volumes:
      - myproject_postgres_data:/var/lib/postgresql/data
    user: ${POSTGRES_USER}
    environment:
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
      POSTGRES_DB: ${POSTGRES_DB}
      POSTGRES_INITDB_ARGS: "--encoding=UTF-8 --locale=C"
      TZ: ${TZ}
      PGTZ: ${TZ}
    ports:
      - "${POSTGRES_PORT}:5432"
    healthcheck:
      test: ["CMD-SHELL", "pg_isready"]
      interval: 10s
      timeout: 5s
      retries: 5
      start_period: 20s
    restart: unless-stopped

  web:
    build:
      context: .
      dockerfile: Dockerfile
    container_name: myproject_web
    command: uv run uvicorn src.app.main:app --host 0.0.0.0 --port 8000 --reload
    volumes:
      - ./src:/code/src
    ports:
      - "${APP_PORT}:8000"
    environment:
      POSTGRES_USER: ${POSTGRES_USER}
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
      POSTGRES_DB: ${POSTGRES_DB}
      POSTGRES_HOST: ${POSTGRES_HOST}
      POSTGRES_PORT: ${POSTGRES_PORT}
      TZ: ${TZ}
    depends_on:
      db:
        condition: service_healthy
    restart: unless-stopped
    develop:
      watch:
        - action: sync
          path: ./src
          target: /code/src

volumes:
  myproject_postgres_data:
    driver: local

networks:
  default:
    name: myproject_network

docker-compose.yml 内で使用されている変数を .env で指定します。

.env.example
# Timezone
TZ=UTC

# Database Configuration
POSTGRES_USER=postgres
POSTGRES_PASSWORD=postgres
POSTGRES_DB=myproject_db
POSTGRES_PORT=5432
POSTGRES_HOST=db

# Application Configuration
APP_PORT=8000
DATABASE_URL=postgresql://${POSTGRES_USER}:${POSTGRES_PASSWORD}@${POSTGRES_HOST}:${POSTGRES_PORT}/${POSTGRES_DB}

.env.example をコピーして、実際の .env を作成します。

Terminal
cp .env.example .env

コンテナを起動し、ログを出力してみます。

Terminal
docker compose up --build

実行ログが出力されれば成功です。

[Errno 48] Address already in useのようなエラーが出る場合は、ポート8000が競合しています。

ローカル実行しているuvicornを停止してください。

ここまでで、開発環境構築は完了です。

まとめ

本記事では、FastAPIを使用したWebアプリケーションのバックエンド開発環境の構築手順を紹介しました。

技術選定のポイント

今回選定した技術スタック(FastAPI、PostgreSQL、SQLModel、uv、Ruff)は、ビジネス観点と技術観点の両面でメリットがあります。

  • ビジネス観点:
    高速な開発サイクル、サービス品質の向上、コスト効率、将来的な拡張性
  • 技術観点:
    開発者体験の向上、保守性の確保、学習コストの低減、型安全性の実現

これらの技術を組み合わせることで、スタートアップから中規模プロジェクトまで幅広く対応できる、モダンで保守性の高いバックエンドシステムを構築できます。

最後に

FastAPIは学習コストが低く、Pythonの基礎知識がある初学者なら取り組みやすいフレームワークです。
一方で、本番運用に耐えうる高いパフォーマンスと拡張性も兼ね備えています。

本記事が、これからFastAPIでバックエンド開発を始める方の参考になれば幸いです。

参考

2
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?