339 lines
6.2 KiB
Markdown
339 lines
6.2 KiB
Markdown
---
|
||
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: #005f8a;
|
||
--color-dimmed: #4a6a7a;
|
||
}
|
||
section.invert {
|
||
--color-foreground: #fff;
|
||
}
|
||
section {
|
||
font-size: 1.7rem;
|
||
}
|
||
h1 {
|
||
color: #005f8a;
|
||
}
|
||
section.invert h1 {
|
||
color: #fff;
|
||
}
|
||
pre {
|
||
background: #0f1e2e;
|
||
color: #00b4d8;
|
||
border-radius: 8px;
|
||
border-left: 3px solid #005f8a;
|
||
}
|
||
pre code {
|
||
background: transparent;
|
||
color: inherit;
|
||
}
|
||
code {
|
||
background: #1a3a4a;
|
||
color: #00b4d8;
|
||
padding: 0.15em 0.4em;
|
||
border-radius: 4px;
|
||
}
|
||
a {
|
||
color: var(--color-highlight);
|
||
}
|
||
</style>
|
||
|
||
<!-- _class: invert -->
|
||
<!-- _header: '' -->
|
||
<!-- _backgroundColor: #001520 -->
|
||
|
||
# Docker
|
||
|
||
## Service Orchestration
|
||
|
||
---
|
||
|
||
# Inhalt
|
||
|
||
1. Architektur: Reverse Proxy + API + DB
|
||
2. Container vs VM
|
||
3. `Dockerfile`
|
||
4. `compose.yml`
|
||
5. Docker CLI / Compose Befehle
|
||
6. Live Demo: `dhbw-docker`
|
||
|
||
---
|
||
|
||
# Architektur
|
||
|
||
```
|
||
Browser (localhost:10007)
|
||
│
|
||
▼
|
||
┌──────────────────┐
|
||
│ Reverse Proxy │ (nginx / traefik)
|
||
└─────────┬────────┘
|
||
┌────┴────┐
|
||
▼ ▼
|
||
┌─────────┐ ┌────────┐
|
||
│ Web │ │ API │
|
||
│ App │ │ (Node) │
|
||
└────┬────┘ └────┬───┘
|
||
└─────┬──────┘
|
||
▼
|
||
┌────────┐
|
||
│ DB │ (Postgres)
|
||
└────────┘
|
||
```
|
||
|
||
---
|
||
|
||
# Container vs VM
|
||
|
||
| | VM | Container |
|
||
|---|----|-----------|
|
||
| Kernel | eigener | Host-Kernel |
|
||
| Boot | Minuten | Sekunden |
|
||
| Größe | GB | MB |
|
||
| Isolation | stark | namespaces, cgroups |
|
||
| Image | komplett | Layer (diff) |
|
||
|
||
→ **Docker** = Container-Engine + Image-Format + Registry.
|
||
|
||
---
|
||
|
||
# Dockerfile – Express API
|
||
|
||
```dockerfile
|
||
FROM node:lts-slim AS builder
|
||
|
||
WORKDIR /app
|
||
|
||
COPY ./package*.json ./
|
||
RUN npm ci --no-audit --no-fund --no-progress --loglevel=error
|
||
|
||
COPY ./ ./
|
||
|
||
ENV NODE_ENV="production"
|
||
|
||
EXPOSE 8080
|
||
|
||
CMD ["npm", "start"]
|
||
```
|
||
|
||
**`npm ci`** statt `npm i` für reproduzierbare Builds.
|
||
|
||
---
|
||
|
||
# Multi-Stage Build
|
||
|
||
```dockerfile
|
||
FROM node:lts-slim AS builder
|
||
WORKDIR /app
|
||
COPY package*.json ./
|
||
RUN npm ci
|
||
COPY . .
|
||
RUN npm run build
|
||
|
||
FROM node:lts-slim AS runtime
|
||
WORKDIR /app
|
||
COPY --from=builder /app/dist ./dist
|
||
COPY --from=builder /app/node_modules ./node_modules
|
||
COPY package*.json ./
|
||
EXPOSE 8080
|
||
CMD ["node", "dist/index.js"]
|
||
```
|
||
|
||
→ kleines Final-Image, keine Build-Tools im Runtime.
|
||
|
||
---
|
||
|
||
# .dockerignore
|
||
|
||
```
|
||
node_modules
|
||
dist
|
||
.git
|
||
.env
|
||
*.log
|
||
coverage
|
||
```
|
||
|
||
Spart Build-Kontext und verhindert Geheimnis-Leaks.
|
||
|
||
---
|
||
|
||
# compose.yml – Services
|
||
|
||
```yaml
|
||
name: dhbw-docker-app
|
||
|
||
services:
|
||
api:
|
||
build: ./api
|
||
container_name: dhbw-api
|
||
environment:
|
||
DATABASE_USERNAME: ${DATABASE_USERNAME}
|
||
DATABASE_PASSWORD: ${DATABASE_PASSWORD}
|
||
DATABASE_NAME: ${DATABASE_NAME}
|
||
DATABASE_HOST: db
|
||
DATABASE_PORT: 5432
|
||
ports:
|
||
- "10000:8080"
|
||
networks: [net, data]
|
||
depends_on:
|
||
db:
|
||
condition: service_healthy
|
||
```
|
||
|
||
---
|
||
|
||
# compose.yml – Datenbank + Proxy
|
||
|
||
```yaml
|
||
db:
|
||
image: postgres:16-alpine
|
||
environment:
|
||
POSTGRES_USER: ${DATABASE_USERNAME}
|
||
POSTGRES_PASSWORD: ${DATABASE_PASSWORD}
|
||
POSTGRES_DB: ${DATABASE_NAME}
|
||
volumes:
|
||
- dbdata:/var/lib/postgresql/data
|
||
networks: [data]
|
||
healthcheck:
|
||
test: ["CMD-SHELL", "pg_isready -U $$DATABASE_USERNAME"]
|
||
interval: 5s
|
||
retries: 5
|
||
|
||
proxy:
|
||
image: nginx:alpine
|
||
ports: ["10007:80"]
|
||
volumes: ["./nginx.conf:/etc/nginx/nginx.conf:ro"]
|
||
networks: [net]
|
||
depends_on: [api]
|
||
|
||
volumes:
|
||
dbdata:
|
||
|
||
networks:
|
||
net:
|
||
data:
|
||
```
|
||
|
||
---
|
||
|
||
# Docker Compose – Befehle
|
||
|
||
```bash
|
||
docker compose -p "dhbw-docker-app" \
|
||
-f compose.yml \
|
||
--env-file .env \
|
||
up \
|
||
--build \
|
||
--remove-orphans \
|
||
--force-recreate
|
||
```
|
||
|
||
| Flag | Bedeutung |
|
||
|------|-----------|
|
||
| `-p` | Projektname |
|
||
| `-f` | mehrere Compose-Files möglich |
|
||
| `--env-file` | `.env` einlesen |
|
||
| `--build` | Images neu bauen |
|
||
| `--remove-orphans` | verwaiste Container weg |
|
||
| `--force-recreate` | Container neu starten |
|
||
|
||
---
|
||
|
||
# Compose – Alltag
|
||
|
||
```bash
|
||
docker compose up -d # detached starten
|
||
docker compose ps # Status
|
||
docker compose logs -f api # Logs streamen
|
||
docker compose exec api sh # Shell im Container
|
||
docker compose down -v # Stop + Volumes löschen
|
||
docker compose restart api # Neustart einzelner Service
|
||
```
|
||
|
||
---
|
||
|
||
# Health Checks
|
||
|
||
```yaml
|
||
api:
|
||
healthcheck:
|
||
test: ["CMD", "curl", "-f", "http://localhost:8080/health"]
|
||
interval: 10s
|
||
timeout: 3s
|
||
retries: 3
|
||
start_period: 5s
|
||
```
|
||
|
||
`depends_on: { condition: service_healthy }` wartet, bis Health passt.
|
||
|
||
---
|
||
|
||
# Networks: Segmentierung
|
||
|
||
- **`net`** – öffentlich erreichbar (Proxy ↔ App)
|
||
- **`data`** – nur intern (App ↔ DB)
|
||
- DB ist **nicht** vom Internet erreichbar
|
||
- Service-DNS: `api`, `db`, `proxy` (Container-Name = Hostname)
|
||
|
||
→ Defense in Depth.
|
||
|
||
---
|
||
|
||
# Volumes – Daten persistent
|
||
|
||
```yaml
|
||
volumes:
|
||
dbdata: # benannt
|
||
- ./code:/app # bind mount (dev)
|
||
- /app/node_modules # anonymous (überschreibt bind)
|
||
```
|
||
|
||
`docker compose down` ohne `-v` lässt Volumes leben.
|
||
|
||
---
|
||
|
||
# Live Demo
|
||
|
||
Repo: https://github.com/nextlevelshit/dhbw-docker
|
||
|
||
```bash
|
||
git clone https://github.com/nextlevelshit/dhbw-docker
|
||
cd dhbw-docker
|
||
cp .env.example .env
|
||
docker compose up --build
|
||
```
|
||
|
||
→ http://localhost:10007
|
||
|
||
---
|
||
|
||
# 100 Concepts of Docker (Exkurs)
|
||
|
||
- Image · Container · Volume · Network
|
||
- Dockerfile · Layer Cache · BuildKit
|
||
- Compose · Stack · Swarm · Kubernetes
|
||
- Registry · Tag · Digest
|
||
- Dev/Prod-Parity (12-Factor)
|
||
- Secrets · Configs
|
||
- Logging Drivers
|
||
- Health Checks · Restart Policies
|
||
|
||
---
|
||
|
||
<!-- _class: invert -->
|
||
<!-- _backgroundColor: #001520 -->
|
||
|
||
# Fragen?
|
||
|
||
**Hausaufgabe:** Eigenes Projekt mit `Dockerfile` + `compose.yml` containerisieren.
|