🦓

FastAPIとNext.jsとPostgreSQLをDevContainerで環境構築する

2024/09/15に公開

はじめに

FastAPI、Next.js、PostgreSQLを使用した環境をDevContainerで構築してみました。

ツール

最低限のツールをインストールする必要があります。

  1. VsCode
    ・Dev Containers拡張機能
    ・Docker拡張機能
  2. Docker Desktop
Dev Containers拡張機能

Dev Containers拡張機能にはDev Containers.Add Dev Container Configuration Files... コマンドがあります。コマンドを実行し、リストからコンテナテンプレート設定を選ぶことができます。
devcontainer.jsonDockerfileを一から作成し、ビルドするよりも、すぐに完全な開発用コンテナを用意したい場合は、開発用コンテナ作成の自動化までできます。

DevContainer

DevContainerは、VSCodの機能の1つで、開発環境を標準化し、簡単に共有できるようにするための機能です。
DevContainerを使用すると、プロジェクトに必要なツール、ライブラリ、ランタイムを含む完全な開発環境をDockerコンテナ内に定義できます。プロジェクトの開発者が同じ環境で作業できるようになります。
プロジェクトに適した特定のVSCode拡張機能、設定、環境変数などを定義できます。これらの設定は.devcontainerフォルダ内のファイルで管理されます。
GitHub CodespacesなどのクラウドベースのIDEと組み合わせることで、ブラウザだけで完全な開発環境にアクセスすることも可能です。

https://code.visualstudio.com/docs/devcontainers/containers
https://code.visualstudio.com/docs/devcontainers/create-dev-container

tl;dr

  1. DevContainerによる環境を設定する
  2. FastAPIアプリを作成する
  3. Next.jsアプリを作成する
  4. DevContainer内にプロジェクトを立ち上げる

プロジェクトの構造

簡単ですが、以下のような構造を持つアプリを作成します。

root/
├── .devcontainer/
│   ├── devcontainer.json
│   └── Dockerfile
│   └── docker-compose.yml
│   └── post-create.sh
├── backend/
│   ├── app/
│   │   └── main.py
│   └── requirements.txt
├── frontend/
│   └── Next.js関連のファイル
└── .gitignore

.devcontainer/devcontainer.jsonを作成する

新しいプロジェクトフォルダを作成し、VSCodeで開きます。
ルートに.devcontainerフォルダを作成し、その中にdevcontainer.jsonファイルを作成します。
devコンテナのコンフィグは、.devcontainer/devcontainer.jsonの下に配置されるか、プロジェクトのルートに.devcontainer.jsonファイル(ドット接頭辞に注意)として保存されます。
devcontainer.json内にVS Codeがどのようにコンテナを起動し、接続後に何をすべきかを記述します。

.devcontainer/devcontainer.json
{
    // プロジェクト名
    "name": "FastAPIとNext.jsとPostgreSQLを使ったアプリ",
    // docker-compose.ymlのパスを指定
    "dockerComposeFile": "docker-compose.yml",
    // devcontainerで使用するサービス名
    "service": "app",
    // サービスコンテナのworkspaceフォルダー
    "workspaceFolder": "/workspace",
    // ポート番号
    "forwardPorts": [3000, 8000, 5432],
    // devcontainerとして開くvscode側の設定カスタマイズ
    "customizations": {
        "vscode": {
            "extensions": [
                "ms-python.python",
                "ms-python.vscode-pylance",
                "ms-python.black-formatter",
                "ms-python.debugpy",
                "dbaeumer.vscode-eslint",
                "esbenp.prettier-vscode"
            ]
        },
        "settings": {
            "python.linting.enabled": true,
            "python.linting.pylintEnabled": true
        }
    },
    // コンテナ内の実行ユーザーの設定
    "remoteUser": "vscode",
    // devcontainer起動時に実行するコマンド
    "postCreateCommand": "postCreateCommand": "bash .devcontainer/post-create.sh"
}

devcontainer.jsonの公式リファレンス:
https://containers.dev/implementors/json_reference/
python-3-postgresDevContainer公式サンプル:
https://github.com/microsoft/vscode-dev-containers/blob/v0.245.2/containers/python-3-postgres/.devcontainer/devcontainer.json

.devcontainer/post-create.shを作成する

コンテナが作成された後実行するスクリプトを指定します。

.devcontainer/post-create.sh
#!/bin/bash

set -e

log_message() {
    echo "$(date '+%Y-%m-%d %H:%M:%S') - $1"
}

handle_error() {
    log_message "Error occurred in line $1"
    exit 1
}

trap 'handle_error $LINENO' ERR

log_message "Starting post-create setup..."

# Backend setup
if [ -d "backend" ]; then
    log_message "Setting up backend..."
    cd backend
    if [ -f "requirements.txt" ]; then
        log_message "Installing Python dependencies..."
        pip install --user -r requirements.txt
    else
        log_message "Error: requirements.txt not found in backend directory"
        exit 1
    fi
    cd ..
else
    log_message "Error: backend directory not found"
    exit 1
fi

# Frontend setup
if [ -d "frontend" ]; then
    log_message "Setting up frontend..."
    cd frontend
    if [ -f "package.json" ]; then
        log_message "Installing Node.js dependencies..."
        npm install
    else
        log_message "Error: package.json not found in frontend directory"
        exit 1
    fi
    cd ..
else
    log_message "Error: frontend directory not found"
    exit 1
fi

log_message "Post-create setup completed successfully"

.devcontainer/Dockerfileを作成する

Dockerfileを作成します。

.devcontainer/Dockerfile
# pythonイメージ
FROM python:3.11

# 環境変数の設定
ENV PYTHONDONTWRITEBYTECODE=1
ENV PYTHONUNBUFFERED=1
ENV PATH="/root/.local/bin:$PATH"

# 依存するパッケージのインストール
RUN apt-get update \
    && apt-get install -y --no-install-recommends \
        postgresql-client \
    && apt-get clean \
    && rm -rf /var/lib/apt/lists/*

# Node.jsをインストール
RUN curl -sL https://deb.nodesource.com/setup_14.x | bash - \
    && apt-get install -y nodejs

# ディレクトリを指定
WORKDIR /workspace

python-3-postgresDevContainer公式サンプル:
https://github.com/microsoft/vscode-dev-containers/blob/v0.245.2/containers/python-3-postgres/.devcontainer/Dockerfile

.devcontainer/docker-compose.ymlを作成する

docker-compose.ymlを作成します。

.devcontainer/docker-compose.yml
version: '3.11'

services:
  app:
    build:
      context: ..
      dockerfile: .devcontainer/Dockerfile

    volumes:
      - ..:/workspace:cached  

    # Overrides default command so things don't shut down after the process ends.
    command: sleep infinity

    # Runs app on the same network as the database container, allows "forwardPorts" in devcontainer.json function.
    network_mode: service:db

    # Uncomment the next line to use a non-root user for all processes.
    user: vscode

    # Use "forwardPorts" in **devcontainer.json** to forward an app port locally.
    # (Adding the "ports" property to this file will not forward from a Codespace.)

  db:
    image: postgres:latest
    restart: unless-stopped
    volumes:
      - postgres-data:/var/lib/postgresql/data
    environment:
      POSTGRES_USER: postgres
      POSTGRES_DB: postgres
      POSTGRES_PASSWORD: postgres

    # Add "forwardPorts": ["5432"] to **devcontainer.json** to forward PostgreSQL locally.
    # (Adding the "ports" property to this file will not forward from a Codespace.)

volumes:
  postgres-data:

python-3-postgresDevContainer公式サンプル:
https://github.com/microsoft/vscode-dev-containers/blob/v0.245.2/containers/python-3-postgres/.devcontainer/docker-compose.yml

FastApiアプリを作成する

backend/requirements.txtファイルを作成し、インストールするパッケージを追加します。

backend/requirements.txt
fastapi
uvicorn
sqlalchemy
pydantic
alembic
psycopg2-binary
python-dotenv

backend/app/main.pyに簡単なFastAPIアプリケーションを作成します:

backend/app/main.py
from fastapi import FastAPI

app = FastAPI()

@app.get("/")
async def root():
    return {"message": "Hello from FastAPI"}

Next.jsアプリを作成する

こちらのコマンドを実行します。

npx create-next-app frontend

実行後、/frontend内にNext.jsプロジェクトが作成されることを確認します。

.gitignoreファイルを作成し、以下を追加します:

__pycache__/
*.pyc
.next/

DevContainer内にて環境構築

これら設定が完了したら、VSCodeでプロジェクトフォルダを開き、コマンドパレット(Ctrl+Shift+P)から「Dev Containers: Reopen in Container」を選択します。
これで、FastAPI、Next.js、PostgreSQLを含む開発環境がDevContainer内に構築されます。

また、Connecting to Dev Containerのログ内にビルド状況を確認することができます。

環境構築に失敗した場合、「Dev Containers: Rebuild and Reopen in Container」を選択し、コンテナを立て直すことができます。

環境構築に成功したら、VSCodeの左下にDev Container名が表示されます。

指定した拡張機能がDev Container内にインストールされたことも確認できます。

Docker DesktopにDev Containerが表示されることを確認します。

Dev Container内に指定したパッケージがインストールされたことを確認します。

root@e3a333aa1237:/workspace# npm --version
10.8.3
root@e3a333aa1237:/workspace# node --version
v20.17.0
root@e3a333aa1237:/workspace# python --version
Python 3.9.20
root@e3a333aa1237:/workspace# psql --version
psql (PostgreSQL) 15.8 (Debian 15.8-0+deb12u1)

バックエンドを立ち上げる

コンテナ内のターミナルで下記のコマンドを実行します。

root@e3a333aa1237:/workspace# cd /backend && uvicorn app.main:app --host 0.0.0.0 --port 8000 --reload
INFO:     Will watch for changes in these directories: ['/workspace/backend']
INFO:     Uvicorn running on http://0.0.0.0:8000 (Press CTRL+C to quit)
INFO:     Started reloader process [3585] using StatReload
INFO:     Started server process [3587]
INFO:     Waiting for application startup.
INFO:     Application startup complete.
INFO:     127.0.0.1:53218 - "GET / HTTP/1.1" 200 OK

app/main.pyに指定したメッセージが表示されることを確認します。

フロントエンドを立ち上げる

コンテナ内の別のターミナルで下記のコマンドを実行します。

root@e3a333aa1237:/workspace# cd frontend && npm run dev

> frontend@0.1.0 dev
> next dev

  ▲ Next.js 14.2.11
  - Local:        http://localhost:3000

 ✓ Starting...
Attention: Next.js now collects completely anonymous telemetry regarding usage.
This information is used to shape Next.js' roadmap and prioritize features.
You can learn more, including how to opt-out if you'd not like to participate in this anonymous program, by visiting the following URL:
https://nextjs.org/telemetry

 ✓ Ready in 2.7s

フロントが立ち上がったことを確認します。

終わりに

簡単ですが、FastAPI、Next.js、PostgreSQLを使用した環境をDevContainerで構築してみました。
誰かの参考になれば嬉しいです。

VercelがFastAPIとNext.jsのテンプレートを提供しています。
https://vercel.com/templates/next.js/nextjs-fastapi-starter
https://github.com/digitros/nextjs-fastapi

FastAPIもサンプルアプリとしてテンプレートを提供しています。
環境構築に参考できると思うのでリンクを貼ります。
https://github.com/fastapi/full-stack-fastapi-template

Discussion