Kubernetes-Betrieb

Nutzen Sie diese Anleitung, wenn Sie Workspace mit externer PostgreSQL-Datenbank, PersistentVolume und Ingress in Kubernetes betreiben. Der Pod startet über nucleus-server onboard; Kubernetes gibt ihn erst nach /health/ready = 200 für Traffic frei.

Für einen lokalen Test nutzen Sie Docker-Demo in 10 Minuten.

kubernetes_first_install ingress Ingress TLS und Host service Service 8443 ingress->service pod Workspace Pod onboard service->pod pvc PVC Konfiguration, Key, Storage pod->pvc postgres PostgreSQL pod->postgres

Voraussetzungen

Sie benötigen:

  • einen Namespace und eine IngressClass;
  • eine externe PostgreSQL-Datenbank;
  • eine ReadWriteOnce-StorageClass;
  • einen festen Workspace-Release-Tag;
  • einen öffentlichen Host und TLS;
  • eine Secret-Verwaltung für Datenbankpasswort und Root-Key.

Verwenden Sie für produktive Rollouts niemals latest:

text
git.schukai.me/releases/nucleus:7.29.10

Bootstrap-Strategie wählen

Für die allererste Installation gibt es zwei sichere Wege:

SituationVorgehen
Neuer Root-Key darf im PVC entstehenMounten Sie /data, starten Sie onboard und übernehmen Sie den erzeugten Key anschließend kontrolliert in den Secret-Manager.
Secret-Manager ist bereits verbindlichErzeugen Sie den Root-Key außerhalb des Pods, mounten Sie ihn als /run/secrets/nucleus-key mit Modus 0600 und setzen Sie NUCLEUS_KEY_FILE.

Das ausgelieferte Deployment und der Update-Preflight deaktivieren automountServiceAccountToken. Beide Prozesse benötigen keinen Zugriff auf die Kubernetes-API. Dadurch erhält der Pod keine unnötigen Cluster-Credentials und der Datenbank-Secret-Mount unter /run/secrets kollidiert nicht mit dem üblichen ServiceAccount-Mount unter /var/run/secrets.

Ein ausdrücklich konfigurierter Key-Dateipfad fällt nicht auf einen anderen Provider zurück. Fehlt der Mount, stoppt der Pod.

Beispielmanifest

Das folgende Beispiel zeigt den Laufzeitvertrag für einen Root-Key im PVC. Ersetzen Sie Host, StorageClass, Image-Version und Datenbankwerte. Legen Sie workspace-secrets mit dem Eintrag database-credential vorab über Ihren Secret-Controller an; das Manifest enthält bewusst keinen Secret-Wert.

yaml
apiVersion: v1
kind: Namespace
metadata:
  name: workspace
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: workspace-data
  namespace: workspace
spec:
  accessModes: [ReadWriteOnce]
  resources:
    requests:
      storage: 20Gi
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: workspace
  namespace: workspace
spec:
  replicas: 1
  strategy:
    type: Recreate
  selector:
    matchLabels:
      app: workspace
  template:
    metadata:
      labels:
        app: workspace
    spec:
      securityContext:
        fsGroup: 1000
      containers:
        - name: workspace
          image: git.schukai.me/releases/nucleus:7.29.10
          imagePullPolicy: IfNotPresent
          args: ["onboard", "--profile", "self-hosted"]
          ports:
            - name: https
              containerPort: 8443
          env:
            - name: NUCLEUS_CONFIG
              value: /data/nucleus.config.enc
            - name: NUCLEUS_PUBLIC_URL
              value: https://workspace.example.com
            - name: NUCLEUS_SERVER_LISTEN
              value: :8443
            - name: NUCLEUS_DB_HOST
              value: postgres.example.internal
            - name: NUCLEUS_DB_PORT
              value: "5432"
            - name: NUCLEUS_DB_USER
              value: nucleus
            - name: NUCLEUS_DB_NAME
              value: nucleus
            - name: NUCLEUS_DB_PASSWORD
              valueFrom:
                secretKeyRef:
                  name: workspace-secrets
                  key: database-credential
          volumeMounts:
            - name: data
              mountPath: /data
          startupProbe:
            httpGet:
              path: /health/live
              port: https
              scheme: HTTPS
            periodSeconds: 10
            failureThreshold: 90
          readinessProbe:
            httpGet:
              path: /health/ready
              port: https
              scheme: HTTPS
            periodSeconds: 10
            failureThreshold: 3
          livenessProbe:
            httpGet:
              path: /health/live
              port: https
              scheme: HTTPS
            periodSeconds: 30
            failureThreshold: 3
          securityContext:
            runAsNonRoot: true
            runAsUser: 1000
            runAsGroup: 1000
            allowPrivilegeEscalation: false
      volumes:
        - name: data
          persistentVolumeClaim:
            claimName: workspace-data
---
apiVersion: v1
kind: Service
metadata:
  name: workspace
  namespace: workspace
spec:
  selector:
    app: workspace
  ports:
    - name: https
      port: 8443
      targetPort: https

Ingress

Leiten Sie den öffentlichen Host auf Service-Port 8443. Der Beispielserver spricht dort HTTPS. Konfigurieren Sie Ihren Ingress passend für ein HTTPS-Upstream und bewahren Sie Host sowie X-Forwarded-Proto.

Setzen Sie NUCLEUS_PUBLIC_URL exakt auf den öffentlichen Browser-Ursprung.

Rollout prüfen

bash
kubectl -n workspace get pods
kubectl -n workspace logs deployment/workspace --tail=200
kubectl -n workspace port-forward service/workspace 18443:8443
kubectl -n workspace cp deployment/workspace:/data/nucleus.crt ./nucleus.crt

Prüfen Sie lokal:

bash
curl --cacert ./nucleus.crt --resolve workspace.example.com:18443:127.0.0.1 \
  -sS -i https://workspace.example.com:18443/health/live
curl --cacert ./nucleus.crt --resolve workspace.example.com:18443:127.0.0.1 \
  -sS -i https://workspace.example.com:18443/health/ready
curl --cacert ./nucleus.crt --resolve workspace.example.com:18443:127.0.0.1 \
  -sS https://workspace.example.com:18443/health/product-release

Die startupProbe erlaubt bis zu 15 Minuten für den ersten Schemaaufbau. readinessProbe verhindert während Product-Release-Maintenance neuen Business-Traffic. livenessProbe darf den Pod in dieser Phase nicht unnötig neu starten.

Updates und Rollback

Betreiben Sie während buildgebundener Produktübergänge zunächst nur eine schreibende Instanz. Ändern Sie ausschließlich den festen Image-Tag und beobachten Sie /health/ready.

Ein Datenbankstand ist nicht automatisch mit einer älteren Binary kompatibel. Planen Sie Rollback mit Backup und den unterstützten Quellversionen aus Produktupdates ohne manuelle Nacharbeit.

Fehler einordnen

SymptomNächster Schritt
Pod bleibt PendingPrüfen Sie PVC, StorageClass und Ressourcen.
Pod startet wegen Root-Key nichtPrüfen Sie Secret-Mount, Dateipfad, Besitzer und Modus 0600.
/health/live = 200, /health/ready = 503Prüfen Sie /health/product-release und die geschützte Release-Diagnose.
Wiederholte Neustarts während ErststartVerlängern Sie die startupProbe; verwenden Sie Liveness nicht als Readiness.
Product Release ist terminal failedFolgen Sie Komponente und Aktionshinweis; führen Sie keinen direkten SQL-Fix aus.

Erfolgskriterien

Der Rollout ist abgeschlossen, wenn:

  • der Pod ohne Root-Rechte läuft;
  • PVC und Secrets gemountet sind;
  • /health/live und /health/ready HTTP 200 liefern;
  • der Service nur Port 8443 veröffentlicht;
  • der Ingress den festen Host mit TLS bedient;
  • das Image auf einen festen Release-Tag zeigt.

Nächste Schritte