Docker und JavaScript: Containerisierung von Node.js-Anwendungen (Fortgeschrittenenniveau)

Online Python-Trainer für Anfänger

Lernen Sie Python einfach ohne theoretische Überlastung. Lösen Sie praktische Aufgaben mit automatischer Überprüfung und schreiben Sie Code direkt im Browser.

Kurs starten

Einleitung: Vom Einfachen zum Komplexen in der Welt der Containerisierung

\n\n

Auf der Anfängerstufe beschränkt sich die Arbeit mit Docker und JavaScript (Node.js) oft auf die Erstellung eines einfachen Dockerfile und das Starten eines Containers. In realen Produktionssystemen reicht dies jedoch nicht aus. Das fortgeschrittene Niveau erfordert ein tiefes Verständnis der Build-Mechanismen, der Optimierung der Image-Größe, des Abhängigkeitsmanagements, der Netzwerkisolation und der Sicherheit.

\n\n

In diesem Artikel behandeln wir die wichtigsten Aspekte der professionellen Containerisierung von Node.js-Anwendungen. Sie erfahren, wie Sie Multi-Stage-Builds verwenden, Docker Compose für eine Microservices-Architektur konfigurieren, Umgebungsvariablen verwalten und die Angriffsfläche minimieren. Das Material richtet sich an Entwickler, die bereits mit den Grundlagen von Docker und JavaScript vertraut sind.

\n\n

1. Multi-Stage-Builds für Node.js

\n\n

Eines der Hauptprobleme bei der Containerisierung von Node.js-Anwendungen ist die übermäßige Größe des endgültigen Images. Der Standardansatz mit einem einzigen Dockerfile enthält Build-Tools (TypeScript, Webpack, Babel), die zur Laufzeit nicht benötigt werden. Multi-Stage-Builds ermöglichen es, den Prozess in Phasen zu unterteilen: Build und Ausführung.

\n\n

1.1. Beispiel eines Dockerfile mit zwei Stufen

\n\n
# Build-Stufe\nFROM node:20-alpine AS builder\nWORKDIR /app\nCOPY package*.json ./\nRUN npm ci --only=production\nCOPY . .\nRUN npm run build  # Es wird angenommen, dass das Build-Skript das Projekt erstellt\n\n# Produktions-Stufe\nFROM node:20-alpine AS production\nWORKDIR /app\n# Nur node_modules und die erstellten Dateien kopieren\nCOPY --from=builder /app/node_modules ./node_modules\nCOPY --from=builder /app/dist ./dist\nCOPY package*.json ./\n\nEXPOSE 3000\nUSER node\nCMD ["node", "dist/index.js"]
\n\n

Wichtige Punkte:

\n
    \n
  • node:20-alpine — leichtgewichtiges Image basierend auf Alpine Linux (ca. 30 MB).
  • \n
  • npm ci — saubere Installation der Abhängigkeiten streng nach package-lock.json.
  • \n
  • --only=production — Ausschluss von Dev-Abhängigkeiten (TypeScript, Tests).
  • \n
  • USER node — Verzicht auf den Root-Benutzer aus Sicherheitsgründen.
  • \n
\n\n

Das Ergebnis ist ein endgültiges Image, das nur die für den Start erforderlichen Dateien enthält, wodurch die Größe von 300-400 MB auf 80-120 MB reduziert wird.

\n\n

1.2. Optimierung des Layer-Cachings

\n\n

Docker cached jede Ebene (jeden Befehl). Um wiederholte Builds zu beschleunigen, kopieren Sie package*.json vor dem Kopieren des gesamten Quellcodes. Wenn sich die Abhängigkeiten nicht geändert haben, wird die Ebene mit npm ci aus dem Cache übernommen.

\n\n
COPY package*.json ./\nRUN npm ci --only=production\nCOPY . .  # Wird nur kopiert, wenn sich die Quelldateien geändert haben
\n\n

2. Docker Compose für Microservices-Architektur

\n\n

In der Produktion arbeitet eine Node.js-Anwendung selten isoliert. In der Regel werden eine Datenbank (PostgreSQL, MongoDB), ein Cache (Redis) oder eine Message Queue (RabbitMQ) benötigt. Docker Compose ermöglicht es, die gesamte Infrastruktur in einer einzigen YAML-Datei zu beschreiben.

\n\n

2.1. Beispiel einer docker-compose.yml für Node.js + Redis

\n\n
version: '3.8'\nservices:\n  app:\n    build:\n      context: .\n      dockerfile: Dockerfile.prod\n    ports:\n      - "3000:3000"\n    environment:\n      - NODE_ENV=production\n      - REDIS_URL=redis://redis:6379\n    depends_on:\n      - redis\n    networks:\n      - backend\n\n  redis:\n    image: redis:7-alpine\n    ports:\n      - "6379:6379"\n    volumes:\n      - redis_data:/data\n    networks:\n      - backend\n\nvolumes:\n  redis_data:\n\nnetworks:\n  backend:\n    driver: bridge
\n\n

Wichtige Aspekte:

\n
    \n
  • Netzwerkisolation: Die Dienste kommunizieren über das interne Netzwerk backend. Redis ist von außen nicht erreichbar (es sei denn, der Port wird freigegeben).
  • \n
  • Benannte Volumes: redis_data speichert die Daten dauerhaft.
  • \n

Blogs

Buchempfehlungen