Docker Composeを使ったモダンな開発環境構築ガイド

Docker Composeを活用して、フロントエンド(React)、バックエンド(Express)、データベース(PostgreSQL)を連携させた、効率的で再現性の高い開発環境を構築する手順を解説します。

docker DockerDocker Compose開発環境ReactNode.js

Docker開発環境構築

Docker Composeを使った効率的な開発環境の構築方法

基本構成

プロジェクト構造

project/
├── docker-compose.yml           # 基本設定
├── docker-compose.dev.yml       # 開発環境用
├── docker-compose.prod.yml      # 本番環境用
├── frontend/
│   ├── Dockerfile
│   ├── nginx.conf               # プロダクション用
│   └── src/
├── backend/
│   ├── Dockerfile
│   └── src/
└── database/
    └── init.sql                 # 初期化スクリプト

Docker Compose設定

基本設定(docker-compose.yml)

version: '3.8'

services:
  # PostgreSQLデータベース
  database:
    image: postgres:15
    container_name: collepoke_db
    environment:
      POSTGRES_DB: collepoke
      POSTGRES_USER: user
      POSTGRES_PASSWORD: password
    ports:
      - "5432:5432"
    volumes:
      - postgres_data:/var/lib/postgresql/data
      - ./database/init.sql:/docker-entrypoint-initdb.d/init.sql
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U user -d collepoke"]
      interval: 30s
      timeout: 10s
      retries: 3

  # バックエンドAPI
  backend:
    build:
      context: ./backend
      dockerfile: Dockerfile
    container_name: collepoke_backend
    environment:
      DB_HOST: database
      DB_PORT: 5432
      DB_NAME: collepoke
      DB_USER: user
      DB_PASSWORD: password
      NODE_ENV: production
    ports:
      - "3001:3001"
    depends_on:
      database:
        condition: service_healthy
    volumes:
      - ./backend:/app
      - /app/node_modules

  # フロントエンド
  frontend:
    build:
      context: ./frontend
      dockerfile: Dockerfile
    container_name: collepoke_frontend
    environment:
      VITE_API_URL: http://backend:3001
    ports:
      - "3002:80"
    depends_on:
      - backend

volumes:
  postgres_data:

開発環境用設定(docker-compose.dev.yml)

version: '3.8'

services:
  backend:
    environment:
      NODE_ENV: development
    volumes:
      - ./backend:/app
      - /app/node_modules
    command: npm run dev

  frontend:
    build:
      context: ./frontend
      target: development  # マルチステージビルドの開発段階
    environment:
      VITE_API_URL: http://localhost:3001  # 開発時はlocalhost
    ports:
      - "5173:5173"  # Vite開発サーバー
    volumes:
      - ./frontend:/app
      - /app/node_modules
    command: npm run dev

本番環境用設定(docker-compose.prod.yml)

version: '3.8'

services:
  backend:
    environment:
      NODE_ENV: production
    restart: always

  frontend:
    build:
      context: ./frontend
      target: production  # マルチステージビルドの本番段階
    restart: always

  database:
    restart: always
    volumes:
      - postgres_data:/var/lib/postgresql/data
      # 本番では初期化スクリプトは除外

Dockerfile設定

フロントエンド(React + Vite)

# マルチステージビルド
FROM node:18-alpine AS base
WORKDIR /app
COPY package*.json ./
RUN npm ci

# 開発段階
FROM base AS development
COPY . .
EXPOSE 5173
CMD ["npm", "run", "dev", "--", "--host", "0.0.0.0"]

# ビルド段階
FROM base AS build
COPY . .
RUN npm run build

# 本番段階
FROM nginx:alpine AS production
COPY --from=build /app/dist /usr/share/nginx/html
COPY nginx.conf /etc/nginx/conf.d/default.conf
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]

バックエンド(Express.js)

FROM node:18-alpine
WORKDIR /app

# 依存関係のインストール
COPY package*.json ./
RUN npm ci

# ソースコードのコピー
COPY . .

# TypeScriptのビルド
RUN npm run build

# アプリケーションの起動
EXPOSE 3001
CMD ["npm", "start"]

運用コマンド

開発環境

# 開発環境の起動
docker-compose -f docker-compose.yml -f docker-compose.dev.yml up

# バックグラウンド実行
docker-compose -f docker-compose.yml -f docker-compose.dev.yml up -d

# ログの確認
docker-compose logs -f [service-name]

# 特定サービスの再起動
docker-compose restart backend

# 全コンテナの停止
docker-compose down

データベースのリセット

# ボリュームも含めて完全削除
docker-compose down -v

# 再構築
docker-compose up --build

本番環境

# 本番環境での起動
docker-compose -f docker-compose.yml -f docker-compose.prod.yml up -d

# イメージの再ビルド
docker-compose -f docker-compose.yml -f docker-compose.prod.yml up --build -d

nginx設定

SPA + API用設定

server {
    listen 80;
    root /usr/share/nginx/html;
    index index.html;

    # SPA用設定(React Router対応)
    location / {
        try_files $uri $uri/ /index.html;
    }

    # API用リバースプロキシ
    location /api/ {
        proxy_pass http://backend:3001;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_connect_timeout 30s;
        proxy_send_timeout 30s;
        proxy_read_timeout 30s;
    }

    # 静的ファイルのキャッシュ設定
    location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ {
        expires 1y;
        add_header Cache-Control "public, immutable";
    }

    # gzip圧縮
    gzip on;
    gzip_vary on;
    gzip_min_length 1000;
    gzip_types
        text/plain
        text/css
        text/xml
        text/javascript
        application/xml+rss
        application/javascript
        application/json;
}

環境変数管理

.env ファイル設定

# データベース設定
POSTGRES_DB=collepoke
POSTGRES_USER=user
POSTGRES_PASSWORD=your_secure_password
DB_HOST=database
DB_PORT=5432

# バックエンド設定
NODE_ENV=development
PORT=3001
JWT_SECRET=your_jwt_secret

# フロントエンド設定
VITE_API_URL=http://localhost:3001
VITE_APP_NAME=CollePoke

docker-compose.ymlでの環境変数読み込み

services:
  database:
    environment:
      POSTGRES_DB: ${POSTGRES_DB}
      POSTGRES_USER: ${POSTGRES_USER}
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}

  backend:
    environment:
      DB_HOST: ${DB_HOST}
      DB_USER: ${POSTGRES_USER}
      DB_PASSWORD: ${POSTGRES_PASSWORD}
      DB_NAME: ${POSTGRES_DB}
      NODE_ENV: ${NODE_ENV}
      JWT_SECRET: ${JWT_SECRET}

  frontend:
    environment:
      VITE_API_URL: ${VITE_API_URL}

ボリューム管理

データの永続化

volumes:
  # PostgreSQLデータの永続化
  postgres_data:
    driver: local

  # node_modulesの効率的な管理
  frontend_node_modules:
  backend_node_modules:

services:
  frontend:
    volumes:
      - ./frontend:/app
      - frontend_node_modules:/app/node_modules  # ホストと分離

  backend:
    volumes:
      - ./backend:/app
      - backend_node_modules:/app/node_modules

開発時のホットリロード対応

services:
  frontend:
    volumes:
      - ./frontend:/app
      - /app/node_modules
    environment:
      - CHOKIDAR_USEPOLLING=true  # ファイル変更検知の改善
    ports:
      - "5173:5173"
    command: npm run dev -- --host 0.0.0.0

ヘルスチェック設定

データベースのヘルスチェック

database:
  healthcheck:
    test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER} -d ${POSTGRES_DB}"]
    interval: 30s
    timeout: 10s
    retries: 3
    start_period: 60s

バックエンドのヘルスチェック

backend:
  healthcheck:
    test: ["CMD", "curl", "-f", "http://localhost:3001/api/health"]
    interval: 30s
    timeout: 10s
    retries: 3
    start_period: 60s

セキュリティ設定

非rootユーザーでの実行

# Dockerfile
FROM node:18-alpine

# 非rootユーザーの作成
RUN addgroup -g 1001 -S nodejs
RUN adduser -S nextjs -u 1001

WORKDIR /app
COPY package*.json ./
RUN npm ci

COPY . .
RUN chown -R nextjs:nodejs /app
USER nextjs

EXPOSE 3001
CMD ["npm", "start"]

ネットワーク分離

networks:
  frontend-network:
  backend-network:
  database-network:

services:
  frontend:
    networks:
      - frontend-network

  backend:
    networks:
      - frontend-network
      - backend-network
      - database-network

  database:
    networks:
      - database-network

パフォーマンス最適化

イメージサイズの最適化

# マルチステージビルドの活用
FROM node:18-alpine AS dependencies
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production

FROM node:18-alpine AS build
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build

FROM node:18-alpine AS runtime
WORKDIR /app
COPY --from=dependencies /app/node_modules ./node_modules
COPY --from=build /app/dist ./dist
COPY package*.json ./

EXPOSE 3001
CMD ["npm", "start"]

.dockerignore の設定

node_modules
npm-debug.log
.git
.gitignore
README.md
.env
.nyc_output
coverage
.vscode
.idea
*.swp
*.swo
*~
.DS_Store
Thumbs.db

モニタリングとログ

ログ設定

services:
  backend:
    logging:
      driver: "json-file"
      options:
        max-size: "10m"
        max-file: "3"

  frontend:
    logging:
      driver: "json-file"
      options:
        max-size: "10m"
        max-file: "3"

ログの確認コマンド

# 全サービスのログを表示
docker-compose logs -f

# 特定サービスのログのみ
docker-compose logs -f backend

# 最新のログのみ表示
docker-compose logs --tail=100 backend

# タイムスタンプ付きでログ表示
docker-compose logs -f -t backend

トラブルシューティング

よくある問題と解決方法

コンテナが起動しない

# ログの確認
docker-compose logs [service-name]

# コンテナの状態確認
docker-compose ps

# 個別コンテナでのデバッグ
docker-compose exec backend sh

ポート競合エラー

# 使用中のポートを確認
netstat -an | grep 3001
lsof -i :3001

# ポート番号を変更
# docker-compose.yml
ports:
  - "3002:3001"  # ホスト側のポートを変更

ボリュームマウントの問題

# ボリュームの確認
docker volume ls

# ボリュームの詳細情報
docker volume inspect project_postgres_data

# ボリュームの削除
docker volume rm project_postgres_data