Docker und TypeScript: Fortgeschrittene Containerisierung von Anwendungen

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

Docker und TypeScript: Fortgeschrittene Containerisierung von Anwendungen

\n\n

Die Containerisierung von TypeScript-Anwendungen mit Docker ist nicht einfach nur das Verpacken von Code in ein Image. Auf fortgeschrittenem Niveau ist es eine Kunst der Optimierung, Sicherheit und Automatisierung. In diesem Artikel werden wir uns damit befassen, wie man effiziente Docker-Images für TypeScript erstellt, die Umgebung verwaltet und die Containerisierung in eine CI/CD-Pipeline integriert. Sie erfahren, wie Sie die Image-Größe um das 5- bis 10-fache reduzieren, den Build beschleunigen und die Isolation von Abhängigkeiten verbessern.

\n\n

1. Multi-Stage-Builds für TypeScript

\n\n

Ein klassisches Problem von Docker-Images für TypeScript ist die Aufnahme aller Entwicklungswerkzeuge in das finale Image: TypeScript-Compiler, dev-Abhängigkeiten, Quelldateien. Dies führt zu enormen Größen (oft > 1 GB). Die Lösung sind Multi-Stage-Builds.

\n\n

Die Idee ist einfach: Die erste Stufe (build) kompiliert TypeScript in JavaScript und installiert alle Abhängigkeiten. Die zweite Stufe (production) kopiert nur das fertige JavaScript und die production-Abhängigkeiten.

\n\n
# Stufe 1: Build\nFROM node:20-alpine AS builder\nWORKDIR /app\nCOPY package*.json ./\nRUN npm ci --only=development\nCOPY . .\nRUN npm run build\n\n# Stufe 2: Produktion\nFROM node:20-alpine AS production\nWORKDIR /app\nCOPY --from=builder /app/dist ./dist\nCOPY --from=builder /app/package*.json ./\nRUN npm ci --only=production\nEXPOSE 3000\nCMD ["node", "dist/index.js"]
\n\n

Dieser Ansatz reduziert die Image-Größe von ~800 MB auf ~150 MB. Beachten Sie --only=development und --only=production – dies sind die entscheidenden Flags zur Trennung der Abhängigkeiten.

\n\n

2. Optimierung des Docker-Layer-Cachings

\n\n

Jede Anweisung in einem Dockerfile erzeugt einen Layer. Docker cached Layer, wenn sie sich nicht geändert haben. Die richtige Reihenfolge der Anweisungen ist entscheidend für die Geschwindigkeit wiederholter Builds.

\n\n

Schlechtes Beispiel (bricht den Cache):

\n
FROM node:20-alpine\nWORKDIR /app\nCOPY . .\nRUN npm ci\nRUN npm run build\nCMD ["node", "dist/index.js"]
\n\n

Hier setzt jede Änderung im Quellcode (selbst in der README.md) den Cache für npm ci und den Build zurück.

\n\n

Gutes Beispiel (erhält den Cache):

\n
FROM node:20-alpine AS builder\nWORKDIR /app\nCOPY package*.json tsconfig.json ./\nRUN npm ci --only=development\nCOPY src ./src\nRUN npm run build
\n\n

Warum funktioniert das? Abhängigkeiten ändern sich selten, der Quellcode jedoch häufig. Indem wir package*.json separat kopieren, stellen wir sicher, dass der Layer mit npm ci nur neu erstellt wird, wenn sich diese Dateien ändern.

\n\n

3. Arbeiten mit Umgebungsvariablen und Secrets

\n\n

Für TypeScript-Anwendungen auf Node.js ist die Verwendung von Umgebungsvariablen Standard. Bei Docker gibt es jedoch Nuancen.

\n\n

Typischer Fehler: Übergabe sensibler Daten (API-Schlüssel, Passwörter) über ENV im Dockerfile. Dies hinterlässt Secrets in der Layer-Historie des Images.

\n\n

Richtiger Ansatz:

\n
    \n
  • Verwenden Sie --env-file beim Starten des Containers
  • \n
  • Für die Produktion verwenden Sie Docker Secrets (in Swarm) oder Kubernetes Secrets
  • \n
  • Für die lokale Entwicklung – eine .env-Datei mit docker-compose
  • \n
\n\n

Beispiel docker-compose.yml:

\n
version: '3.8'\nservices:\n  app:\n    build: .\n    ports:\n      - "3000:3000"\n    env_file:\n      - .env.production\n    volumes:\n      - ./logs:/app/logs
\n\n

Im TypeScript-Code verwenden Sie die Bibliothek dotenv zum Laden der Variablen:

\n
import dotenv from 'dotenv';\nimport { resolve } from 'path';\n\ndotenv.config({ path: resolve(__dirname, '../.env') });\n\nconst config = {\n  port: parseInt(process.env.PORT || '3000', 10),\n  dbUrl: process.env.DATABASE_URL,\n  apiKey: process.env.API_KEY\n};\n\nexport default config;
\n\n

Wichtig: Committen Sie niemals echte .env-Dateien

Blogs

Buchempfehlungen