Kubernetes-Manifeste¶
Alle Kubernetes-Ressourcen sind im k8s/-Verzeichnis definiert und werden in nummerierter Reihenfolge angewendet.
Manifestübersicht¶
| Datei | Ressource | Zweck |
|---|---|---|
00-namespace.yaml |
Namespace | Erstellt den jlpt-kanji-Namespace |
01-secrets.yaml |
Secret | Datenbank-URL, JWT-Secret, OpenAI-Schlüssel |
02-postgres-pvc.yaml |
PersistentVolumeClaim | 10Gi Speicher für PostgreSQL |
03-postgres-deployment.yaml |
Deployment + Service | PostgreSQL 15 Datenbank |
04-libretranslate-deployment.yaml |
Deployment + Service | Selbst gehostete Übersetzung (optional) |
05-deployment.yaml |
Deployment | Hauptanwendung (Frontend + Backend Container) |
06-service.yaml |
Service (x2) | Frontend (:80) und Backend (:8080) Services |
07-ingress.yaml |
Ingress | Traefik-Routing für jlpt.iqquest.app |
08-security-middlewares.yaml |
Middleware (CRD) | Ratenbegrenzung und Sicherheitsheader |
ingress-kanjiiq.yaml |
Ingress | Routing für kanjiiq.com-Domains |
ingress-docs.yaml |
Ingress | Routing für docs.kanjiiq.app |
docs-deployment.yaml |
Deployment | Dokumentationsseite |
docs-service.yaml |
Service | Dokumentations-Service |
Erstmalige Bereitstellung¶
Manifeste in Reihenfolge anwenden:
# Create namespace and secrets
kubectl apply -f k8s/00-namespace.yaml
kubectl apply -f k8s/01-secrets.yaml
# Database
kubectl apply -f k8s/02-postgres-pvc.yaml
kubectl apply -f k8s/03-postgres-deployment.yaml
# Application
kubectl apply -f k8s/05-deployment.yaml
kubectl apply -f k8s/06-service.yaml
# Networking
kubectl apply -f k8s/07-ingress.yaml
kubectl apply -f k8s/08-security-middlewares.yaml
kubectl apply -f k8s/ingress-kanjiiq.yaml
Namespace: jlpt-kanji¶
Alle Ressourcen befinden sich in einem einzelnen Namespace:
Dies bietet:
- Ressourcenisolierung von anderen Workloads
- Eingeschränkte RBAC (bei Bedarf)
- Einfache Bereinigung (
kubectl delete namespace jlpt-kanji) - Durchsetzung von Ressourcenkontingenten (bei Bedarf)
Secrets-Verwaltung¶
Sensible Werte werden in Kubernetes Secrets gespeichert (nicht in Git eingecheckt):
apiVersion: v1
kind: Secret
metadata:
name: jlpt-kanji-secrets
namespace: jlpt-kanji
type: Opaque
stringData:
database-url: "postgresql://user:pass@jlpt-postgres:5432/jlpt_flashcard"
jwt-secret: "random-secret-string"
openai-api-key: "sk-..."
Die 01-secrets.yaml im Repository ist eine Vorlage — die tatsächlichen Werte werden manuell auf dem Server angewendet.
Pod-Design¶
Der Hauptanwendungs-Pod führt zwei Container nebeneinander aus:
spec:
replicas: 2
template:
spec:
imagePullSecrets:
- name: forgejo-registry
containers:
- name: backend
image: <registry>/jlpt-kanji-backend:latest
ports:
- containerPort: 8080
resources:
requests: { memory: "256Mi", cpu: "250m" }
limits: { memory: "512Mi", cpu: "500m" }
- name: frontend
image: <registry>/jlpt-kanji-frontend:latest
ports:
- containerPort: 80
resources:
requests: { memory: "128Mi", cpu: "100m" }
limits: { memory: "256Mi", cpu: "200m" }
Gesundheitsprüfungen¶
Beide Container haben Liveness- und Readiness-Probes:
- Liveness: Startet den Container neu, wenn er nicht mehr reagiert (alle 10s, 3 Fehlschläge)
- Readiness: Entfernt den Pod aus den Service-Endpunkten, bis er bereit ist (alle 5s, 2 Fehlschläge)
Sicherheitskontext¶
Alle Container laufen als Non-Root (UID 1000):
Services¶
Zwei ClusterIP-Services stellen die Container des Pods dem Cluster zur Verfügung:
# Frontend service (port 80 → 80)
name: jlpt-kanji-frontend
ports:
- port: 80
targetPort: 80
# Backend service (port 80 → 8080)
name: jlpt-kanji-backend
ports:
- port: 80
targetPort: 8080
Der Backend-Service bildet den externen Port 80 auf den internen Port 8080 ab, sodass Traefik alle Services auf demselben Port ansteuert.
Ingress¶
Host-basiertes Routing über Traefik:
spec:
ingressClassName: traefik
tls:
- hosts:
- kanjiiq.com
- api.kanjiiq.com
- admin.kanjiiq.com
secretName: kanjiiq-tls
rules:
- host: kanjiiq.com → jlpt-kanji-frontend:80
- host: api.kanjiiq.com → jlpt-kanji-backend:80
- host: admin.kanjiiq.com → jlpt-kanji-backend:80
TLS-Zertifikate werden automatisch von cert-manager bereitgestellt, wenn der Ingress erstellt wird.