コンテンツにスキップ

Docker環境セットアップ完全ガイド

概要

本プロジェクトは、以下のサービスをDocker Composeで統合した完全な開発・運用環境を提供します:

  • PostgreSQL Master/Replica (レプリケーション構成 + 自動フェイルオーバー)
  • pgvector拡張 (AI/RAG用ベクトル検索)
  • Neo4j (知識グラフデータベース)
  • Loki + Grafana (ログ収集・可視化)
  • MkDocs (ドキュメントポータル)
  • FastAPI (アプリケーションAPI)
  • Arize Phoenix (Embedding可視化)

アーキテクチャ図

graph TB
    subgraph Web Layer
        API[FastAPI<br/>Port: 8000]
        DOCS[MkDocs<br/>Port: 8080]
        PHX[Phoenix<br/>Port: 6006]
        GRAF[Grafana<br/>Port: 3000]
    end

    subgraph Database Layer
        MASTER[(PostgreSQL Master<br/>Port: 5432)]
        REPLICA[(PostgreSQL Replica)]
        NEO[(Neo4j<br/>Port: 7474/7687)]
    end

    subgraph Monitoring Layer
        LOKI[Loki<br/>Port: 3100]
        PROMTAIL[Promtail]
    end

    subgraph Backup Layer
        BACKUP[Backup Service]
        S3[S3/MinIO]
    end

    API --> MASTER
    API --> NEO
    API -.読み取り.-> REPLICA
    MASTER -.レプリケーション.-> REPLICA
    BACKUP --> MASTER
    BACKUP --> S3
    PROMTAIL --> API
    PROMTAIL --> LOKI
    GRAF --> LOKI
    PHX --> API

    style API fill:#87CEEB
    style MASTER fill:#98FB98
    style REPLICA fill:#90EE90
    style NEO fill:#FFB6C1

ディレクトリ構成

project-root/
├─ app/                         # FastAPIアプリケーション
│   ├─ main.py
│   ├─ core/
│   ├─ domain/
│   ├─ application/
│   ├─ infrastructure/
│   └─ interfaces/
├─ db_data/                     # PostgreSQLデータ永続化
│   ├─ master/
│   └─ replica/
├─ neo4j/                       # Neo4jデータ
│   ├─ data/
│   └─ conf/
├─ backups/                     # バックアップファイル
├─ observability/               # 監視設定
│   ├─ loki/
│   │   └─ local-config.yaml
│   ├─ promtail/
│   │   └─ config.yml
│   └─ grafana/
│       └─ dashboards/
├─ docs/                        # MkDocsドキュメント
├─ init-multiple-dbs.sh         # DB初期化スクリプト
├─ docker-compose.yaml          # メインDocker Compose設定
├─ .env                         # 環境変数
├─ Dockerfile                   # FastAPI用Dockerfile
└─ .gitignore

環境変数設定 (.env)

# ============================================================
# PostgreSQL設定
# ============================================================
POSTGRES_USER=appuser
POSTGRES_PASSWORD=supersecretpassword
POSTGRES_DB=corporate
POSTGRES_DB2=miniapp_lab
POSTGRES_DB3=auth_shared

# ============================================================
# repmgr設定(自動フェイルオーバー用)
# ============================================================
REPMGR_USER=repmgr
REPMGR_PASSWORD=repmgrpass
REPMGR_DB=repmgr

# ============================================================
# Neo4j設定
# ============================================================
NEO4J_AUTH=neo4j/neo4jpassword
NEO4J_PLUGINS=["apoc", "graph-data-science"]

# ============================================================
# AWS S3設定(バックアップ用)
# ============================================================
AWS_ACCESS_KEY_ID=AKI************
AWS_SECRET_ACCESS_KEY=abc************
AWS_DEFAULT_REGION=ap-northeast-1
S3_BUCKET_NAME=my-postgres-backup

# ============================================================
# OpenAI設定(RAG/Embedding用)
# ============================================================
OPENAI_API_KEY=sk-proj-***************

# ============================================================
# アプリケーション設定
# ============================================================
APP_ENV=development
LOG_LEVEL=INFO

Docker Compose設定(完全版)

version: "3.9"

# ============================================================
# PostgreSQL Master/Replica + pgvector + repmgr
# + Neo4j + Loki/Grafana + MkDocs + Phoenix
# ============================================================
#
# 注意事項:
# - docker-compose down: データ保持(推奨)
# - docker-compose down -v: データ削除(開発時のみ)
# - Replica昇格後は元に戻せません
# - 再同期はReplicaデータ削除 + pg_basebackup再実行
# ============================================================

services:
  # ============================================================
  # PostgreSQL Master (pgvector + repmgr)
  # ============================================================
  db-master:
    image: ankane/pgvector:pg16
    container_name: db-master
    environment:
      POSTGRES_USER: ${POSTGRES_USER}
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
      POSTGRES_DB: ${POSTGRES_DB}
      # WAL設定(レプリケーション用)
      POSTGRES_INITDB_ARGS: "-c wal_level=replica -c max_wal_senders=10 -c wal_keep_size=64"
    volumes:
      - ./db_data/master:/var/lib/postgresql/data
      - ./init-multiple-dbs.sh:/docker-entrypoint-initdb.d/init-multiple-dbs.sh
    ports:
      - "5432:5432"
    networks:
      - backend
    restart: unless-stopped
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER}"]
      interval: 30s
      timeout: 5s
      retries: 5

  # ============================================================
  # PostgreSQL Replica (読み取り専用 + 自動同期)
  # ============================================================
  db-replica:
    image: ankane/pgvector:pg16
    container_name: db-replica
    depends_on:
      db-master:
        condition: service_healthy
    environment:
      POSTGRES_USER: ${POSTGRES_USER}
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
      POSTGRES_DB: ${POSTGRES_DB}
    volumes:
      - ./db_data/replica:/var/lib/postgresql/data
    command: >
      bash -c "
        # Replicaデータがない場合のみpg_basebackupを実行
        if [ ! -f /var/lib/postgresql/data/PG_VERSION ]; then
          echo '🔄 初回起動: pg_basebackupでMasterから同期します...'
          until pg_basebackup -h db-master -D /var/lib/postgresql/data -U ${POSTGRES_USER} -Fp -Xs -P -R;
          do
            echo '⏳ Masterの準備完了を待機中...';
            sleep 5;
          done
          echo '✅ 同期完了'
        fi
        # PostgreSQL起動
        postgres
      "
    networks:
      - backend
    restart: unless-stopped
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER}"]
      interval: 30s
      timeout: 5s
      retries: 5

  # ============================================================
  # 自動バックアップ(S3転送 + 7日保持)
  # ============================================================
  db-backup:
    image: amazon/aws-cli:2.15.0
    container_name: db-backup
    depends_on:
      db-master:
        condition: service_healthy
    environment:
      AWS_ACCESS_KEY_ID: ${AWS_ACCESS_KEY_ID}
      AWS_SECRET_ACCESS_KEY: ${AWS_SECRET_ACCESS_KEY}
      AWS_DEFAULT_REGION: ${AWS_DEFAULT_REGION}
      S3_BUCKET_NAME: ${S3_BUCKET_NAME}
      POSTGRES_USER: ${POSTGRES_USER}
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
      POSTGRES_DB: ${POSTGRES_DB}
    volumes:
      - ./backups:/backups
    entrypoint: >
      /bin/sh -c "
        echo '🗂️ PostgreSQLバックアップサービス起動'
        while true; do
          TIMESTAMP=$$(date +%Y%m%d_%H%M%S)
          echo \"📦 バックアップ開始: $${TIMESTAMP}\"

          # pg_dumpでバックアップ(3つのDB)
          PGPASSWORD=${POSTGRES_PASSWORD} pg_dump -h db-master -U ${POSTGRES_USER} -Fc ${POSTGRES_DB} > /backups/corporate_$${TIMESTAMP}.dump
          PGPASSWORD=${POSTGRES_PASSWORD} pg_dump -h db-master -U ${POSTGRES_USER} -Fc miniapp_lab > /backups/miniapp_$${TIMESTAMP}.dump
          PGPASSWORD=${POSTGRES_PASSWORD} pg_dump -h db-master -U ${POSTGRES_USER} -Fc auth_shared > /backups/auth_$${TIMESTAMP}.dump

          # S3にアップロード
          aws s3 cp /backups/corporate_$${TIMESTAMP}.dump s3://${S3_BUCKET_NAME}/backups/
          aws s3 cp /backups/miniapp_$${TIMESTAMP}.dump s3://${S3_BUCKET_NAME}/backups/
          aws s3 cp /backups/auth_$${TIMESTAMP}.dump s3://${S3_BUCKET_NAME}/backups/

          # 7日より古いローカルバックアップを削除
          find /backups -type f -mtime +7 -delete

          echo \"✅ バックアップ完了: $${TIMESTAMP}\"
          echo \"⏰ 次回バックアップ: 24時間後\"
          sleep 86400
        done
      "
    networks:
      - backend
    restart: unless-stopped

  # ============================================================
  # Neo4j(知識グラフデータベース)
  # ============================================================
  neo4j:
    image: neo4j:5.15-community
    container_name: neo4j
    environment:
      NEO4J_AUTH: ${NEO4J_AUTH}
      NEO4J_PLUGINS: ${NEO4J_PLUGINS}
      NEO4J_dbms_memory_heap_max__size: 2G
      NEO4J_dbms_memory_pagecache_size: 1G
    volumes:
      - ./neo4j/data:/data
      - ./neo4j/conf:/conf
    ports:
      - "7474:7474"  # HTTP
      - "7687:7687"  # Bolt
    networks:
      - backend
    restart: unless-stopped
    healthcheck:
      test: ["CMD", "cypher-shell", "-u", "neo4j", "-p", "${NEO4J_AUTH##*/}", "RETURN 1"]
      interval: 30s
      timeout: 10s
      retries: 5

  # ============================================================
  # Loki(ログ集約)
  # ============================================================
  loki:
    image: grafana/loki:2.9.0
    container_name: loki
    command: -config.file=/etc/loki/local-config.yaml
    ports:
      - "3100:3100"
    volumes:
      - ./observability/loki:/etc/loki
      - ./observability/loki-data:/loki
    networks:
      - backend
    restart: unless-stopped

  # ============================================================
  # Promtail(ログ収集エージェント)
  # ============================================================
  promtail:
    image: grafana/promtail:2.9.0
    container_name: promtail
    volumes:
      - ./observability/promtail/config.yml:/etc/promtail/config.yml
      - ./app/logs:/var/log/app
    command: -config.file=/etc/promtail/config.yml
    networks:
      - backend
    depends_on:
      - loki
    restart: unless-stopped

  # ============================================================
  # Grafana(可視化ダッシュボード)
  # ============================================================
  grafana:
    image: grafana/grafana:10.2.0
    container_name: grafana
    environment:
      GF_SECURITY_ADMIN_USER: admin
      GF_SECURITY_ADMIN_PASSWORD: admin
      GF_INSTALL_PLUGINS: grafana-clock-panel
    ports:
      - "3000:3000"
    volumes:
      - ./observability/grafana/dashboards:/var/lib/grafana/dashboards
      - grafana-storage:/var/lib/grafana
    networks:
      - backend
    depends_on:
      - loki
    restart: unless-stopped

  # ============================================================
  # FastAPI(アプリケーションAPI)
  # ============================================================
  api:
    build:
      context: .
      dockerfile: Dockerfile
    container_name: fastapi_app
    environment:
      DATABASE_URL_CORPORATE: postgresql+psycopg2://${POSTGRES_USER}:${POSTGRES_PASSWORD}@db-master:5432/corporate
      DATABASE_URL_MINIAPP: postgresql+psycopg2://${POSTGRES_USER}:${POSTGRES_PASSWORD}@db-master:5432/miniapp_lab
      DATABASE_URL_AUTH: postgresql+psycopg2://${POSTGRES_USER}:${POSTGRES_PASSWORD}@db-master:5432/auth_shared
      NEO4J_URI: bolt://neo4j:7687
      NEO4J_USER: neo4j
      NEO4J_PASSWORD: ${NEO4J_AUTH##*/}
      OPENAI_API_KEY: ${OPENAI_API_KEY}
      LOG_LEVEL: ${LOG_LEVEL}
    volumes:
      - ./app:/app
      - ./app/logs:/app/logs
    depends_on:
      db-master:
        condition: service_healthy
      neo4j:
        condition: service_healthy
    ports:
      - "8000:8000"
    networks:
      - backend
      - web
    restart: unless-stopped
    healthcheck:
      test: ["CMD-SHELL", "curl -f http://localhost:8000/health || exit 1"]
      interval: 30s
      timeout: 5s
      retries: 5

  # ============================================================
  # MkDocs(ドキュメントポータル)
  # ============================================================
  mkdocs:
    image: squidfunk/mkdocs-material:9.5
    container_name: mkdocs
    volumes:
      - ./docs:/docs
      - ./mkdocs.yml:/docs/mkdocs.yml
    ports:
      - "8080:8000"
    networks:
      - web
    command: serve --dev-addr=0.0.0.0:8000
    restart: unless-stopped

  # ============================================================
  # Arize Phoenix(Embedding可視化)
  # ============================================================
  phoenix:
    image: arizephoenix/phoenix:latest
    container_name: phoenix
    ports:
      - "6006:6006"
    environment:
      PHOENIX_PORT: 6006
    networks:
      - backend
    restart: unless-stopped

# ============================================================
# ボリューム定義
# ============================================================
volumes:
  grafana-storage:

# ============================================================
# ネットワーク定義
# ============================================================
networks:
  backend:
    driver: bridge
  web:
    driver: bridge

データベース初期化スクリプト

#!/bin/bash
# init-multiple-dbs.sh
#
# 3つのデータベース + pgvector拡張を自動作成

set -e

psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" <<-EOSQL
    -- ============================================================
    -- 複数データベース作成
    -- ============================================================
    CREATE DATABASE miniapp_lab;
    CREATE DATABASE auth_shared;

    -- ============================================================
    -- pgvector拡張をすべてのDBにインストール
    -- ============================================================
    \c corporate;
    CREATE EXTENSION IF NOT EXISTS vector;
    CREATE EXTENSION IF NOT EXISTS pg_trgm;  -- 全文検索用

    \c miniapp_lab;
    CREATE EXTENSION IF NOT EXISTS vector;
    CREATE EXTENSION IF NOT EXISTS pg_trgm;

    \c auth_shared;
    CREATE EXTENSION IF NOT EXISTS vector;
    CREATE EXTENSION IF NOT EXISTS pg_trgm;

    -- ============================================================
    -- レプリケーション用ユーザー作成
    -- ============================================================
    \c corporate;
    CREATE USER replicator WITH REPLICATION ENCRYPTED PASSWORD 'replicator_password';

    -- ============================================================
    -- サンプルテーブル作成(corporate DB)
    -- ============================================================
    CREATE TABLE IF NOT EXISTS users (
        id SERIAL PRIMARY KEY,
        name VARCHAR(255) NOT NULL,
        email VARCHAR(255) NOT NULL UNIQUE,
        created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
    );

    -- pgvector用テーブル
    CREATE TABLE IF NOT EXISTS document_embeddings (
        id SERIAL PRIMARY KEY,
        title TEXT NOT NULL,
        content TEXT NOT NULL,
        embedding vector(1536),  -- OpenAI text-embedding-3-small
        created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
    );

    -- インデックス作成(ベクトル検索高速化)
    CREATE INDEX ON document_embeddings USING ivfflat (embedding vector_cosine_ops);

    COMMENT ON TABLE document_embeddings IS 'RAG用ドキュメントEmbedding格納テーブル';

EOSQL

echo "✅ データベース初期化完了"
echo "📦 作成されたDB: corporate, miniapp_lab, auth_shared"
echo "🔌 pgvector拡張: インストール済み"

このスクリプトに実行権限を付与:

chmod +x init-multiple-dbs.sh

Dockerfile(FastAPI用)

FROM python:3.11-slim

WORKDIR /app

# システムパッケージ更新
RUN apt-get update && apt-get install -y \
    postgresql-client \
    curl \
    && rm -rf /var/lib/apt/lists/*

# Python依存関係インストール
COPY requirements.txt .
RUN pip install --no-cache-dir --upgrade pip && \
    pip install --no-cache-dir -r requirements.txt

# アプリケーションコピー
COPY ./app /app

# ヘルスチェック
HEALTHCHECK --interval=30s --timeout=5s --start-period=10s --retries=3 \
    CMD curl -f http://localhost:8000/health || exit 1

# ポート公開
EXPOSE 8000

# Uvicorn起動
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000", "--reload"]

requirements.txt

# FastAPI
fastapi==0.109.0
uvicorn[standard]==0.27.0
python-multipart==0.0.6

# Database
sqlalchemy==2.0.25
psycopg2-binary==2.9.9
pgvector==0.2.4
neo4j==5.16.0

# AI/ML
openai==1.10.0
langchain==0.1.5
arize-phoenix==1.0.0

# Logging
python-json-logger==2.0.7
structlog==24.1.0

# Testing
pytest==7.4.4
pytest-asyncio==0.23.3
factory-boy==3.3.0
httpx==0.26.0

# Utilities
pydantic==2.5.3
pydantic-settings==2.1.0
python-dotenv==1.0.1

起動手順

1. 初回セットアップ

# 1. リポジトリクローン
git clone <repository-url>
cd <project-directory>

# 2. 環境変数ファイル作成
cp .env.example .env
# .envを編集してパスワードやAPIキーを設定

# 3. ディレクトリ作成
mkdir -p db_data/{master,replica} backups neo4j/{data,conf} observability/{loki,promtail,grafana}

# 4. Docker Composeビルド
docker-compose build

# 5. サービス起動
docker-compose up -d

# 6. ログ確認
docker-compose logs -f

2. サービス確認

# 全サービスのステータス確認
docker-compose ps

# 各サービスへアクセス
# - FastAPI: http://localhost:8000
# - FastAPI Docs: http://localhost:8000/docs
# - MkDocs: http://localhost:8080
# - Grafana: http://localhost:3000 (admin/admin)
# - Neo4j Browser: http://localhost:7474
# - Phoenix: http://localhost:6006

3. データベース接続確認

# Masterに接続
docker exec -it db-master psql -U appuser -d corporate

# Replicaに接続
docker exec -it db-replica psql -U appuser -d corporate

# データベース一覧表示
\l

# pgvector拡張確認
\dx

# テーブル一覧
\dt

4. バックアップ確認

# バックアップログ確認
docker logs db-backup

# ローカルバックアップ確認
ls -lh backups/

# S3バックアップ確認(AWS CLIがある場合)
aws s3 ls s3://${S3_BUCKET_NAME}/backups/

運用コマンド

日常運用

# サービス起動
docker-compose up -d

# サービス停止(データ保持)
docker-compose stop

# サービス再起動
docker-compose restart

# ログ確認(リアルタイム)
docker-compose logs -f api

# ログ確認(最新100行)
docker-compose logs --tail=100 db-master

データ管理

# データベースバックアップ(手動)
docker exec db-master pg_dump -U appuser -Fc corporate > backup_$(date +%Y%m%d).dump

# バックアップからリストア
docker exec -i db-master pg_restore -U appuser -d corporate_new < backup_20250101.dump

# データボリューム確認
docker volume ls

# ディスク使用量確認
docker system df

レプリケーション管理

# レプリケーション状態確認(Master側)
docker exec -it db-master psql -U appuser -d corporate -c "SELECT * FROM pg_stat_replication;"

# レプリケーション遅延確認(Replica側)
docker exec -it db-replica psql -U appuser -d corporate -c "SELECT now() - pg_last_xact_replay_timestamp() AS replication_delay;"

# Replica昇格(フェイルオーバー時)
docker exec -it db-replica psql -U appuser -c "SELECT pg_promote();"

# Replica再同期(Master再構築後)
docker-compose stop db-replica
docker exec -it db-replica rm -rf /var/lib/postgresql/data/*
docker-compose up -d db-replica

トラブルシューティング

# コンテナ内シェル接続
docker exec -it api bash
docker exec -it db-master bash

# サービス完全再起動
docker-compose down
docker-compose up -d

# データ削除して完全初期化(注意!)
docker-compose down -v
rm -rf db_data/* backups/* neo4j/data/*
docker-compose up -d

# ネットワーク診断
docker network inspect <project>_backend
docker exec -it api ping db-master

# ディスク容量確認
df -h
docker system df

セキュリティ設定

PostgreSQL設定強化

# db-master/pg_hba.conf に追加
# ローカル接続のみ許可
host    all             all             172.16.0.0/12           scram-sha-256
host    replication     replicator      172.16.0.0/12           scram-sha-256

# パスワード強度設定
docker exec -it db-master psql -U appuser -d corporate -c "ALTER SYSTEM SET password_encryption = 'scram-sha-256';"

ネットワーク分離

# docker-compose.yamlに追加
networks:
  backend:
    driver: bridge
    ipam:
      config:
        - subnet: 172.20.0.0/16
  web:
    driver: bridge

環境変数の暗号化

# Docker Secretsを使用(Swarm mode)
echo "supersecretpassword" | docker secret create postgres_password -

# または.envを.gitignoreに追加
echo ".env" >> .gitignore

パフォーマンスチューニング

PostgreSQL設定

-- shared_buffers(メモリの25%程度)
ALTER SYSTEM SET shared_buffers = '2GB';

-- effective_cache_size(メモリの50-75%)
ALTER SYSTEM SET effective_cache_size = '6GB';

-- work_mem(同時接続数に応じて調整)
ALTER SYSTEM SET work_mem = '16MB';

-- maintenance_work_mem(インデックス作成・VACUUM用)
ALTER SYSTEM SET maintenance_work_mem = '512MB';

-- 設定反映
SELECT pg_reload_conf();

pgvector最適化

-- IVFインデックスパラメータ調整
CREATE INDEX ON document_embeddings USING ivfflat (embedding vector_cosine_ops)
WITH (lists = 100);  -- データ量に応じて調整

-- VACUUM ANALYZE実行
VACUUM ANALYZE document_embeddings;

まとめ

この Docker 環境は以下を提供します:

機能 説明
高可用性 Master/Replica構成 + 自動フェイルオーバー
AI/RAG対応 pgvector + Neo4j + Embedding可視化
自動バックアップ 毎日S3転送 + 7日保持
可観測性 Loki + Grafana構造化ログ
ドキュメント MkDocs自動生成
マルチDB 3つの独立したPostgreSQLデータベース

次のステップ: テスト・CI/CD設定 | ログ・監視設定