Docker構成(DBのみ)

AIコンポーネント(Ollama・FastAPI・Frontend)はホストで直接起動する。 DockerはDBの管理・永続化にのみ使用する。

環境別docker-compose対応表

ファイル用途DBポートChromaDBポートボリューム
docker-compose.yml開発環境54328001named volume(永続化)
docker-compose.test.ymlテスト環境54338002tmpfs(使い捨て・高速)
docker-compose.prod.yml本番環境54328001named volume(永続化)
# docker-compose.yml(PostgreSQL・ChromaDBのみ・開発環境)
#
# ホスト環境: Mac Studio M4 Max 16コアCPU / 40コアGPU / 48GB / 1TB
# Docker Desktop メモリ割り当て推奨: 6〜8GB(DBのみ起動のため)
# AI コンポーネント(Ollama / FastAPI / Frontend)はホスト直接起動
#   → Metal GPU(gemma3:27b: 30〜40 tok/s)・Metal MPS(Embedding / Reranker)を使用

services:
  postgres:
    image: postgres:16-alpine
    environment:
      POSTGRES_DB: ${POSTGRES_DB}
      POSTGRES_USER: ${POSTGRES_USER}
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
    # Mac Studio 48GB 環境向け PostgreSQL チューニング
    command: >
      postgres
        -c shared_buffers=512MB
        -c effective_cache_size=2GB
        -c work_mem=16MB
        -c max_connections=20
    volumes:
      - postgres_data:/var/lib/postgresql/data  # named volume 必須(bind mountはI/O 10〜30倍遅化)
    shm_size: '256m'                             # shared_buffers に必要な共有メモリ領域
    ports:
      - "5432:5432"
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER}"]
      interval: 10s
      timeout: 5s
      retries: 5
    restart: unless-stopped

  chromadb:
    image: chromadb/chroma:latest
    volumes:
      - chromadb_data:/chroma/data             # named volume 必須
    ports:
      - "8001:8001"
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:8001/api/v1/heartbeat"]
      interval: 10s
      timeout: 5s
      retries: 5
    restart: unless-stopped

volumes:
  postgres_data:    # ホストのDocker named volumeに保存(NASには置かない)
  chromadb_data:
# docker-compose.test.yml(テスト用・開発環境と別ポート・tmpfsで使い捨て)
services:
  postgres-test:
    image: postgres:16-alpine
    environment:
      POSTGRES_DB: company_rag_test
      POSTGRES_USER: raguser
      POSTGRES_PASSWORD: test_password   # テスト専用・固定値でよい
    ports:
      - "5433:5432"                      # 開発環境の5432と衝突しない
    tmpfs:
      - /var/lib/postgresql/data         # tmpfs使用(永続化不要・高速・テスト後消える)
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U raguser"]
      interval: 5s
      timeout: 3s
      retries: 5

  chromadb-test:
    image: chromadb/chroma:latest
    ports:
      - "8002:8001"                      # 開発環境の8001と衝突しない
    tmpfs:
      - /chroma/data                     # tmpfs使用(永続化不要)
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:8001/api/v1/heartbeat"]
      # コンテナ内部ポートは8001(ホスト側は8002にマッピング・ヘルスチェックは内部から実行のため8001を使用)
      interval: 5s
      timeout: 3s
      retries: 5

# volumesブロックなし(tmpfsを使用するため named volume 不要)

ホスト起動スクリプト(scripts/start-dev.sh

#!/bin/bash
set -e

# 1. DockerでDB起動
docker-compose up -d

# 2. Ollamaをホスト起動(すでに起動中の場合はスキップ)
if ! pgrep -x "ollama" > /dev/null; then
  ollama serve &
  echo "Ollama started"
else
  echo "Ollama already running"
fi

# 3. FastAPIをホスト起動(仮想環境アクティベート後)
cd backend
source .venv/bin/activate  # or: source venv/bin/activate
uvicorn app.main:app --reload --host 0.0.0.0 --port 8000 &

# 4. Frontend起動の案内(別ターミナル推奨)
echo ""
echo "=== 別ターミナルで以下を実行してください ==="
echo "cd frontend && npm run dev"

テスト起動スクリプト(scripts/start-test.sh

#!/bin/bash
set -e

# 1. テスト用DBを起動(開発DBとは別ポート・tmpfsで使い捨て)
docker-compose -f docker-compose.test.yml up -d

# 2. DBのヘルスチェックが通るまで待機
echo "Waiting for test DB to be ready..."
until docker-compose -f docker-compose.test.yml exec -T postgres-test pg_isready -U raguser; do
  sleep 1
done

# 3. テスト用DBにAlembicマイグレーションを適用
cd backend
source .venv/bin/activate
DATABASE_URL=postgresql://raguser:test_password@localhost:5433/company_rag_test \
  alembic upgrade head

# 4. pytestを実行(.env.testを使用)
pytest tests/ -v --cov=app --cov-report=term-missing

# 5. テスト用DBを停止・削除(tmpfsなので自動的にデータは消える)
cd ..
docker-compose -f docker-compose.test.yml down

本番用 (docker-compose.prod.yml) の追加事項:

  • Frontend: Nginx で静的ビルドを配信 + セキュリティヘッダー設定(docker-compose.prod.yml 内の Nginx サービスとして Docker 管理を推奨docker-compose up 一発起動と整合するため。ホスト直接起動も可だが管理が煩雑になる)
  • Backend: Gunicorn + Uvicorn workers(2〜4 workers推奨、ホスト直接起動)
  • 全Dockerサービスにヘルスチェック設定
  • restart: unless-stopped 全Dockerサービスに設定
  • バックアップ用コンテナ(定期的にpg_dump + ChromaDBデータをローカルボリュームへ)

Nginxセキュリティヘッダー(本番必須):

add_header X-Frame-Options "DENY";
add_header X-Content-Type-Options "nosniff";
add_header Content-Security-Policy "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; object-src 'none'";
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;

※ Mermaid.jsがSVGをインライン生成するため、CSPのscript-srcstyle-srcは実装確認後に調整が必要


環境変数一覧

環境別ファイル対応

ファイルGit管理用途
.env.example○(雛形)全変数の説明・空値の雛形
.env.test○(秘匿情報なし)テスト環境のデフォルト値(テスト用DB接続先・固定SECRET_KEY)
.env✗(.gitignore開発環境の実際の値
.env.production✗(.gitignore本番環境の値

.env(開発環境)

# 環境識別(development 環境では CORS_ALLOWED_ORIGINS に "http://localhost:3000" またはワイルドカード "*" を設定可能)
ENVIRONMENT=development

# Database(ホスト直接起動のためlocalhost)
POSTGRES_DB=company_rag
POSTGRES_USER=raguser
POSTGRES_PASSWORD=           # 必須・空白禁止(起動時チェックあり)
DATABASE_URL=postgresql://raguser:@localhost:5432/company_rag

# Auth
SECRET_KEY=                  # 必須・32文字以上・起動時に強度チェックあり
ALGORITHM=HS256
ACCESS_TOKEN_EXPIRE_MINUTES=60
REFRESH_TOKEN_EXPIRE_DAYS=7

# CORS(本番は実際のドメインを指定・"*"は開発環境のみ)
CORS_ALLOWED_ORIGINS=http://localhost:3000

# Ollama(ホスト直接起動)
OLLAMA_BASE_URL=http://localhost:11434
OLLAMA_MODEL=gemma3:27b
OLLAMA_TIMEOUT_SECONDS=120

# Embedding(バージョン固定でベクトル空間の変動を防ぐ)
EMBEDDING_MODEL=intfloat/multilingual-e5-large
EMBEDDING_MODEL_REVISION=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx  # 固定コミットハッシュ

# ChromaDB(ホスト直接起動のためlocalhost)
CHROMA_HOST=localhost
CHROMA_PORT=8001
CHROMA_COLLECTION=company_documents

# File Storage(ホスト直接起動のため絶対パス or 相対パス)
UPLOAD_DIR=./uploads
MAX_UPLOAD_SIZE_MB=50
ALLOWED_EXTENSIONS=.pdf,.docx,.xlsx,.txt

# Hugging Face キャッシュ(ホストの ~/.cache/huggingface を使用)
HF_HOME=~/.cache/huggingface

# PyTorch MPS(Metal Performance Shaders)設定
# MPS非対応演算をCPUにフォールバックさせる(macOS必須)
PYTORCH_ENABLE_MPS_FALLBACK=1

# Rate Limiting(POST /chat)
CHAT_RATE_LIMIT_PER_MINUTE=10

# Frontend
VITE_API_BASE_URL=http://localhost:8000

.env.test(テスト環境・git管理可)

# テスト環境識別
ENVIRONMENT=test

# テスト用DB(docker-compose.test.ymlと対応・開発DBとは別)
POSTGRES_DB=company_rag_test
POSTGRES_USER=raguser
POSTGRES_PASSWORD=test_password
DATABASE_URL=postgresql://raguser:test_password@localhost:5433/company_rag_test

# Auth(テスト用固定値・強度チェックはskip)
SECRET_KEY=test-secret-key-for-testing-only-do-not-use-in-production
ALGORITHM=HS256
ACCESS_TOKEN_EXPIRE_MINUTES=60
REFRESH_TOKEN_EXPIRE_DAYS=7

# CORS(テスト時はテストクライアントのみ)
CORS_ALLOWED_ORIGINS=http://localhost:3000

# Ollama(テストではモックするため実際には使用しない)
OLLAMA_BASE_URL=http://localhost:11434
OLLAMA_MODEL=gemma3:27b
OLLAMA_TIMEOUT_SECONDS=10

# Embedding(テストではモックするため実際には使用しない)
EMBEDDING_MODEL=intfloat/multilingual-e5-large
EMBEDDING_MODEL_REVISION=

# ChromaDB(テスト用・docker-compose.test.ymlの8002ポートと対応)
CHROMA_HOST=localhost
CHROMA_PORT=8002
CHROMA_COLLECTION=company_documents_test

# File Storage(テスト用一時ディレクトリ)
UPLOAD_DIR=./test_uploads
MAX_UPLOAD_SIZE_MB=50
ALLOWED_EXTENSIONS=.pdf,.docx,.xlsx,.txt

# Rate Limiting(テストでは緩く設定)
CHAT_RATE_LIMIT_PER_MINUTE=1000

# Frontend
VITE_API_BASE_URL=http://localhost:8000

起動時バリデーション(config.py):

  • SECRET_KEY が空・32文字未満・your-super-secret を含む場合は起動を拒否
    • 例外: ENVIRONMENT=test の場合はこのチェックをスキップ(テスト用固定キーを許容)
  • POSTGRES_PASSWORD が空の場合は起動を拒否
    • 例外: ENVIRONMENT=test の場合はスキップ
  • CORS_ALLOWED_ORIGINS* かつ ENVIRONMENT=production の場合は起動を拒否