Docker und TypeScript: Containerisierung von Anwendungen von Grund auf

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: Warum TypeScript-Anwendungen containerisieren?



Moderne Softwareentwicklung ist ohne Containerisierung nicht denkbar. Docker hat sich zum De-facto-Standard für das Verpacken, Ausliefern und Ausführen von Anwendungen in isolierten Umgebungen entwickelt. In Kombination mit TypeScript – einer streng typisierten Obermenge von JavaScript – sorgt Docker für Vorhersagbarkeit, Portabilität und vereinfacht CI/CD-Prozesse.



In diesem Artikel werden wir uns ansehen, wie man eine TypeScript-Anwendung richtig containerisiert: vom einfachen Dockerfile bis hin zu einem production-ready Build mit docker-compose und Multi-Stage-Builds. Sie erfahren, wie Sie typische Fehler vermeiden, die Image-Größe reduzieren und die Bereitstellung beschleunigen.



Grundlagen: TypeScript und Node.js in Docker



TypeScript ist eine Sprache, die zu JavaScript kompiliert wird. Das bedeutet, dass wir zum Ausführen einer TypeScript-Anwendung in einem Container zuerst den Quellcode kompilieren und dann das resultierende JavaScript mit Node.js ausführen müssen. Docker eignet sich hervorragend zur Automatisierung dieses Prozesses.



Erstellen einer einfachen TypeScript-Anwendung



Zunächst erstellen wir eine minimale TypeScript-Anwendung. Die Projektstruktur:



my-ts-app/├── src/│   └── index.ts├── package.json├── tsconfig.json└── Dockerfile


src/index.ts:



import express, { Request, Response } from 'express';

const app = express();const PORT = process.env.PORT || 3000;

app.get('/', (req: Request, res: Response) => { res.json({ message: 'Hello from TypeScript + Docker!' });});

app.listen(PORT, () => { console.log(`Server is running on port ${PORT}`);});


package.json:



{  "name": "my-ts-app",  "version": "1.0.0",  "scripts": {    "build": "tsc",    "start": "node dist/index.js",    "dev": "ts-node src/index.ts"  },  "dependencies": {    "express": "^4.18.2"  },  "devDependencies": {    "@types/express": "^4.17.21",    "@types/node": "^20.11.0",    "typescript": "^5.3.3",    "ts-node": "^10.9.2"  }}


tsconfig.json:



{  "compilerOptions": {    "target": "ES2020",    "module": "commonjs",    "outDir": "./dist",    "rootDir": "./src",    "strict": true,    "esModuleInterop": true,    "skipLibCheck": true  },  "include": ["src/**/*"]}


Einfaches Dockerfile



Die erste, einfachste Variante eines Dockerfiles:



FROM node:20-alpine

WORKDIR /app

COPY package*.json ./RUN npm install

COPY . .

RUN npm run build

EXPOSE 3000

CMD ["npm", "start"]


Dieses Dockerfile kopiert das gesamte Projekt, installiert Abhängigkeiten, kompiliert TypeScript und startet die Anwendung. Dieser Ansatz hat jedoch Nachteile: Die Image-Größe ist groß und das Caching der Layer ist ineffizient.



Optimierung: Multi-Stage-Build und Größenreduzierung



Für die Production-Umgebung wird die Verwendung eines Multi-Stage-Builds empfohlen. Dies ermöglicht die Trennung von Build- und Ausführungsphasen, sodass im finalen Image nur die notwendigen Dateien verbleiben.



Production Dockerfile mit Multi-Stage-Build



# Stage 1: BuildFROM node:20-alpine AS builder

WORKDIR /app

COPY package*.json ./RUN npm ci --only=production

COPY . .RUN npm run build

# Stage 2: ProductionFROM node:20-alpine

WORKDIR /app

COPY --from=builder /app/dist ./distCOPY --from=builder /app/node_modules ./node_modulesCOPY --from=builder /app/package.json ./

EXPOSE 3000

USER node

CMD ["node", "dist/index.js"]


Vorteile dieses Ansatzes:

  • Geringere Image-Größe – Die finale Schicht enthält nur den kompilierten Code und die Production-Abhängigkeiten.
  • Sicherheit – Im Container verbleibt kein TypeScript-Quellcode, dev

Blogs

Buchempfehlungen