Docker für die ERP-Bereitstellung in der Produktion: Ein vollständiger Betriebsleitfaden

Stellen Sie ERP-Systeme mit Docker in der Produktion bereit. Behandelt mehrstufige Builds, Docker Compose-Orchestrierung, Volume-Management, Netzwerk- und Skalierungsstrategien.

E
ECOSIRE Research and Development Team
|16. März 20268 Min. Lesezeit1.8k Wörter|

Docker für die ERP-Bereitstellung in der Produktion: Ein vollständiger Betriebsleitfaden

Organisationen, die ERP-Systeme in Docker-Containern betreiben, berichten von 73 % schnelleren Bereitstellungszyklen und 45 % weniger umgebungsbedingten Vorfällen im Vergleich zu herkömmlichen Bare-Metal-Bereitstellungen. Docker verwandelt die ERP-Bereitstellung von einem mehrtägigen, fehleranfälligen Prozess in einen wiederholbaren, versionierten Vorgang, den jedes Teammitglied ausführen kann.

Dieser Leitfaden deckt den gesamten Lebenszyklus der Ausführung von Unternehmens-ERP-Systemen ab – einschließlich Odoo, benutzerdefinierten NestJS-Backends und Next.js-Frontends – in Docker-Produktionsumgebungen.

Wichtige Erkenntnisse

– Mehrstufige Docker-Builds reduzieren die Größe der ERP-Container-Images um 60–80 % und verbessern so die Bereitstellungsgeschwindigkeit – Docker Compose orchestriert ERP-, Datenbank-, Reverse-Proxy- und Cache-Dienste als eine einzige bereitstellbare Einheit – Benannte Volumes und Bind-Mounts stellen die Datenpersistenz bei Container-Neustarts und -Upgrades sicher

  • Gesundheitsprüfungen und Neustartrichtlinien sorgen für eine automatische Wiederherstellung nach vorübergehenden Ausfällen

Architektur eines Docker-ERP-Stacks

Eine ERP-Produktionsbereitstellung umfasst typischerweise fünf oder mehr miteinander verbundene Dienste. Docker Compose definiert diese Dienste deklarativ und gewährleistet so eine konsistente Bereitstellung in allen Umgebungen.

Diensttopologie

Der standardmäßige Dockerized ERP-Stack:

  1. Anwendungsserver: Die ERP-Laufzeit (Odoo, NestJS oder ähnlich)
  2. Datenbank: PostgreSQL mit persistentem Volume-Speicher
  3. Reverse-Proxy: Nginx kümmert sich um die SSL-Terminierung, statische Dateien und das Anforderungsrouting
  4. Cache-Ebene: Redis für Sitzungsspeicher, Jobwarteschlangen und Anwendungs-Caching
  5. Hintergrundarbeiter: Asynchrone Jobprozessoren für E-Mails, Berichte und Integrationen

Zu den optionalen Diensten gehören Backup-Container (pg_dump auf cron), Überwachungs-Sidecars (Prometheus-Exporter) und Protokollversender (Fluent Bit).


Mehrstufige Builds für ERP-Anwendungen

Mehrstufige Builds sind für die Produktion von Docker-Images unerlässlich. Sie trennen Abhängigkeiten zur Build-Zeit von der Laufzeit und erzeugen so schlanke, sichere Images.

NestJS-Backend-Build

# 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 Frontend Build

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"]

Bildgrößenvergleich

Build-TypImage SizeBauzeit
Einstufig (vollständiges Knotenbild)1,8 GB4 Minuten
Einstufig (Alpin)650 MB3,5 Minuten
Mehrstufig (Alpin)180 MB5 Minuten
Mehrstufige + beschnittene Deps120 MB5,5 Minuten

Die Buildzeit von 5,5 Minuten ist akzeptabel, da sie in CI und nicht auf Entwicklermaschinen erfolgt.


Docker Compose für die Produktion

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:

Netzwerkisolation

Die obige Konfiguration verwendet zwei Netzwerke:

  • Frontend: Nginx, Web und API (Nginx-Proxys für beide)
  • Backend: API, Datenbank und Redis

Auf die Datenbank und Redis kann nicht über den Nginx-Container oder das externe Netzwerk zugegriffen werden. Diese Netzwerksegmentierung ist eine wichtige Sicherheitsmaßnahme.


Volume-Management und Datenpersistenz

Volumes sind der kritischste Teil einer Docker-ERP-Bereitstellung. Wenn Sie Ihre Datenträger verlieren, verlieren Sie Ihre Daten.

Volume-Typen

Geben Sieein AnwendungsfallBeharrlichkeitLeistung
Benannte BändeDatenbank, RedisÜberlebt ContainerentfernungGeschwindigkeit des nativen Dateisystems
Halterungen bindenKonfigurationsdateien, ProtokolleAn Host-Dateisystem gebundenGeschwindigkeit des nativen Dateisystems
tmpfs mountetTemporäre Dateien, GeheimnisseNur Speicher, geht beim Neustart verlorenSpeichergeschwindigkeit

Backup-Strategie für Docker-Volumes

#!/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

Integritätsprüfungen und Neustartrichtlinien

Produktionscontainer müssen ihren Zustand selbst melden und sich nach Ausfällen automatisch erholen.

Endpunkt zur Anwendungsintegritätsprüfung

// 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;
    }
  }
}

Richtlinienauswahl neu starten

PolitikVerhaltenAnwendungsfall
noNie neu startenEntwicklung, einmalige Aufgaben
on-failureNur bei Exit ungleich Null neu startenArbeiter, Batch-Jobs
alwaysImmer neu starten (auch beim Neustart des Docker-Daemons)Produktionsdienstleistungen
unless-stoppedWie always, berücksichtigt aber manuelle StoppsDie meisten Produktionsdienstleistungen

Verwenden Sie unless-stopped für Produktionsdienste. Dies stellt sicher, dass Container nach einem Server-Neustart oder einem Docker-Daemon-Neustart neu gestartet werden, berücksichtigt aber manuelle docker compose stop-Befehle während der Wartung.


Bereitstellungsworkflow

Rolling Updates mit 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

Sicherheit der Datenbankmigration

Führen Sie Migrationen niemals innerhalb des Anwendungsstarts durch. Führen Sie sie stattdessen als separaten Schritt aus:

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

# Then deploy the new version
docker compose up -d

Dieses Muster stellt sicher, dass die alte Version unbeeinträchtigt weiterläuft, wenn eine Migration fehlschlägt.


Protokollierung und Debugging

Zentralisierte Protokollierung

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

Allgemeine Debugging-Befehle

# 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

Häufig gestellte Fragen

Wie gehen wir mit Datenbankmigrationen in Docker um?

Führen Sie Migrationen als separaten Schritt aus, bevor Sie neue Anwendungscontainer bereitstellen. Verwenden Sie docker compose run --rm api npx drizzle-kit push (oder den Migrationsbefehl Ihres ORM) als Schritt vor der Bereitstellung. Betten Sie die Migrationsausführung niemals in den Container-Startbefehl ein – eine fehlgeschlagene Migration sollte nicht verhindern, dass die aktuelle Version weiterhin ausgeführt wird.

Wie hoch ist der Leistungsaufwand von Docker?

Unter Linux ist der Leistungsaufwand von Docker vernachlässigbar – typischerweise weniger als 2 % für CPU-gebundene Arbeitslasten und kein messbarer Unterschied für E/A-gebundene Arbeitslasten. Unter macOS und Windows läuft Docker in einer virtuellen Maschine, was einen Mehraufwand von 5–15 % verursacht. Für die Produktion (die Linux sein sollte) stellt Docker kein nennenswertes Leistungsproblem dar.

Wie verwalten wir Geheimnisse in Docker?

Fügen Sie niemals Geheimnisse in Dockerfiles- oder docker-compose.yml-Dateien ein. Verwenden Sie Umgebungsvariablendateien (.env), die von der Versionskontrolle ausgeschlossen sind, Docker-Geheimnisse (für den Swarm-Modus) oder externe Geheimnismanager (AWS Secrets Manager, HashiCorp Vault). Für Docker Compose ist eine .env-Datei im Projektstamm der einfachste Ansatz.

Sollten wir Docker Swarm oder Kubernetes verwenden?

Für die meisten KMU-ERP-Bereitstellungen ist Docker Compose ausreichend. Docker Swarm fügt Multi-Host-Orchestrierung mit minimalem Komplexitätsaufwand hinzu. Kubernetes eignet sich, wenn Sie automatische Skalierung, komplexe Netzwerkrichtlinien oder Service-Mesh-Funktionen benötigen. Weitere Informationen zu Entscheidungsframeworks finden Sie in unserem Kubernetes-Skalierungsleitfaden und unserem Microservices-Architekturleitfaden.

Wie gehen wir mit benutzerdefinierten Odoo-Modulen in Docker um?

Hängen Sie benutzerdefinierte Module als Bind-Mount-Volume ein, das auf Ihr Add-On-Verzeichnis verweist. Stellen Sie in der Docker-Datei sicher, dass der Add-On-Pfad in odoo.conf konfiguriert ist. Erstellen Sie für CI/CD ein benutzerdefiniertes Docker-Image, das Ihre Module einbettet und so die Versionskonsistenz gewährleistet. Informationen zur Odoo-spezifischen Konfiguration finden Sie in unserem bestehenden Docker Odoo-Bereitstellungsleitfaden.


Was als nächstes kommt

Docker ist die Grundlage für die moderne ERP-Bereitstellung. Sobald Ihr Container-Stack stabil ist, erkunden Sie Bereitstellungsstrategien ohne Ausfallzeiten, Produktionsüberwachung und Infrastruktur als Code, um eine vollständig automatisierte Betriebspipeline aufzubauen.

Kontaktieren Sie ECOSIRE für Beratung zur Docker-Bereitstellung oder erkunden Sie unsere Odoo-Implementierungsdienste für die vollständig verwaltete Container-ERP-Bereitstellung.


Herausgegeben von ECOSIRE – hilft Unternehmen dabei, Unternehmenssoftware sicher bereitzustellen.

E

Geschrieben von

ECOSIRE Research and Development Team

Entwicklung von Enterprise-Digitalprodukten bei ECOSIRE. Einblicke in Odoo-Integrationen, E-Commerce-Automatisierung und KI-gestützte Geschäftslösungen.

Chatten Sie auf WhatsApp