Files
uni/slides/dhbw/07_docker.md
T
libretech 4053185e74 dhbw phase 4: alle 8 kapitel slide-MD komplett (4176 zeilen → ~1100 zeilen, ~210 slides total)
kap1 web_eng (104 → 57 slides): kurs-intro + prüfungsleistung-übersicht, internet-timeline (4 milestones), URL→pixel-7-schritte, HTTP, onboarding (node 24 LTS via fnm, brew/winget paket-manager, VS Code/Chromium/Hoppscotch, git setup mit SSH-key, projekt-skeleton), HTML (anatomie, self-closing, grundgerüst, semantik-tabelle, native elemente details/dialog/input-types), A11y volle tiefe (BFSG+EAA 28.06.2025, WCAG-POUR, Perceivable/Operable/Understandable/Robust einzeln mit code, testen mit lighthouse/axe/manuell), CSS-vorschau (anatomie/selektoren/spezifizität/box-model/farben/einheiten/pseudos), JS-vorschau (ECMAScript-timeline/grundlagen/DOM/fetch), frameworks-übersicht (react/vue/svelte/astro counter-vergleich), build-tools/rendering-modi, selbstlernen erste-eigene-seite

kap2 css_extended (13 → 28 slides): box-model + box-sizing global, flexbox basics+achsen+item-properties+typische-patterns, grid basics+areas+auto-layout, flexbox-vs-grid tabelle, mobile-first media queries, viewport-meta, fluid sizing mit clamp(), transitions (was performant), keyframe-animationen, prefers-reduced-motion pflicht, CSS-variablen + dark-mode-pattern, CSS functions (calc/clamp/gradient/oklch/filter), CSS-frameworks tabelle + tailwind pro/contra, selbstlernen flexboxfroggy+cssgridgarden

kap3 nodejs_basics (~22 → 20 slides): was-ist-node + warum-node-tabelle, fnm versions-manager + node 24 LTS + .nvmrc, npm init + package.json (mit type:module), ESM modern + CJS legacy, built-in modules (node: prefix), HTTP-server eingebaut + express, REST mit express (GET/POST/PUT/DELETE-pattern), alternative frameworks tabelle (fastify/hono/koa), routing-pattern mit Router, fetch global ab node 18, error-handling res.ok, environment variables mit dotenv + niemals committen, selbstlernen mini-API

kap4 nodejs_advanced (~24 → 22 slides): synchron-vs-asynchron, promise then-vs-async/await, sequenziell-vs-parallel + Promise.all, promise-methoden tabelle (all/allSettled/race/any), fs/promises lesen+schreiben, streams pipeline für große dateien, DB-übersicht SQLite/Postgres/MongoDB/Redis, better-sqlite3 prepared statements, ORM-übersicht (drizzle/prisma/knex), CRUD-pattern express+sqlite, auth-strategien tabelle, bcrypt für passwörter, JWT-pattern mit httpOnly+secure cookie, try/catch + error-klassen, globaler express-error-handler, selbstlernen REST+DB+auth

kap5 testing (~23 → 23 slides): test-pyramide 70%/20%/10%, vitest setup + describe/it/expect, AAA-pattern, matchers tabelle, TDD red-green-refactor mit konkretem beispiel, supertest für API-integration, test-DB :memory: + lifecycle hooks, mocking mit vi.spyOn (sparsam), playwright E2E mit role-based-locators, E2E-vs-unit tradeoffs, coverage realistisch (80% gut), CI mit github-actions, selbstlernen tests-schreiben

kap6 typescript (~30 → 19 slides): was-ist-TS + warum-tabelle, setup mit tsx + tsconfig.json + strict:true, basis-typen + any vermeiden, object-typen + interfaces + type-aliases, function-typen (Promise<T>), union + discriminated union + intersection, generics + constraints, built-in generics (Partial/Omit/Record), typ-inference (nicht über-annotieren), typen für REST-API mit express, zod runtime-validation + z.infer, any-vs-unknown-vs-never, best practices, selbstlernen API-zu-TS-migration

kap7 docker (~24 → 24 slides): auf-meinem-rechner-läufts problem, container-vs-VM tabelle, docker basics (image/container/dockerfile/registry), dockerfile hallo-welt, schichten + cache-optimierung, multi-stage build, base-image-größen tabelle (alpine ~180MB vs node ~1.1GB), .dockerignore, compose.yml beispiel, compose-commands, networking (service-namen als hostnamen), volumes (named vs bind), env+secrets, github-actions docker-build, registry-übersicht, health-checks, best-practices, selbstlernen app-dockerizen

kap8 best_practices (~30 → 28 slides): sinnvolle commits + conventional commits format, .gitignore template, branches+PRs workflow, README-template mit 6 sektionen, SOLID 5 prinzipien tabelle, S-single-responsibility + D-dependency-inversion mit code, 12-factor wichtigste (codebase/deps/config/processes/disposability), factor 3 config-in-env, factor 6 stateless-processes, SemVer MAJOR.MINOR.PATCH, package.json caret/tilde/exakt, code-reviews geben+nehmen + checkliste, doku-quellen tabelle (MDN/nodejs/npm/tc39/caniuse), stack-overflow gut-nutzen, AI-assistenten pro/contra (verstehen-nicht-kopieren), selbstlernen projekt-hygiene-check

build geht durch alle 8 kapitel-html+pdf
render-spot-check: cover-slide-dark-mode-invert, git-setup code-syntax-highlight, css-anatomie code-blocks — alle sauber

kein deploy, nur build+verify
2026-05-14 17:14:02 +02:00

384 lines
7.4 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
marp: true
theme: gaia
paginate: true
backgroundColor: #fff
header: "Web Engineering – DHBW Stuttgart"
footer: "Michael Czechowski – SoSe 2026"
title: Docker und Service Orchestration
---
<style>
:root { --color-foreground: #1a1a2e; --color-highlight: #d63384; }
section.invert { --color-foreground: #fff; }
section { font-size: 1.4rem; }
h1 { color: #a02060; }
section.invert h1 { color: #fff; }
h2 { color: #1f2937; }
pre { background: #0f0f23; color: #f48fb1; border-radius: 8px; border-left: 3px solid #d63384; }
pre code { background: transparent; color: inherit; }
code { background: #1a1a2e; color: #f48fb1; padding: 0.15em 0.4em; border-radius: 4px; }
a { color: var(--color-highlight); }
</style>
<!-- _class: lead -->
# Kapitel 7 — Docker
## Container für reproducible Setups
---
# „Auf meinem Rechner läuft's"
Das klassische Software-Problem:
- Entwickler: Node 22 + Postgres 16 lokal
- Server: Node 18 + Postgres 14
- → bricht beim Deploy
**Lösung:** App + Abhängigkeiten als **Container** verpacken.
---
# Container vs. VM
| | Container | Virtual Machine |
|--|-----------|-----------------|
| Startzeit | ms | min |
| Größe | MB | GB |
| Kernel | shared (Host-Linux) | eigener |
| Isolation | Prozess-Level | Hardware-Level |
| Overhead | minimal | hoch |
Container = leichtgewichtige Prozess-Isolation.
---
# Docker — die Idee
- **Image** = Schnappschuss (App + Files + OS-Layer)
- **Container** = laufende Instanz eines Images
- **Dockerfile** = Anleitung zum Image-Bauen
- **Registry** = Image-Speicher (Docker Hub, GHCR)
```sh
docker pull node:24
docker run node:24 node --version
```
---
# Dockerfile — Hallo Welt
```dockerfile
FROM node:24-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
EXPOSE 3000
CMD ["node", "src/server.js"]
```
```sh
docker build -t mein-app .
docker run -p 3000:3000 mein-app
```
---
# Dockerfile-Schichten verstehen
Jedes `RUN`/`COPY`/`ADD` = neue Schicht.
```dockerfile
# Schlecht — npm install nach JEDER Code-Änderung
COPY . .
RUN npm ci
# Gut — package.json zuerst, npm install gecached
COPY package*.json ./
RUN npm ci
COPY . .
```
**Build-Cache** spart Minuten.
---
# Multi-Stage Build
```dockerfile
# Stage 1: Build mit allem
FROM node:24-alpine AS builder
WORKDIR /app
COPY . .
RUN npm ci && npm run build
# Stage 2: nur Runtime
FROM node:24-alpine
WORKDIR /app
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/node_modules ./node_modules
COPY package*.json ./
EXPOSE 3000
CMD ["node", "dist/server.js"]
```
Finales Image: kleiner, sicherer (kein Build-Tools drin).
---
# Image-Größen reduzieren
| Base | Größe |
|------|------:|
| `node:24` | ~1.1 GB |
| `node:24-slim` | ~280 MB |
| `node:24-alpine` | **~180 MB** |
| Distroless | ~150 MB |
**`alpine`** = Alpine Linux, sehr klein. **Distroless** = nur Runtime, kein Shell.
---
# .dockerignore
Verhindert dass Müll ins Image kommt:
```
node_modules
.git
.env
*.log
build/
dist/
.DS_Store
README.md
.github/
```
Schneller Build, kleineres Image, weniger Secrets im Image.
---
<!-- _class: lead -->
# docker compose
---
# Multi-Container — die Realität
Eine App braucht oft:
- App-Server
- Datenbank
- Cache (Redis)
- Reverse Proxy
**docker compose** orchestriert das.
---
# compose.yml — Beispiel
```yaml
services:
app:
build: .
ports:
- "3000:3000"
environment:
DATABASE_URL: postgres://user:pass@db:5432/app
depends_on:
- db
db:
image: postgres:16-alpine
environment:
POSTGRES_USER: user
POSTGRES_PASSWORD: pass
POSTGRES_DB: app
volumes:
- db-data:/var/lib/postgresql/data
volumes:
db-data:
```
---
# compose-Commands
```sh
docker compose up # alles starten (Foreground)
docker compose up -d # detached (background)
docker compose down # alles stoppen + entfernen
docker compose down -v # ... und Volumes löschen
docker compose logs -f app # Logs streamen
docker compose exec app sh # Shell im laufenden Container
docker compose ps # Status sehen
```
---
# Networking in compose
Standard: alle Services im selben `default`-Netzwerk.
```yaml
services:
app:
environment:
# `db` ist der Service-Name → DNS-Hostname
DATABASE_URL: postgres://...@db:5432/app
```
**Service-Namen werden zu Hostnamen.** Kein localhost zwischen Containern.
---
# Volumes — Daten überleben
```yaml
volumes:
db-data: # named volume (managed by Docker)
services:
db:
volumes:
- db-data:/var/lib/postgresql/data # named
- ./backups:/backups # bind mount
```
**Named Volumes** für DB-Daten. **Bind Mounts** für lokale Config.
---
# Environment + Secrets
```yaml
services:
app:
env_file: .env # ganze .env-Datei laden
environment:
NODE_ENV: production # einzeln setzen
DATABASE_URL: ${DATABASE_URL} # vom Host
```
**Secrets nicht ins compose.yml.** Lieber `.env` (gitignored) oder Docker Secrets.
---
<!-- _class: lead -->
# CI/CD
---
# Docker in GitHub Actions
```yaml
name: Build + Push
on:
push:
branches: [main]
jobs:
docker:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: docker/setup-buildx-action@v3
- uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_TOKEN }}
- uses: docker/build-push-action@v5
with:
push: true
tags: user/app:latest
```
---
# Container-Registry
| Registry | Stärke |
|----------|--------|
| **Docker Hub** | Standard, kostenlos für Public |
| **GHCR** (GitHub) | mit Repo verbunden |
| **GitLab Registry** | mit Repo verbunden |
| **AWS ECR** | für AWS-Hosting |
```sh
# Tag + Push
docker tag mein-app ghcr.io/user/mein-app:v1.0.0
docker push ghcr.io/user/mein-app:v1.0.0
```
---
# Health-Checks
```dockerfile
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s \
CMD wget --no-verbose --tries=1 --spider http://localhost:3000/health || exit 1
```
```javascript
// In Express
app.get('/health', (req, res) => res.json({ ok: true }));
```
Orchestrators (k8s, ECS, Coolify) entscheiden via HealthCheck, ob neu starten.
---
# Best Practices
- **`alpine`** oder **distroless** als Base
- **Multi-stage builds** für kleinere Images
- **`.dockerignore`** anlegen
- **Non-root user** im Container (`USER node`)
- **`COPY` nach `RUN npm ci`** für Cache-Hit
- **Tags statt `latest`** für Reproducibility
- **Health-Checks** für Orchestration
- **Secrets via env, niemals im Image**
---
<!-- _class: aufgabe -->
# Selbstlernen — App dockerizen
1. **Dockerfile** für eure Node-API (multi-stage)
2. **.dockerignore** mit node_modules, .env, .git
3. **compose.yml** mit App + Postgres
4. **`docker compose up`** lokal starten
5. **Health-Check** auf `/health`-Endpoint
**Bonus:** GitHub-Actions-Workflow, der Image bei jedem Push baut.
---
# Zusammenfassung
**Heute gelernt:**
- Container vs. VM — Prozess-Isolation, leicht + schnell
- **Dockerfile** mit `FROM`, `COPY`, `RUN`, `CMD`
- **Multi-stage Builds** für kleine Production-Images
- **alpine** + Distroless als Base
- **docker compose** für Multi-Container-Setups
- **Volumes** für persistente Daten
- **Service-Namen als Hostnamen** im compose-Netzwerk
- **CI/CD** mit GitHub Actions + Registry
**Nächste Stunde:** Best Practices — Git, README, SOLID, 12-Factor.