メインコンテンツにスキップ

実稼働 ERP 導入のための Docker: 完全な運用ガイド

Docker を使用して ERP システムを実稼働環境に導入します。マルチステージビルド、Docker Compose オーケストレーション、ボリューム管理、ネットワーキング、およびスケーリング戦略について説明します。

E
ECOSIRE Research and Development Team
|2026年3月16日7 分で読める1.2k 語数|

Docker コンテナで ERP システムを実行している組織は、従来のベアメタル展開と比較して、展開サイクルが 73% 速く、環境関連のインシデントが 45% 少ないと報告しています。 Docker は、ERP 導入を、数日かかるエラーが発生しやすいプロセスから、チーム メンバーなら誰でも実行できる反復可能なバージョン管理された操作に変換します。

Docker コンテナで ERP システムを実行している組織は、従来のベアメタル展開と比較して、展開サイクルが 73% 速く、環境関連のインシデントが 45% 少ないと報告しています。 Docker は、ERP 導入を、数日かかるエラーが発生しやすいプロセスから、チーム メンバーなら誰でも実行できる反復可能なバージョン管理された操作に変換します。

このガイドでは、運用環境の Docker 環境で、Odoo、カスタム NestJS バックエンド、Next.js フロントエンドを含むエンタープライズ ERP システムを実行するライフサイクル全体を取り上げます。

重要なポイント

  • 多段階の Docker ビルドにより ERP コンテナー イメージのサイズが 60 ~ 80% 削減され、デプロイメント速度が向上します
  • Docker Compose は、ERP、データベース、リバース プロキシ、キャッシュ サービスを単一のデプロイ可能なユニットとして調整します
  • 名前付きボリュームとバインド マウントにより、コンテナの再起動やアップグレード後もデータの永続性が確保されます。
  • ヘルスチェックと再起動ポリシーにより、一時的な障害から自動的に回復します

Docker 化された ERP スタックのアーキテクチャ

本番環境の ERP 導入には通常、5 つ以上の相互接続されたサービスが含まれます。 Docker Compose はこれらのサービスを宣言的に定義し、環境全体で一貫したデプロイを保証します。

サービストポロジ

標準の Docker 化された ERP スタック:

  1. アプリケーション サーバー: ERP ランタイム (Odoo、NestJS など)
  2. データベース: 永続ボリューム ストレージを備えた PostgreSQL
  3. リバース プロキシ: SSL 終了、静的ファイル、リクエスト ルーティングを処理する Nginx
  4. キャッシュ レイヤー: セッション ストレージ、ジョブ キュー、アプリケーション キャッシュ用の Redis
  5. バックグラウンド ワーカー: 電子メール、レポート、統合用の非同期ジョブ プロセッサー

オプションのサービスには、バックアップ コンテナー (cron 上の pg_dump)、モニタリング サイドカー (Prometheus エクスポーター)、およびログ シッパー (Fluent Bit) が含まれます。


ERP アプリケーションのマルチステージ ビルド

実稼働 Docker イメージには、マルチステージ ビルドが不可欠です。ビルド時の依存関係を実行時から分離し、無駄のない安全なイメージを生成します。

NestJS バックエンドのビルド

# Stage 1: Install dependencies and build
FROM node:20-alpine AS builder
WORKDIR /app

# Install pnpm
RUN corepack enable

# Copy workspace configuration
COPY pnpm-lock.yaml pnpm-workspace.yaml package.json ./
COPY packages/ ./packages/
COPY apps/api/package.json ./apps/api/

# Install dependencies
RUN pnpm install --frozen-lockfile

# Copy source and build
COPY apps/api/ ./apps/api/
RUN pnpm --filter @ecosire/db build
RUN pnpm --filter @ecosire/types build
RUN pnpm --filter @ecosire/validators build
RUN pnpm --filter @ecosire/api build

# Stage 2: Production runtime
FROM node:20-alpine AS runner
WORKDIR /app

RUN addgroup -g 1001 -S appgroup && \
    adduser -S appuser -u 1001 -G appgroup

COPY --from=builder --chown=appuser:appgroup /app/apps/api/dist ./dist
COPY --from=builder --chown=appuser:appgroup /app/node_modules ./node_modules
COPY --from=builder --chown=appuser:appgroup /app/apps/api/package.json ./

USER appuser
EXPOSE 3001

HEALTHCHECK --interval=30s --timeout=5s --start-period=10s --retries=3 \
  CMD wget --no-verbose --tries=1 --spider http://localhost:3001/health || exit 1

CMD ["node", "dist/main.js"]

Next.js フロントエンド ビルド

FROM node:20-alpine AS builder
WORKDIR /app
RUN corepack enable

COPY pnpm-lock.yaml pnpm-workspace.yaml package.json ./
COPY packages/ ./packages/
COPY apps/web/package.json ./apps/web/

RUN pnpm install --frozen-lockfile

COPY apps/web/ ./apps/web/
RUN pnpm --filter @ecosire/web build

FROM node:20-alpine AS runner
WORKDIR /app

RUN addgroup -g 1001 -S appgroup && \
    adduser -S appuser -u 1001 -G appgroup

COPY --from=builder --chown=appuser:appgroup /app/apps/web/.next/standalone ./
COPY --from=builder --chown=appuser:appgroup /app/apps/web/.next/static ./.next/static
COPY --from=builder --chown=appuser:appgroup /app/apps/web/public ./public

USER appuser
EXPOSE 3000
ENV NODE_ENV=production
CMD ["node", "server.js"]

画像サイズの比較

ビルドタイプ画像サイズビルド時間
シングルステージ (フルノードイメージ)1.8GB4分
シングルステージ (アルパイン)650MB3.5分
マルチステージ(アルパイン)180MB5分
マルチステージ+プルーニングされたdeps120MB5.5分

5.5 分のビルド時間は、開発者のマシンではなく CI で発生するため、許容範囲です。


本番環境向けの Docker Compose

version: "3.8"

services:
  api:
    build:
      context: .
      dockerfile: apps/api/Dockerfile
    environment:
      - DATABASE_URL=postgresql://app:${DB_PASSWORD}@db:5432/ecosire
      - REDIS_URL=redis://redis:6379
      - NODE_ENV=production
    depends_on:
      db:
        condition: service_healthy
      redis:
        condition: service_healthy
    restart: unless-stopped
    networks:
      - backend
      - frontend

  web:
    build:
      context: .
      dockerfile: apps/web/Dockerfile
    environment:
      - API_URL=http://api:3001
      - NODE_ENV=production
    depends_on:
      - api
    restart: unless-stopped
    networks:
      - frontend

  db:
    image: postgres:17-alpine
    environment:
      POSTGRES_USER: app
      POSTGRES_PASSWORD: ${DB_PASSWORD}
      POSTGRES_DB: ecosire
    volumes:
      - postgres-data:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U app -d ecosire"]
      interval: 10s
      timeout: 5s
      retries: 5
    restart: unless-stopped
    networks:
      - backend

  redis:
    image: redis:7-alpine
    command: redis-server --requirepass ${REDIS_PASSWORD} --maxmemory 256mb --maxmemory-policy allkeys-lru
    volumes:
      - redis-data:/data
    healthcheck:
      test: ["CMD", "redis-cli", "-a", "${REDIS_PASSWORD}", "ping"]
      interval: 10s
      timeout: 5s
      retries: 5
    restart: unless-stopped
    networks:
      - backend

  nginx:
    image: nginx:alpine
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./infrastructure/nginx/production.conf:/etc/nginx/conf.d/default.conf:ro
      - ./certbot/conf:/etc/letsencrypt:ro
      - ./certbot/www:/var/www/certbot:ro
    depends_on:
      - web
      - api
    restart: unless-stopped
    networks:
      - frontend

volumes:
  postgres-data:
  redis-data:

networks:
  frontend:
  backend:

Network Isolation

上記の構成では 2 つのネットワークを使用します。

  • フロントエンド: Nginx、Web、および API (両方に対する Nginx プロキシ)
  • バックエンド: API、データベース、Redis

データベースと Redis には、Nginx コンテナーまたは外部ネットワークからアクセスできません。このネットワークのセグメント化は重要なセキュリティ対策です。


ボリューム管理とデータの永続化

ボリュームは、Dockerized ERP 導入の最も重要な部分です。ボリュームが失われると、データも失われます。

ボリュームの種類

タイプ使用例永続性パフォーマンス
名前付きボリュームデータベース、Redisコンテナの撤去に耐えるネイティブ ファイルシステムの速度
バインドマウント設定ファイル、ログホスト ファイル システムに関連付けられているネイティブ ファイルシステムの速度
tmpfs マウント一時ファイル、シークレットメモリのみ、再起動時に失われますメモリ速度

Docker ボリュームのバックアップ戦略

#!/bin/bash
# backup-volumes.sh - Run via cron every 6 hours

TIMESTAMP=$(date +%Y%m%d_%H%M%S)
BACKUP_DIR="/opt/backups"

# Stop the application briefly for consistent backup
docker compose stop api web

# Backup PostgreSQL
docker compose exec -T db pg_dump -U app ecosire | gzip > "$BACKUP_DIR/db_$TIMESTAMP.sql.gz"

# Backup Redis
docker compose exec -T redis redis-cli -a "$REDIS_PASSWORD" BGSAVE
sleep 5
docker cp $(docker compose ps -q redis):/data/dump.rdb "$BACKUP_DIR/redis_$TIMESTAMP.rdb"

# Restart services
docker compose start api web

# Upload to S3
aws s3 sync "$BACKUP_DIR" "s3://company-backups/docker-volumes/" --exclude "*.tmp"

# Retain 30 days locally
find "$BACKUP_DIR" -name "*.gz" -mtime +30 -delete
find "$BACKUP_DIR" -name "*.rdb" -mtime +30 -delete

ヘルスチェックと再起動ポリシー

実稼働コンテナは状態を自己報告し、障害から自動的に回復する必要があります。

アプリケーションヘルスチェックエンドポイント

// health.controller.ts
@Controller('health')
export class HealthController {
  constructor(
    private readonly db: DatabaseService,
    private readonly redis: RedisService,
  ) {}

  @Get()
  @Public()
  async check() {
    const checks = {
      database: await this.checkDatabase(),
      redis: await this.checkRedis(),
      uptime: process.uptime(),
      memory: process.memoryUsage(),
    };

    const healthy = checks.database && checks.redis;
    return { status: healthy ? 'ok' : 'degraded', checks };
  }

  private async checkDatabase(): Promise<boolean> {
    try {
      await this.db.execute('SELECT 1');
      return true;
    } catch {
      return false;
    }
  }

  private async checkRedis(): Promise<boolean> {
    try {
      await this.redis.ping();
      return true;
    } catch {
      return false;
    }
  }
}

再起動ポリシーの選択

ポリシー行動使用例
no決して再起動しないでください開発、単発タスク
on-failureゼロ以外の終了時にのみ再起動しますワーカー、バッチ ジョブ
always常に再起動 (docker デーモンの再起動時を含む)制作サービス
unless-stoppedalways と似ていますが、手動停止を尊重しますほとんどの制作サービス

実稼働サービスには unless-stopped を使用します。これにより、サーバーの再起動または Docker デーモンの再起動後にコンテナーが確実に再起動されますが、メンテナンス中は手動の docker compose stop コマンドが尊重されます。


導入ワークフロー

Docker Compose を使用したローリング アップデート

#!/bin/bash
# deploy.sh - Zero-downtime deployment

set -e

echo "Pulling latest code..."
git pull origin main

echo "Building new images..."
docker compose build --no-cache api web

echo "Rolling update - API first..."
docker compose up -d --no-deps api
sleep 10

# Verify API health
if ! curl -sf http://localhost:3001/health > /dev/null; then
  echo "API health check failed, rolling back..."
  docker compose up -d --no-deps api
  exit 1
fi

echo "Rolling update - Web..."
docker compose up -d --no-deps web
sleep 5

# Verify Web health
if ! curl -sf http://localhost:3000 > /dev/null; then
  echo "Web health check failed, rolling back..."
  docker compose up -d --no-deps web
  exit 1
fi

echo "Deployment complete!"
docker compose ps

データベース移行の安全性

アプリケーションの起動中に移行を実行しないでください。代わりに、それらを別のステップとして実行します。

# Run migrations before deploying new containers
docker compose run --rm api npx drizzle-kit push

# Then deploy the new version
docker compose up -d

このパターンにより、移行が失敗した場合でも、古いバージョンは影響を受けずに実行し続けることが保証されます。


ロギングとデバッグ

集中ログ

# Add to docker-compose.yml
services:
  api:
    logging:
      driver: json-file
      options:
        max-size: "10m"
        max-file: "5"
        labels: "service"
    labels:
      service: "ecosire-api"

一般的なデバッグ コマンド

# View logs for a specific service
docker compose logs -f api --tail 100

# Execute a shell inside a running container
docker compose exec api sh

# View resource usage
docker stats --format "table {{.Name}}\t{{.CPUPerc}}\t{{.MemUsage}}\t{{.NetIO}}"

# Inspect container networking
docker compose exec api ping db

# View container environment variables
docker compose exec api env | sort

よくある質問

Docker でデータベースの移行を処理するにはどうすればよいですか?

新しいアプリケーション コンテナをデプロイする前に、別の手順として移行を実行します。デプロイ前の手順として docker compose run --rm api npx drizzle-kit push (または ORM の移行コマンド) を使用します。コンテナ起動コマンドに移行の実行を決して埋め込まないでください。移行が失敗しても、現在のバージョンの実行が妨げられることはありません。

Docker のパフォーマンスのオーバーヘッドはどれくらいですか?

Linux では、Docker のパフォーマンス オーバーヘッドは無視できます。通常、CPU バウンドのワークロードでは 2% 未満であり、I/O バウンドのワークロードでは測定可能な差はありません。 macOS および Windows では、Docker は仮想マシン内で実行され、5 ~ 15% のオーバーヘッドが追加されます。運用環境 (Linux である必要があります) の場合、Docker はパフォーマンス上の重大な懸念事項ではありません。

Docker でシークレットを管理するにはどうすればよいですか?

Dockerfile または docker-compose.yml ファイルにはシークレットを決して入れないでください。バージョン管理、Docker シークレット (Swarm モードの場合)、または外部シークレット マネージャー (AWS Secrets Manager、HashiCorp Vault) から除外された環境変数ファイル (.env) を使用します。 Docker Compose の場合、プロジェクト ルートにある .env ファイルを使用するのが最も簡単な方法です。

Docker Swarm と Kubernetes のどちらを使用すべきでしょうか?

ほとんどの SMB ERP 導入には、Docker Compose で十分です。 Docker Swarm は、複雑さのオーバーヘッドを最小限に抑えながらマルチホスト オーケストレーションを追加します。 Kubernetes は、自動スケーリング、複雑なネットワーク ポリシー、またはサービス メッシュ機能が必要な場合に適しています。意思決定フレームワークについては、Kubernetes スケーリング ガイド および マイクロサービス アーキテクチャ ガイド を参照してください。

Docker で Odoo カスタム モジュールを処理するにはどうすればよいですか?

カスタム モジュールを、アドオン ディレクトリを指すバインド マウント ボリュームとしてマウントします。 Dockerfile で、アドオン パスが odoo.conf で構成されていることを確認します。 CI/CD の場合は、モジュールをベイクするカスタム Docker イメージを構築して、バージョンの一貫性を確保します。 Odoo 固有の構成については、既存の Docker Odoo 導入ガイド を参照してください。


次に何が起こるか

Docker は最新の ERP 導入の基盤です。コンテナ化されたスタックが安定したら、ゼロダウンタイム展開戦略、運用監視、コードとしてのインフラストラクチャ を検討して、完全に自動化された運用パイプラインを構築します。

Docker 導入コンサルティングについては ECOSIRE にお問い合わせ、フルマネージドのコンテナ化された ERP 導入については Odoo 実装サービス をご覧ください。


ECOSIRE が発行 -- 企業がエンタープライズ ソフトウェアを自信を持って導入できるように支援します。

E

執筆者

ECOSIRE Team

Technical Writing

The ECOSIRE technical writing team covers Odoo ERP, Shopify eCommerce, AI agents, Power BI analytics, GoHighLevel automation, and enterprise software best practices. Our guides help businesses make informed technology decisions.

ECOSIRE

Odoo ERP でビジネスを変革

Odoo の専門家による実装、カスタマイズ、サポートにより、業務を合理化します。