refactor(k8s): Aufbau wie Wabenhain/ApiCore, Zertifikat funktionsfaehig
Docker-Images bauen und veroeffentlichen / build-and-push (push) Successful in 3m2s
Docker-Images bauen und veroeffentlichen / build-and-push (push) Successful in 3m2s
- Dateinamen nach Wabenhain-Schema (01-configmap, 02-secret, 03-storage, 04-postgres, 05-app-deployment, 06-ingress, 07-worker-cronjob, 08-networkpolicy); Secret-Vorlage als 02-secret.yaml.example, echte 02-secret.yaml gitignored. - Namespace: Pod Security "baseline" erzwungen, "restricted" als warn/audit. "restricted" kann den HTTP-01-Solver-Pod von cert-manager abweisen und damit die Zertifikatsausstellung blockieren. - NetworkPolicy nur noch fuer PostgreSQL; keine Policy vor der App (wie Wabenhain/ApiCore), da sie bei Traefik im Host-Netzwerk die Seite sperrt. - README: kompletter Neuaufbau inkl. Freigabe der Retain-PVs nach "kubectl delete namespace", Zertifikats-Diagnose. Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
This commit is contained in:
1 parent
d813d56514
commit
a0ba921d19
12 files changed
+70
-71
No files matched your search
+2
-2
@@ -24,5 +24,5 @@ npm-debug.log*
|
|||||||
# Laufzeit-Cache des Design-Hooks (impeccable)
|
# Laufzeit-Cache des Design-Hooks (impeccable)
|
||||||
.impeccable/hook.cache.json
|
.impeccable/hook.cache.json
|
||||||
|
|
||||||
# Echte Kubernetes-Secrets (Vorlage: k8s/secrets.yaml.example)
|
# Echte Kubernetes-Secrets (Vorlage: k8s/02-secret.yaml.example)
|
||||||
k8s/secrets.yaml
|
k8s/02-secret.yaml
|
||||||
@@ -1,6 +1,13 @@
|
|||||||
|
# Pod Security: "baseline" wird erzwungen (blockiert privilegierte Pods,
|
||||||
|
# hostPath, Host-Netzwerk usw.), laesst aber den HTTP-01-Solver-Pod von
|
||||||
|
# cert-manager zu. "restricted" wird gemeldet (warn/audit); die eigenen Pods
|
||||||
|
# dieses Namespaces erfuellen es bereits (non-root, keine Capabilities,
|
||||||
|
# seccomp RuntimeDefault).
|
||||||
apiVersion: v1
|
apiVersion: v1
|
||||||
kind: Namespace
|
kind: Namespace
|
||||||
metadata:
|
metadata:
|
||||||
name: artista
|
name: artista
|
||||||
labels:
|
labels:
|
||||||
pod-security.kubernetes.io/enforce: restricted
|
pod-security.kubernetes.io/enforce: baseline
|
||||||
|
pod-security.kubernetes.io/warn: restricted
|
||||||
|
pod-security.kubernetes.io/audit: restricted
|
||||||
File renamed without changes.
@@ -1,5 +1,5 @@
|
|||||||
# Kopieren nach k8s/secrets.yaml (ist in .gitignore), Werte eintragen,
|
# Kopieren nach k8s/02-secret.yaml (ist in .gitignore), Werte eintragen,
|
||||||
# dann: kubectl apply -f k8s/secrets.yaml
|
# dann: kubectl apply -f k8s/02-secret.yaml
|
||||||
# Zufallswerte: openssl rand -base64 48
|
# Zufallswerte: openssl rand -base64 48
|
||||||
apiVersion: v1
|
apiVersion: v1
|
||||||
kind: Secret
|
kind: Secret
|
||||||
@@ -17,7 +17,7 @@ stringData:
|
|||||||
SMTP_USER: "benutzer"
|
SMTP_USER: "benutzer"
|
||||||
SMTP_PASSWORD: "passwort"
|
SMTP_PASSWORD: "passwort"
|
||||||
---
|
---
|
||||||
# Zugang zur SMB-Freigabe (fuer 02-storage.yaml)
|
# Zugang zur SMB-Freigabe (fuer 03-storage.yaml)
|
||||||
apiVersion: v1
|
apiVersion: v1
|
||||||
kind: Secret
|
kind: Secret
|
||||||
metadata:
|
metadata:
|
||||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
@@ -1,5 +1,5 @@
|
|||||||
# Ingress fuer Traefik + cert-manager (gleiches Muster wie Wabenhain).
|
# Ingress fuer Traefik + cert-manager (gleiches Muster wie Wabenhain).
|
||||||
# ANPASSEN: Domain (2x, auch APP_URL in 01-config.yaml).
|
# ANPASSEN: Domain (2x, auch APP_URL in 01-configmap.yaml).
|
||||||
apiVersion: networking.k8s.io/v1
|
apiVersion: networking.k8s.io/v1
|
||||||
kind: Ingress
|
kind: Ingress
|
||||||
metadata:
|
metadata:
|
||||||
@@ -1,47 +0,0 @@
|
|||||||
# Datenbank nur fuer App und Worker erreichbar; App nur ueber Traefik.
|
|
||||||
# Traefik wird an Namespace (traefik oder kube-system) UND Pod-Label erkannt
|
|
||||||
# (eigene Installation "traefik" oder RKE2-Paket "rke2-traefik"). Laeuft
|
|
||||||
# Traefik in einem anderen Namespace: dessen Namen unten ergaenzen.
|
|
||||||
# Pruefen: kubectl get pods -A -l 'app.kubernetes.io/name in (traefik,rke2-traefik)'
|
|
||||||
apiVersion: networking.k8s.io/v1
|
|
||||||
kind: NetworkPolicy
|
|
||||||
metadata:
|
|
||||||
name: artista-modelcamp-postgres
|
|
||||||
namespace: artista
|
|
||||||
spec:
|
|
||||||
podSelector:
|
|
||||||
matchLabels:
|
|
||||||
app: artista-modelcamp-postgres
|
|
||||||
ingress:
|
|
||||||
- from:
|
|
||||||
- podSelector:
|
|
||||||
matchLabels:
|
|
||||||
db-client: "true"
|
|
||||||
ports:
|
|
||||||
- port: 5432
|
|
||||||
---
|
|
||||||
apiVersion: networking.k8s.io/v1
|
|
||||||
kind: NetworkPolicy
|
|
||||||
metadata:
|
|
||||||
name: artista-modelcamp-app
|
|
||||||
namespace: artista
|
|
||||||
spec:
|
|
||||||
podSelector:
|
|
||||||
matchLabels:
|
|
||||||
app: artista-modelcamp-app
|
|
||||||
ingress:
|
|
||||||
- from:
|
|
||||||
# Namespace UND Pod-Label muessen passen: ein Label allein koennte
|
|
||||||
# jeder setzen, der irgendwo Pods starten darf.
|
|
||||||
- namespaceSelector:
|
|
||||||
matchExpressions:
|
|
||||||
- key: kubernetes.io/metadata.name
|
|
||||||
operator: In
|
|
||||||
values: [traefik, kube-system]
|
|
||||||
podSelector:
|
|
||||||
matchExpressions:
|
|
||||||
- key: app.kubernetes.io/name
|
|
||||||
operator: In
|
|
||||||
values: [traefik, rke2-traefik]
|
|
||||||
ports:
|
|
||||||
- port: 3000
|
|
||||||
File renamed without changes.
@@ -0,0 +1,23 @@
|
|||||||
|
# Die Datenbank ist nur fuer Pods mit dem Label db-client=true erreichbar
|
||||||
|
# (App inkl. Migration, Worker, Admin-Anlage). Beruehrt weder Traefik noch
|
||||||
|
# cert-manager.
|
||||||
|
#
|
||||||
|
# Bewusst KEINE Policy vor der App (wie bei Wabenhain/ApiCore): laeuft
|
||||||
|
# Traefik im Host-Netzwerk, wuerde sie die Website aussperren.
|
||||||
|
apiVersion: networking.k8s.io/v1
|
||||||
|
kind: NetworkPolicy
|
||||||
|
metadata:
|
||||||
|
name: artista-modelcamp-postgres
|
||||||
|
namespace: artista
|
||||||
|
spec:
|
||||||
|
podSelector:
|
||||||
|
matchLabels:
|
||||||
|
app: artista-modelcamp-postgres
|
||||||
|
policyTypes: ["Ingress"]
|
||||||
|
ingress:
|
||||||
|
- from:
|
||||||
|
- podSelector:
|
||||||
|
matchLabels:
|
||||||
|
db-client: "true"
|
||||||
|
ports:
|
||||||
|
- port: 5432
|
||||||
+33
-17
@@ -10,7 +10,7 @@ Prüfen:
|
|||||||
```bash
|
```bash
|
||||||
kubectl get ingressclass
|
kubectl get ingressclass
|
||||||
kubectl get clusterissuer letsencrypt-prod
|
kubectl get clusterissuer letsencrypt-prod
|
||||||
kubectl get pods -A -l 'app.kubernetes.io/name in (traefik,rke2-traefik)'
|
kubectl get csidrivers | grep smb
|
||||||
```
|
```
|
||||||
|
|
||||||
## Einmalige Vorbereitung
|
## Einmalige Vorbereitung
|
||||||
@@ -21,26 +21,40 @@ kubectl get pods -A -l 'app.kubernetes.io/name in (traefik,rke2-traefik)'
|
|||||||
helm repo add csi-driver-smb https://raw.githubusercontent.com/kubernetes-csi/csi-driver-smb/master/charts
|
helm repo add csi-driver-smb https://raw.githubusercontent.com/kubernetes-csi/csi-driver-smb/master/charts
|
||||||
helm install csi-driver-smb csi-driver-smb/csi-driver-smb -n kube-system
|
helm install csi-driver-smb csi-driver-smb/csi-driver-smb -n kube-system
|
||||||
```
|
```
|
||||||
3. **NAS:** Die Ordner `artista/modelcamp-postgres` (leer) und `artista/modelcamp-media` anlegen und SMB-Verschlüsselung erlauben. `nas.example.lan` in `02-storage.yaml` anpassen.
|
3. **NAS:** Die Ordner `artista/modelcamp-postgres` (leer) und `artista/modelcamp-media` anlegen und SMB-Verschlüsselung erlauben. `nas.example.lan` in `03-storage.yaml` anpassen.
|
||||||
4. **Domain:** `modelcamp.example.org` in `01-config.yaml` (APP_URL) und `05-ingress.yaml` (2×) ersetzen. Der DNS-Eintrag muss auf den Cluster zeigen, sonst stellt cert-manager kein Zertifikat aus.
|
4. **Domain:** `modelcamp.example.org` in `01-configmap.yaml` (APP_URL) und `06-ingress.yaml` (2×) ersetzen. Der DNS-Eintrag muss auf den Cluster zeigen, sonst stellt cert-manager kein Zertifikat aus.
|
||||||
5. **Secrets:** `cp k8s/secrets.yaml.example k8s/secrets.yaml` und ausfüllen. Die Datei steht in `.gitignore`, bitte **nie** mit echten Werten committen.
|
5. **Secrets:** `cp k8s/02-secret.yaml.example k8s/02-secret.yaml` und ausfüllen. Die Datei steht in `.gitignore`, bitte **nie** mit echten Werten committen.
|
||||||
|
|
||||||
## Deployment
|
## Deployment (auch für einen kompletten Neuaufbau)
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
kubectl apply -f k8s/00-namespace.yaml
|
kubectl apply -f k8s/00-namespace.yaml
|
||||||
kubectl apply -f k8s/secrets.yaml
|
kubectl apply -f k8s/01-configmap.yaml
|
||||||
kubectl apply -f k8s/01-config.yaml
|
kubectl apply -f k8s/02-secret.yaml
|
||||||
kubectl apply -f k8s/02-storage.yaml
|
kubectl apply -f k8s/03-storage.yaml
|
||||||
kubectl apply -f k8s/03-postgres.yaml
|
kubectl apply -f k8s/04-postgres.yaml
|
||||||
kubectl wait --for=condition=ready pod -l app=artista-modelcamp-postgres -n artista --timeout=180s
|
kubectl wait --for=condition=ready pod -l app=artista-modelcamp-postgres -n artista --timeout=180s
|
||||||
kubectl apply -f k8s/04-app.yaml
|
kubectl apply -f k8s/05-app-deployment.yaml
|
||||||
kubectl apply -f k8s/05-ingress.yaml
|
kubectl apply -f k8s/06-ingress.yaml
|
||||||
kubectl apply -f k8s/06-worker.yaml
|
kubectl apply -f k8s/07-worker-cronjob.yaml
|
||||||
kubectl apply -f k8s/07-networkpolicy.yaml
|
kubectl apply -f k8s/08-networkpolicy.yaml
|
||||||
```
|
```
|
||||||
|
|
||||||
Die Migration läuft automatisch als initContainer vor dem App-Start. Den Fortschritt zeigt `kubectl rollout status deployment/artista-modelcamp-app -n artista`, das Zertifikat `kubectl get certificate -n artista`.
|
Die Migration läuft automatisch als initContainer vor dem App-Start. Den Stand zeigen:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
kubectl rollout status deployment/artista-modelcamp-app -n artista
|
||||||
|
kubectl get certificate -n artista # READY muss True werden (meist < 2 Minuten)
|
||||||
|
```
|
||||||
|
|
||||||
|
**Neuaufbau mit `kubectl delete namespace artista`:** Die PersistentVolumes (`artista-modelcamp-postgres`, `artista-modelcamp-media`) gehören keinem Namespace und bleiben auf `Released` stehen. Die Daten auf dem NAS bleiben erhalten (`Retain`). Damit die neuen Claims sie wieder binden können, vor dem erneuten Anlegen:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
kubectl patch pv artista-modelcamp-postgres -p '{"spec":{"claimRef":null}}'
|
||||||
|
kubectl patch pv artista-modelcamp-media -p '{"spec":{"claimRef":null}}'
|
||||||
|
```
|
||||||
|
|
||||||
|
Soll die Datenbank wirklich leer neu starten, den Ordner `modelcamp-postgres` auf dem NAS vorher leeren.
|
||||||
|
|
||||||
## Erstes Admin-Konto
|
## Erstes Admin-Konto
|
||||||
|
|
||||||
@@ -61,7 +75,9 @@ kubectl rollout restart deployment/artista-modelcamp-app -n artista
|
|||||||
## Fehlersuche
|
## Fehlersuche
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
kubectl -n artista logs deploy/artista-modelcamp-app -c migrate # Migration
|
kubectl -n artista get certificate,certificaterequest,order,challenge # Zertifikat
|
||||||
kubectl -n artista logs deploy/artista-modelcamp-app -c app # App
|
kubectl -n artista describe challenge
|
||||||
kubectl -n artista describe certificate artista-modelcamp-tls # Zertifikat
|
kubectl -n artista logs deploy/artista-modelcamp-app -c migrate # Migration
|
||||||
|
kubectl -n artista logs deploy/artista-modelcamp-app -c app # App
|
||||||
|
kubectl -n artista get events --sort-by=.lastTimestamp | tail -20
|
||||||
```
|
```
|
||||||
Reference in new issue
Block a user