はじめに
以前、Reactでのフロントエンド開発の環境構築、Python(FastAPI)でのバックエンド開発の環境構築をしました。
今回はソレらをDockerで起動して疎通してみたいという趣旨で、やったことを自分用メモとして残したいと思います。
相変わらずよわよわエンジニア御用達のWindowsを使ってます。情弱で誠にごめんなさい。
Podman Desktop
Dockerと言いつつ、今回はDocker Desktopの代替ツール(無料)として注目を集めるPodman Desktopを使用しました。
dockerコマンドのdockerをpodmanに置き換えるだけでdockerとほぼ同じコマンドが使えます。
例:podman compose up -d
ディレクトリ構成
主要人物たちは大体こんな感じ。
otameshi
├─hoge_project ※Pythonプロジェクト
│ ├─pyproject.toml
│ ├─poetry.lock
│ ├─Dockerfile
│ └─src
│ ├─自作モジュールを配置する各ディレクトリ
│ └─main.py
├─hoge_front ※Reactプロジェクト
│ ├─package.json
│ ├─package-lock.json
│ ├─Dockerfile
│ └─src
│ └─(省略)
└─docker-compose.yml
Dockerfileの作成
バックエンドの方のDockerfile
# ベースイメージとしてPythonの公式イメージを使用
FROM python:3.13.7-slim
# 作業ディレクトリを設定
WORKDIR /hoge_project
# Poetryをインストール
RUN pip install poetry
# Poetryを最新版にアップグレード
RUN poetry self update
# Poetryのパスの設定
ENV PATH /root/.local/bin:$PATH
# poetry.lock と pyproject.toml をコピーして依存関係をインストール
# これにより、依存関係が変更されない限り、キャッシュが利用される
COPY pyproject.toml poetry.lock ./
# アプリケーションのコードをコピー
COPY src ./src
# Poetryの仮想環境をコンテナのグローバルキャッシュに作成
RUN poetry config virtualenvs.create false
RUN poetry install --no-root --without dev
# main.pyが配置されている場所へ移動。これをしないと自作モジュールのimportのパスがずれてエラーになる模様。
WORKDIR /hoge_project/src
# アプリケーションを起動
# Uvicornを使ってFastAPIアプリを起動します。
CMD ["poetry", "run", "uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]
フロントエンドの方のDockerfile
# ベースイメージとしてNode.jsを使用
FROM node:24.8-alpine
# 作業ディレクトリを設定
WORKDIR /app
# 必要なファイルをコンテナにコピー
COPY package*.json ./
# 依存関係をインストール
RUN npm install
# ソースコードをコピー
COPY . .
# Viteサーバーを起動するポートを公開
EXPOSE 5173
# 開発サーバーを起動
CMD ["npm", "run", "dev"]
docker-compose.ymlの作成
version: '3.9'
services:
backend:
build:
context: ./hoge_project
dockerfile: Dockerfile
ports:
- "8000:8000"
volumes:
- ./hoge_project:/hoge_project
# ホストマシンの.venvが更新されてホストマシンでFastAPIの起動が出来なくなる事故があったのでソレを防ぐおまじない。
- /hoge_project/.venv
environment:
# 環境変数が必要な場合はここで設定
- DATABASE_URL=postgresql://user:password@db:5432/myapp
frontend:
build:
context: ./hoge_front
dockerfile: Dockerfile
ports:
- "5173:5173"
volumes:
- ./hoge_front:/app
# よその記事のコピペだけどbackendの.venv問題と同様の問題を回避するおまじないなんじゃないかと思う。
- /app/node_modules
バックエンドの修正(CORS)
CORSでエラーになったので、許可するドメインの追加をしました。
import math
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
app = FastAPI()
# 許可するオリジン(ドメイン)を指定
origins = [
"http://localhost",
"http://localhost:5173",
"http://127.0.0.1:5173",
]
app.add_middleware(
CORSMiddleware,
allow_origins=origins,
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
@app.get("/hoge")
def read_root():
return {
"message": "Hello, FastAPI with Poetry!",
"message1": "Hello, FastAPI with Poetry!",
"message2": "Hello, FastAPI with Poetry!",
"message3": "Hello, FastAPI with Poetry!",
"hogefuga": "piyo",
}
フロントエンドの修正(API呼び出し)
vite.config.ts にserverセクションを追加。
よその記事からコピペしてきたので何のおまじないなのかはわからないが、これがないとブラウザで画面の表示ができなかった。
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react-swc'
// https://vite.dev/config/
export default defineConfig({
plugins: [react()],
server: {
host: true,
port: 5173,
// ↓はDocker起動時もホットリロードが可能になるおまじないらしい。
watch: {
usePolling: true,
}
},
})
App.tsx にAPI呼び出しボタンを追加。
ボタン押下で、APIを呼び出してレスポンスされたJSONを表示する。
import { useState } from 'react';
import reactLogo from './assets/react.svg';
import viteLogo from '/vite.svg';
import './App.css';
function App() {
const [count, setCount] = useState(0);
const [data, setData] = useState(null);
const handleFetchData = async () => {
try {
// API呼び出し
const response = await fetch('http://localhost:8000/hoge');
if (!response.ok) {
throw new Error(`HTTPエラー! ステータス: ${response.status}`);
}
const jsonData = await response.json();
// 成功した場合、データをstateにセット
setData(jsonData);
} catch (e) {
} finally {
}
};
return (
<>
<div>
<a href="https://vite.dev" target="_blank">
<img src={viteLogo} className="logo" alt="Vite logo" />
</a>
<a href="https://react.dev" target="_blank">
<img src={reactLogo} className="logo react" alt="React logo" />
</a>
</div>
<h1>Vite + React</h1>
<div className="card">
<button onClick={() => setCount((count) => count + 1)}>count is {count}</button>
<p>
Edit <code>src/App.tsx</code> and save to test HMR
</p>
</div>
<p className="read-the-docs">Click on the Vite and React logos to learn more</p>
{data && (
<div>
<h2>APIからのレスポンス:</h2>
<pre>{JSON.stringify(data, null, 2)}</pre>
</div>
)}
<button onClick={handleFetchData}>APIを実行</button>
</>
);
}
export default App;
フロント-バックの疎通確認
GitBashで以下のコマンドを実行。
podman compose up
フロントエンドの修正の通り、ボタン押下でlocalhost:8000/hoge でレスポンスされたJSONを表示することに成功。
不明点
バックエンドのDockerfileで以下のように仮想環境を作る設定にするとアプリ起動時にuvicornが見つからないというエラーがでる。
原因がよくわからなかったが、falseにすると動いたのでとりあえずfalseにした。
どういうことなのか、わかる方がいたら教えてください。
RUN poetry config virtualenvs.create true
Attaching to backend-1
backend-1 | Command not found: uvicorn
backend-1 exited with code 1
Podman備忘
たまにこんなエラーが出るが、
$ podman compose up backend
Error: get machine connection URI: command C:\Users\user\AppData\Local\Microsoft\WindowsApps\wsl.exe [C:\Users\user\AppData\Local\Microsoft\WindowsApps\wsl.exe -u root -d podman-machine-default sh] failed: exit status 0xffffffff ()
WSLシャットダウンしたりPodmanを再起動すると解決することが多い。
wsl --shutdown
