実稼働 ERP 導入のための Docker: 完全な運用ガイド
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 スタック:
- アプリケーション サーバー: ERP ランタイム (Odoo、NestJS など)
- データベース: 永続ボリューム ストレージを備えた PostgreSQL
- リバース プロキシ: SSL 終了、静的ファイル、リクエスト ルーティングを処理する Nginx
- キャッシュ レイヤー: セッション ストレージ、ジョブ キュー、アプリケーション キャッシュ用の Redis
- バックグラウンド ワーカー: 電子メール、レポート、統合用の非同期ジョブ プロセッサー
オプションのサービスには、バックアップ コンテナー (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.8GB | 4分 |
| シングルステージ (アルパイン) | 650MB | 3.5分 |
| マルチステージ(アルパイン) | 180MB | 5分 |
| マルチステージ+プルーニングされたdeps | 120MB | 5.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;
}
}
}
再起動ポリシーの選択
| ポリシー | 行動 | 使用例 |
|---|---|---|
| コード0 | 決して再起動しないでください | 開発、単発タスク |
| コード0 | ゼロ以外の終了時にのみ再起動します。ワーカー、バッチ ジョブ | |
| コード0 | 常に再起動 (docker デーモンの再起動時を含む) | 制作サービス |
| コード0 | always と似ていますが、手動停止を尊重します。ほとんどの制作サービス |
実稼働サービスには 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 が発行 -- 企業がエンタープライズ ソフトウェアを自信を持って導入できるように支援します。
執筆者
ECOSIRE Research and Development Team
ECOSIREでエンタープライズグレードのデジタル製品を開発。Odoo統合、eコマース自動化、AI搭載ビジネスソリューションに関するインサイトを共有しています。
関連記事
買掛金管理の自動化: 処理コストを 80% 削減
OCR、三者照合、ERP ワークフローを使用して買掛金の自動化を実装し、請求書処理コストを請求書あたり 15 ドルから 3 ドルに削減します。
会計および簿記の自動化における AI: CFO 導入ガイド
AI を使用して請求書処理、銀行調整、経費管理、財務報告のための会計を自動化します。クローズサイクルが 85% 高速化。
最新のアプリケーションの API ゲートウェイ パターンとベスト プラクティス
スケーラブルな Web アーキテクチャ向けに、レート制限、認証、リクエスト ルーティング、サーキット ブレーカー、API バージョン管理などの API ゲートウェイ パターンを実装します。