Zum Hauptinhalt springen

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 20269 Min. Lesezeit1.8k Wörter|

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.

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

Transformieren Sie Ihr Unternehmen mit Odoo ERP

Kompetente Odoo-Implementierung, Anpassung und Support zur Optimierung Ihrer Abläufe.