Einführung in Docker und TypeScript: Warum Containerisierung notwendig ist
Moderne Webentwicklung ist ohne Werkzeuge, die eine einheitliche Umgebung gewährleisten, nicht denkbar. Docker hat sich zum De-facto-Standard für das Verpacken, Ausliefern und Ausführen von Anwendungen entwickelt. In Kombination mit TypeScript – einer streng typisierten Sprache, die zu JavaScript kompiliert wird – bietet die Containerisierung ein leistungsstarkes Werkzeug zur Erstellung skalierbarer und zuverlässiger Dienste.
Warum sollte man eine TypeScript-Anwendung containerisieren? Erstens löst es das Problem „Auf meinem Rechner funktioniert es“. Zweitens vereinfacht es die Bereitstellung in der Produktion und in CI/CD. Drittens ermöglicht es die Isolierung von Abhängigkeiten und Node.js-Versionen. In diesem Artikel werden wir uns ansehen, wie man ein Docker-Image für eine TypeScript-Anwendung erstellt, einen Multi-Stage-Build konfiguriert und docker-compose für die lokale Entwicklung verwendet.
Grundlagen von Docker für TypeScript-Entwickler
Bevor wir Code schreiben, erinnern wir an die grundlegenden Docker-Konzepte: Image – eine Vorlage zum Erstellen eines Containers; Container – eine laufende Instanz eines Images; Dockerfile – eine Anleitung zum Erstellen eines Images.
Für eine TypeScript-Anwendung auf Node.js benötigen wir:
- Node.js-Laufzeitumgebung (normalerweise das Image
node:18-alpineodernode:20-alpinefür minimale Größe) - Installation von Abhängigkeiten (
npm installoderyarn install) - Kompilierung von TypeScript in JavaScript (
tsc) - Starten der kompilierten Anwendung
Betrachten wir ein einfaches Beispiel einer TypeScript-Anwendung (Datei src/index.ts):
import express from 'express';
const app = express();const PORT = process.env.PORT || 3000;
app.get('/', (req, res) => { res.send('Hello from TypeScript + Docker!');});
app.listen(PORT, () => { console.log(`Server running on port ${PORT}`);});Und tsconfig.json:
{ "compilerOptions": { "target": "ES2020", "module": "commonjs", "outDir": "./dist", "rootDir": "./src", "strict": true, "esModuleInterop": true }, "include": ["src"], "exclude": ["node_modules", "dist"]}Jetzt erstellen wir ein Dockerfile für diese Anwendung.
Erstellen eines Dockerfile für eine TypeScript-Anwendung
Ein grundlegendes Dockerfile könnte so aussehen:
FROM node:18-alpine AS builderWORKDIR /appCOPY package*.json ./RUN npm ciCOPY . .RUN npm run build
FROM node:18-alpine AS runnerWORKDIR /appCOPY --from=builder /app/dist ./distCOPY --from=builder /app/package*.json ./COPY --from=builder /app/node_modules ./node_modulesEXPOSE 3000CMD ["node", "dist/index.js"]Hier wird ein Multi-Stage-Build verwendet. Die erste Stage (builder) kompiliert TypeScript in JavaScript, die zweite (runner) enthält nur den kompilierten Code und die Laufzeitabhängigkeiten. Dies reduziert die Größe des endgültigen Images – die TypeScript-Quellen und Dev-Abhängigkeiten gelangen nicht hinein.
Wichtig: Wir führen npm ci (saubere Installation) anstelle von npm install aus, um Reproduzierbarkeit und Geschwindigkeit zu gewährleisten.
Optimierung des Dockerfile: Layer-Caching
Docker cached jede Schicht (Anweisung). Um den Build zu beschleunigen, kopieren Sie Dateien, die sich selten ändern, früher. Zum Beispiel werden package.json und package-lock.json vor allen Quelldateien kopiert, sodass Codeänderungen nicht zur Neuinstallation von Abhängigkeiten führen.
Zusätzlich kann man eine .dockerignore-Datei hinzufügen:
node_modulesdist.git*.md.gitignore.envDies verhindert, dass unnötige Dateien in den Build-Kontext gelangen.
docker-compose für die lokale Entwicklung
Für eine bequeme lokale Entwicklung verwenden Sie docker-compose.yml. Es ermöglicht das Ausführen der Anwendung mit automatischem Neuladen (unter Verwendung von nodemon od