Dieses Dokument wurde mithilfe automatisierter maschineller Übersetzungstechnologie übersetzt. Wir bemühen uns um korrekte Übersetzungen, übernehmen jedoch keine Gewähr für die Vollständigkeit, Richtigkeit oder Zuverlässigkeit der übersetzten Inhalte. Im Falle von Abweichungen ist die englische Originalversion maßgebend und stellt den verbindlichen Text dar.

Entwicklung für Kubernetes

Rancher Desktop – SUSE Application Collection – Tilt

Von der Entwicklungsumgebung bis zur Bereitstellung – Innere Schleife, Einblick, GitOps

1. Überblick: Warum dieser Leitfaden?

Dieser Leitfaden behandelt die komplette Wertschöpfungskette der Kubernetes-Entwicklung, von der anfänglichen Einrichtung der Umgebung bis zur kontinuierlichen Bereitstellung. Das Ziel: einen Entwickler schnell produktiv zu machen, indem beliebte Werkzeuge, ein lokaler Cluster (Rancher Desktop) und vertrauenswürdige Images (SUSE Application Collection) verwendet werden.

Er ist in zwei Teile gegliedert: zuerst eine praktische Demo, die Sie in wenigen Minuten zum Laufen bringt. Dann ein Weiterführender Abschnitt, der das breitere Ökosystem (Dev-Container, Testcontainers, mirrord, Helm, Sicherheit, GitOps) abdeckt, wenn Sie bereit sind, Ihren Workflow zu vertiefen.

1.1 Die beiden Schleifen der cloudnativen Entwicklung

Innere Schleife Äußere Schleife

Was

Der schnelle tägliche Zyklus des Entwicklers: Code schreiben, bauen, lokal bereitstellen, testen, debuggen, iterieren

Der automatisierte Post-Commit-Zyklus: CI/CD, Integrationstests, Sicherheitsprüfungen, Staging/Produktion-Bereitstellung

Zielwert

Feedback in Sekunden

Qualität und Reproduzierbarkeit

Werkzeuge

Tilt, mirrord

Argo CD, GitHub Actions, Tekton

Bereich

Entwicklerarbeitsplatz + lokaler Cluster

CI/CD-Pipeline + Remote-Cluster

Schlüsselprinzip – Die innere Schleife muss so schnell wie möglich sein. Jede Sekunde, die im Code-Bau-Bereitstellungs-Testzyklus eingespart wird, multipliziert sich mit der Anzahl der täglichen Änderungen. Eine gute innere Schleife bedeutet, von 5-10 Minuten auf 5-10 Sekunden pro Iteration zu kommen.

2. Gesamtarchitektur

2.1 Diagramm

Architektur der inneren und äußeren Schleife – dieselben vertrauenswürdigen SUSE-Grundlagen auf beiden Seiten
Figure 1. Architektur der inneren und äußeren Schleife – dieselben vertrauenswürdigen SUSE-Grundlagen auf beiden Seiten

2.2 Stapelschichten

ebene Werkzeug Rolle

IDE

VS Code + Erweiterungen

Editor, Debuggen, integrierte Terminals

Lokaler Cluster

Rancher Desktop (k3s)

Lokales Kubernetes + Container-Laufzeit

Images

SUSE Anwendungssammlung

Basisbilder, Sprachen, Middleware, Werkzeuge

Innere Schleife

Tilt

Automatisches Bauen, automatisches Bereitstellen, Hot Reload

Authentifizierung

Keycloak

OAuth2 / OpenID Connect Identitätsanbieter

Einblick

Prometheus + Grafana

Anwendungsmetriken, Echtzeit-Dashboards

Paketerstellung

Helm / Kustomize

K8s-Manifestvorlagen

Sicherheit

Trivy / Cosign

Schwachstellenscanning, Bildsignierung

GitOps

Argo CD

Deklarative Bereitstellung aus Git

3. Einrichten von Rancher Desktop

3.1 Was ist Rancher Desktop?

Rancher Desktop ist eine Open-Source-Desktopanwendung, die einen lokalen Kubernetes-Cluster (k3s) und eine Container-Laufzeit (dockerd oder containerd) bereitstellt, alles innerhalb einer automatisch verwalteten VM. Es ist nicht erforderlich, Docker Desktop zu installieren.

3.2 Installation und Konfiguration

  1. Herunterladen von rancherdesktop.io.

  2. Wählen Sie die Laufzeit: wählen Sie dockerd (moby) (nicht containerd). Dies ist entscheidend für das Folgende.

  3. Kubernetes aktivieren (standardmäßig aktiviert).

  4. Überprüfen:

    docker info          # shows "Server Version: ..."
    kubectl get nodes    # shows "Ready"
  5. PATH – unter macOS überprüfen Sie, ob ~/.rd/bin/ in Ihrem $PATH ist (automatisch vom Installer hinzugefügt):

    which docker kubectl helm   # should point to ~/.rd/bin/

Rancher Desktop ist nicht Docker Desktop. Sie benötigen Docker Desktop nicht. Rancher Desktop bietet seinen eigenen Docker-Daemon (moby/dockerd) an. Wenn beide installiert sind, kann es zu Konflikten bei den Sockets kommen. Deaktivieren Sie Docker Desktop, wenn Sie es haben.

3.3 Warum dockerd (moby), wenn die Produktion containerd verwendet?

In der Produktion verwendet Kubernetes containerd als Laufzeit. Hier ist die entscheidende Erkenntnis: das tut auch Rancher Desktop, selbst im Moby-Modus. Der k3s-Cluster läuft immer auf containerd, unabhängig von der Einstellung. Die Wahl von “dockerd (moby)” ersetzt containerd nicht – es fügt den Daemon von Docker hinzu, und beide teilen sich denselben Image-Speicher.

Das ist es, was uns das Beste aus beiden Welten gibt: dieselbe Laufzeit wie in der Produktion, plus die entwicklerfreundlichen Werkzeuge von Docker.

Rancher Desktop VM (moby mode):
+---------------------------------------------+
|                                             |
|   dockerd (moby)         k3s (containerd)   |
|   +-- image store <----> image store --+    |
|       (shared)           (same!)       |    |
|                                             |
|   docker build -> image appears in both     |
|   NO PUSH NEEDED!                           |
+---------------------------------------------+

Rancher Desktop VM (containerd mode):
+---------------------------------------------+
|                                             |
|   nerdctl (containerd)   k3s (containerd)   |
|   +-- image store        image store --+    |
|       (separate!)        (separate!)   |    |
|                                             |
|   nerdctl build -> push -> pull -> k3s      |
|   3 steps instead of 1 = slower             |
+---------------------------------------------+

Von Docker erstellte Images sind sofort sichtbar für k3s, da sie denselben Speicher teilen. Kein Registry, kein Push, kein Pull. Das ist es, was die innere Schleife so schnell macht.

Kein Kompromiss bei der Parität. Ihre App läuft in beiden Fällen auf containerd. Der einzige Unterschied ist die Kommandozeilenschnittstelle, die zum Erstellen von Images verwendet wird: docker (Moby-Modus) vs nerdctl (containerd-Modus). Zur Laufzeit verhält sich k3s identisch.

Das ist auch der Grund, warum die Demo-K8s-Deployments imagePullPolicy: IfNotPresent (oder Never) verwenden: Wir sagen k3s “use the local image, do not look in a registry”.

4. SUSE Anwendungssammlung

4.1 Was ist die SUSE Application Collection?

SUSE Application Collection ist eine Sammlung von Anwendungen in Form von Container-Images und Helm-Charts, die von SUSE erstellt, verpackt, gehärtet und gewartet werden – mit SLSA L3-Builds und allen Metadaten, die benötigt werden, um den Betrieb ruhig zu halten. Es ist die vertrauenswürdige Quelle zum Erstellen von Anwendungen auf Kubernetes.

Die Registry ist dp.apps.rancher.io. Hier finden Sie:

  • Basisbilder (BCI) – SUSE Linux Enterprise Basis-Containerbilder: minimale, sichere Grundlagen.

  • Language images – Node.js, Go, Rust, Java, Ruby, Clojure… mit vollständigen Toolchains.

  • Middleware – PostgreSQL, Redis, Kafka, MariaDB, Nats, NGINX, Apache ActiveMQ, Apache Apisix, Apache Tomcat…

  • Werkzeuge – Helm, Trivy, Cosign, kubectl, ArgoCD, Prometheus, Grafana…

Verfügbar in Form von einzelnen Containern oder, wenn relevant, vollwertigen Anwendungen mit Helm-Charts für die Bereitstellung.

Die SUSE Application Collection-Erweiterung in Rancher Desktop fügt eine dedizierte Registerkarte in der Benutzeroberfläche hinzu. Sie durchsuchen den Katalog, konfigurieren Werte und installieren mit einem Klick – die Helm-Komplexität ist verborgen.

4.2 Warum Application Collection über öffentliche Registries?

Öffentliche Registries SUSE Anwendungssammlung

Wartung

Gemeinschaft, variabel

SUSE, Unternehmens-SLA

Basis-OS

Alpine, Debian, Ubuntu…

SLE BCI (SUSE Linux Enterprise)

Sicherheitspatches

Wenn der Maintainer es möchte

Kontinuierliches CVE-Tracking durch SUSE

Signieren

Optional

Cosign integriert

Lieferkette

Variable

SBOM, Provenance, Attestierungen, SLSA L3

4.3 Authentifizierung

Die Authentifizierung für die SUSE Application Collection Registry wird automatisch über die SUSE Application Collection-Erweiterung in Rancher Desktop konfiguriert.

Überprüfen Sie, ob es funktioniert:

docker pull dp.apps.rancher.io/containers/bci-base:latest

Wenn die Authentifizierung nicht konfiguriert ist, fügen Sie sie manuell hinzu:

# Log in to the registry (SUSE Customer Center credentials)
docker login dp.apps.rancher.io

# Verify
docker pull dp.apps.rancher.io/containers/bci-base:latest

Für Kubernetes (helm install, Pods) – ein Pull-Secret ist erforderlich, wenn die Images nicht bereits heruntergeladen wurden. Rancher Desktop erledigt dies automatisch über die Erweiterung. Wenn es ein Problem gibt:

kubectl create secret docker-registry application-collection \
  --docker-server=dp.apps.rancher.io \
  --docker-username=<USERNAME> \
  --docker-password=<PASSWORD>

Fügen Sie dann imagePullSecrets: [{name: application-collection}] in Ihre Helm-Werte ein.

5. Tilt installieren

Tilt ist ein Open-Source-Tool, das jeden Schritt der inneren Schleife automatisiert, von der Codeänderung bis zur erneuten Bereitstellung. Es überwacht Ihre Dateien, baut Images neu, aktualisiert den Cluster und zeigt alles in einem Echtzeit-Dashboard an. Siehe tilt.dev.

5.1 macOS

brew install tilt

5.2 Linux (SUSE und andere)

curl -fsSL https://raw.githubusercontent.com/tilt-dev/tilt/master/scripts/install.sh | bash

Das Skript erkennt Ihre Architektur und platziert die Binärdatei in Ihrem $PATH (~/.local/bin, /usr/local/bin oder ~/bin). Überprüfen:

tilt version

5.3 Windows

In PowerShell:

iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/tilt-dev/tilt/master/scripts/install.ps1'))

Wenn Sie Scoop installiert haben, wird das Skript es automatisch verwenden. Andernfalls müssen Sie möglicherweise das Installationsverzeichnis zu Ihrem $PATH hinzufügen. Überprüfen:

tilt version

5.4 Tilt + Rancher Desktop

Tilt läuft auf dem Host (nicht in einem Container) und verwendet direkt die von Rancher Desktop installierten Kommandozeilenschnittstellen: docker, kubectl, helm. Es erkennt automatisch Rancher Desktop (seit Tilt v0.25.1+), wenn die Laufzeit dockerd ist. Es weiß dann, dass lokal erstellte Images direkt im Cluster verfügbar sind, und überspringt den Push.

Wenn Tilt Ihr Cluster nicht automatisch erkennt, fügen Sie diese Zeile oben in die Tiltfile ein:

allow_k8s_contexts('rancher-desktop')

6. Die Demo: Nachrichtenwand mit Einblick

Dieser Abschnitt führt durch die vollständige Demo. Es zeigt den inneren Loop-Workflow: eine Node.js “message wall”-Anwendung, die mit PostgreSQL verbunden ist, mit Keycloak zur Authentifizierung, instrumentiert mit Prometheus und in Grafana visualisiert. Alles wird aus der SUSE Application Collection installiert.

Der vollständige Quellcode ist auf GitHub verfügbar: fxHouard/Rancher-Developer-Access-Demo.

6.1 Projektstruktur

Rancher-Developer-Access-Demo/
+-- src/
|   +-- server.js               Application (API + UI + Prometheus metrics)
+-- k8s/
|   +-- appco/
|   |   +-- deployment.yaml     Pod spec with Prometheus annotations
|   |   +-- service.yaml        ClusterIP service
|   |   +-- keycloak.yaml       Keycloak Deployment + Service (Application Collection image)
|   +-- shared/
|       +-- grafana-dashboard.yaml   8-panel dashboard (auto-provisioned via sidecar)
|       +-- keycloak-realm.json      Realm config (demo user + OAuth client)
+-- scripts/
|   +-- setup-keycloak-realm.sh      Keycloak realm import via Admin REST API
+-- values_yaml/
|   +-- postgresql.yaml          Helm values for PostgreSQL
|   +-- prometheus.yaml          Helm values for Prometheus
|   +-- grafana.yaml             Helm values for Grafana
+-- Dockerfile                   Container image (Application Collection base)
+-- Tiltfile                     Inner loop config (build, deploy, sync, monitoring)
+-- package.json

6.2 Die package.json

{
  "name": "message-wall",
  "version": "1.0.0",
  "description": "SUSE Rancher Developer Access + Tilt: Demo",
  "main": "src/server.js",
  "scripts": {
    "start": "node src/server.js"
  },
  "dependencies": {
    "pg": "^8.13.0",
    "prom-client": "^15.1.0"
  }
}

Nur zwei Abhängigkeiten: pg für PostgreSQL und prom-client, um Prometheus-Metriken bereitzustellen.

6.3 Die Anwendung (src/server.js)

Die Anwendung ist eine interaktive Nachrichtenwand mit einer integrierten Web-UI. Sie stellt Prometheus-Metriken für den Einblick bereit. Hier sind die wichtigsten Teile – die vollständige Datei befindet sich im Repo.

Konfiguration und Prometheus-Metriken:

const http = require('http');
const { Client } = require('pg');
const promClient = require('prom-client');

const PORT = 3000;

// Change this color, save, see it update!
const ACCENT_COLOR = "#747dcd";

// --- Prometheus metrics ---
// collectDefaultMetrics() automatically exposes Node.js
// metrics: CPU, heap memory, event loop lag, GC...
promClient.collectDefaultMetrics();

// Custom metrics -- prefixed "app_" for easy discovery
const httpDuration = new promClient.Histogram({
  name: 'app_http_request_duration_seconds',
  help: 'Duration of HTTP requests in seconds',
  labelNames: ['method', 'path', 'status'],
  buckets: [0.005, 0.01, 0.05, 0.1, 0.5, 1],
});

const messagesPosted = new promClient.Counter({
  name: 'app_messages_posted_total',
  help: 'Total number of messages posted',
});

const messagesDeleted = new promClient.Counter({
  name: 'app_messages_deleted_total',
  help: 'Total number of bulk deletes',
});

const messagesCurrent = new promClient.Gauge({
  name: 'app_messages_count',
  help: 'Current number of messages in the database',
});

Warum das app_ Präfix? – Prometheus sammelt Hunderte von Metriken (Node.js, k8s, System…). Das app_-Präfix ermöglicht es Ihnen, Ihre Anwendungsmetriken sofort zu finden: Geben Sie app_ in Grafana ein und die Autovervollständigung erledigt den Rest.

Prometheus Metriktypen:

Typ Verwendung Demobeispiel

+++Counter

Wert, der nur steigt

app_messages_posted_total – insgesamt veröffentlichte Nachrichten

Messwert

Wert, der steigt und fällt

app_messages_count – aktuelle Nachrichten in der Datenbank

Histogramm

Verteilung der Werte (Latenz)

app_http_request_duration_seconds – Antwortzeit pro Route

API-Routen:

Die Anwendung stellt 6 Routen zur Verfügung: GET / dient der HTML-Seite, GET /api/messages listet die 50 neuesten Nachrichten auf, POST /api/messages erstellt eine Nachricht (280 Zeichen Limit), DELETE /api/messages löscht alle Nachrichten, GET /health dient als K8s-Prüfung (Liveness + Readiness) und GET /metrics stellt Prometheus-Metriken im Textformat zur Verfügung.

Der /metrics Endpunkt:

if (req.method === 'GET' && req.url === '/metrics') {
  const metrics = await promClient.register.metrics();
  res.writeHead(200, { 'Content-Type': promClient.register.contentType });
  res.end(metrics);
  // Do not record /metrics in the histogram (noise)
  return;
}

Dies ist der Endpunkt, den Prometheus regelmäßig abruft. Er gibt alle Metriken im OpenMetrics-Textformat zurück. Beachten Sie, dass /metrics selbst nicht vom Histogramm gemessen wird – das wäre Rauschen.

The measurement middleware:
Die Mess-Middleware:

Jede HTTP-Anfrage wird automatisch zeitlich erfasst:

const end = httpDuration.startTimer();
// ... request processing ...
end({ method: req.method, path: routePath, status: statusCode });

Das Histogramm zeichnet die Dauer, Methode, den Pfad und den Rückgabecode auf. Grafana kann dann Perzentile (p50, p95, p99) pro Route berechnen.

Die HTML-Seite:

Die Anwendung dient einer interaktiven Nachrichtenwand, die direkt von Node.js (Inline-HTML in server.js) bereitgestellt wird. Die Benutzeroberfläche umfasst ein Eingabefeld, eine Informationsleiste, die den Pod-Namen und die Betriebszeit anzeigt, sowie eine automatische Abfrage alle 3 Sekunden mit intelligentem Diffing (nur Zeitstempel werden aktualisiert, wenn sich die Nachrichten nicht geändert haben, kein Flackern).

live_update-Demo – Ändern Sie die Konstante ACCENT_COLOR in Zeile 9 und speichern Sie. In ~2 Sekunden ändert sich die Wandfarbe, ohne dass Nachrichten verloren gehen. Das ist Tilt’s live_update in Aktion.

6.4 Das Dockerfile

FROM dp.apps.rancher.io/containers/nodejs:24-dev
WORKDIR /app
COPY package.json ./
RUN npm install --no-package-lock
COPY . .
EXPOSE 3000
CMD ["node", "src/server.js"]

In der Produktion würden Sie einen Multi-Stage-Build verwenden, um den npm install-Schritt (Entwicklungsimage mit npm) vom finalen Image (minimales nodejs:24-Image, ohne npm oder Build-Tools) zu trennen. Hier behalten wir ein einfaches Dockerfile für die Demo. Siehe Weiterführend: minimale Images.

6.5 Die Kubernetes-Manifeste

k8s/deployment.yaml:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: message-wall
spec:
  replicas: 1
  selector:
    matchLabels:
      app: message-wall
  template:
    metadata:
      labels:
        app: message-wall
      annotations:
        prometheus.io/scrape: "true"
        prometheus.io/port: "3000"
        prometheus.io/path: "/metrics"
    spec:
      containers:
        - name: message-wall
          image: message-wall           # Tilt replaces with local image
          ports:
            - containerPort: 3000
          env:
            - name: DB_HOST
              value: "demo-db-postgresql"
            - name: DB_PORT
              value: "5432"
            - name: DB_USER
              value: "demo"
            - name: DB_PASSWORD
              value: "demo"
            - name: DB_NAME
              value: "demo"
          livenessProbe:
            httpGet:
              path: /health
              port: 3000
            initialDelaySeconds: 5
          readinessProbe:
            httpGet:
              path: /health
              port: 3000
            initialDelaySeconds: 5

Prometheus-Anmerkungen – Die drei Anmerkungen unter template.metadata.annotations sagen Prometheus: “scrape diesen Pod, auf Port 3000, unter dem Pfad /metrics”. Der Prometheus-Server, der standardmäßig für die Kubernetes-Autoentdeckung konfiguriert ist, erkennt automatisch annotierte Pods. Keine zusätzliche Prometheus-Konfiguration erforderlich.

Beobachten Sie die Einrückung – Anmerkungen müssen unter template.metadata (der Pod-Vorlage) stehen, nicht unter dem metadata des Deployments oder auf der spec-Ebene. Dies ist ein häufiger Fehler: Wenn Anmerkungen auf der falschen Ebene sind, findet Prometheus Ihre Pods nicht.

k8s/service.yaml:

apiVersion: v1
kind: Service
metadata:
  name: message-wall
spec:
  selector:
    app: message-wall
  ports:
    - port: 3000
      targetPort: 3000

6.6 Installation von PostgreSQL, Prometheus und Grafana

Alle drei sind Infrastruktur-Dienste – installieren Sie sie einmal über Rancher Desktop, nicht bei jedem tilt up. Sie bleiben zwischen den Entwicklungssitzungen bestehen.

Das Repository enthält Helm-Werte-Dateien in values_yaml/ für jeden Dienst. Im Rancher Desktop-Anwendungsbereich "Sammlung" suchen Sie nach jedem Chart, wechseln Sie in den YAML-Modus und fügen Sie die entsprechende Datei ein.

values_yaml/postgresql.yaml:

auth:
  database: demo
  postgresPassword: demo
  postgresUsername: demo
  username: demo
global:
  imagePullSecrets:
  - application-collection

values_yaml/prometheus.yaml:

alertmanager:
  service:
    type: NodePort
global:
  imagePullSecrets:
  - application-collection

values_yaml/grafana.yaml:

adminPassword: admin
global:
  imagePullSecrets:
  - application-collection
sidecar:
  dashboards:
    enabled: true
  datasources:
    enabled: true

imagePullSecrets – Jede Werte-Datei verweist auf das application-collection Geheimnis, damit Pods Images von dp.apps.rancher.io abrufen können. Dieses Geheimnis wird automatisch von der Rancher Desktop-Erweiterung erstellt.

Grafana-Sidecars – Die sidecar.dashboards.enabled und sidecar.datasources.enabled Einstellungen sind entscheidend. Sie starten kleine Container neben Grafana, die nach Kubernetes ConfigMaps mit bestimmten Labels suchen und deren Inhalte automatisch in Grafana laden. Es ist nicht erforderlich, Datenquellen manuell zu konfigurieren oder Dashboards zu importieren.

Sidecar Überwachtes Label Auswirkung

grafana-sc-dashboard

grafana_dashboard: "1"

Lädt automatisch Dashboard-JSON-Dateien

grafana-sc-datasources

grafana_datasource: "1"

Konfiguriert automatisch Datenquellen

Überprüfen Sie, ob die Sidecars aktiv sind:

kubectl get pods -l app.kubernetes.io/name=grafana \
  -o jsonpath='{.items[0].spec.containers[*].name}'
# Expected: grafana grafana-sc-dashboard grafana-sc-datasources

Wenn Sie nur grafana sehen, gehen Sie zurück zur Rancher Desktop-Benutzeroberfläche und überprüfen Sie, ob sowohl sidecar.dashboards.enabled als auch sidecar.datasources.enabled true sind, dann Aktualisieren Sie das Chart.

Das Helm-Chart für PostgreSQL erstellt automatisch den Benutzer, die Datenbank und einen Dienst mit dem Namen <release-name>-postgresql. Die Tiltfile erkennt diesen Dienst automatisch über das app.kubernetes.io/name=postgresql Label – es ist nicht erforderlich, sich den Release-Namen zu merken.

6.7 Keycloak: Authentifizierung ohne ein Helm-Chart

Keycloak bietet OAuth2 / OpenID Connect-Authentifizierung für die Message Wall. Benutzer melden sich an, und die App überprüft ihr Identitätstoken, bevor sie Nachrichten posten oder löschen dürfen.

Warum keine Helm-Installation? – Im Gegensatz zu PostgreSQL, Prometheus und Grafana gibt es kein Helm-Chart für Keycloak in der SUSE Application Collection. Es ist nur als Container-Image verfügbar (dp.apps.rancher.io/containers/keycloak). Dies ist ein realistisches Szenario: Nicht jede Anwendung liefert ein Helm-Chart, und Entwickler müssen wissen, wie man rohe Kubernetes-Manifeste bereitstellt.

k8s/appco/keycloak.yaml (simplified):

apiVersion: apps/v1
kind: Deployment
metadata:
  name: keycloak-appco
spec:
  replicas: 1
  selector:
    matchLabels:
      app: keycloak
  template:
    metadata:
      labels:
        app: keycloak
    spec:
      volumes:
        - name: realm-config
          configMap:
            name: keycloak-realm
      containers:
        - name: keycloak
          image: dp.apps.rancher.io/containers/keycloak:26.5.4
          args: ["start-dev", "--health-enabled=true", "--import-realm"]
          volumeMounts:
            - name: realm-config
              mountPath: /opt/keycloak/data/import
          env:
            - name: KC_DB
              value: postgres
            - name: KC_DB_URL
              value: jdbc:postgresql://PLACEHOLDER_PG_SVC:5432/keycloak
            # ... KC_DB_USERNAME, KC_DB_PASSWORD, KEYCLOAK_ADMIN, etc.
          readinessProbe:
            httpGet:
              path: /health/ready
              port: 9000
            initialDelaySeconds: 30
      imagePullSecrets:
        - name: application-collection

Wichtigste Punkte:

  • start-dev + --import-realm – Keycloak startet im Entwicklungsmodus (HTTP, kein Zertifikat) und importiert automatisch alle JSON-Realm-Dateien, die in /opt/keycloak/data/import gefunden werden.

  • Realm ConfigMap – Eine ConfigMap (keycloak-realm), die das Realm-JSON enthält, wird als Volume eingebunden. Diese ConfigMap wird von der Tiltfile aus k8s/shared/keycloak-realm.json erstellt.

  • PLACEHOLDER_PG_SVC – Die Tiltfile ersetzt dies zur Deploy-Zeit durch den tatsächlichen PostgreSQL-Dienstnamen, der über Label-Selectoren entdeckt wird.

  • Getrennte Datenbank – Keycloak verwendet eine dedizierte keycloak Datenbank in derselben PostgreSQL-Instanz. Die Tiltfile erstellt sie automatisch, wenn sie nicht existiert.

Realm-setup-Skript (scripts/setup-keycloak-realm.sh):

Die Tiltfile führt auch ein setup-Skript über die Admin REST API als Fallback aus. Das Skript ist idempotent: Es überprüft, ob das Realm bereits existiert, erhält ein Admin-Token und erstellt das Realm, falls erforderlich. Dies behandelt den Fall, in dem der Import der ConfigMap nicht erfasst wird (z. B. wenn Keycloak bereits lief, bevor die ConfigMap erstellt wurde).

6.8 Das Grafana-Dashboard (automatisch bereitgestellte ConfigMap)

Das Grafana-Dashboard ist in einer Kubernetes ConfigMap definiert. Dank des Sidecars, das im vorherigen Schritt aktiviert wurde, wird es automatisch geladen – kein manueller Import erforderlich.

k8s/grafana-dashboard.yaml (Struktur – die vollständige Datei befindet sich im Repository):

apiVersion: v1
kind: ConfigMap
metadata:
  name: message-wall-dashboard
  labels:
    grafana_dashboard: "1"      # the sidecar detects this label
data:
  message-wall.json: |
    {
      "uid": "message-wall",
      "title": "Message Wall",
      "panels": [ ... ]
    }

uid: "prometheus" – Jedes Panel verweist auf die Datenquelle über "uid": "prometheus". Diese UID muss genau übereinstimmen mit der, die in der von der Tiltfile generierten Datenquellen-ConfigMap deklariert ist (siehe nächster Abschnitt). Wenn das JSON ${DS_PROMETHEUS} verwendet (Grafana UI-Importsyntax), wird das Sidecar diese Variable nicht auflösen – Sie müssen die hardcodierte UID verwenden.

Das Dashboard enthält 8 Panels:

des Assistenten Typ Metrik Was es zeigt

Nachrichten in der Datenbank

Stat

app_messages_count

Messgerät mit Schwellenwerten grün < 50 < gelb < 100 < rot

Veröffentlichte Nachrichten

Stat

app_messages_posted_total

Zähler für insgesamt veröffentlichte Nachrichten

Massenlöschungen

Stat

app_messages_deleted_total

Zähler für insgesamt Massenlöschungen

Anfragen / Sekunde

Zeitreihe

rate(app_http_…​_count[5m])

Durchsatz pro HTTP-Route

Beiträge / Minute

Zeitreihe

rate(app_messages_posted_total[5m]) * 60

Veröffentlichungsrate

Antwortzeit (p95)

Zeitreihe

histogram_quantile(0.95, …​)

Latenz des 95. Perzentils pro Route

Speichernutzung

Zeitreihe

process_resident_memory_bytes

RSS + Node.js-Heap

Verzögerung der Ereignisschleife (p99)

Zeitreihe

nodejs_eventloop_lag_p99_seconds

Gesundheit der Ereignisschleife

Warum rate(…​[5m]) und nicht [1m]? – Die rate() Funktion benötigt mindestens 2 Datenpunkte innerhalb des Fensters. Wenn Prometheus alle 60 Sekunden abfragt, hat ein 1-Minuten-Fenster nur einen Punkt und gibt nichts zurück. Die Faustregel: Setzen Sie das rate() Fenster auf mindestens 2x des Abfrageintervalls. 5 Minuten sind ein sicherer Standardwert.

Deklarative Bereitstellung – Das Dashboard befindet sich in Git, versioniert mit dem Code. Wenn Sie es in Grafana ändern (Panels hinzufügen, Abfragen ändern), exportieren Sie es und aktualisieren Sie die ConfigMap, damit Änderungen bei der nächsten erneuten Implementierung nicht verloren gehen. Dies ist der Infrastruktur als Code-Ansatz, der auf Einblick angewendet wird.

6.9 Die vollständige Tiltfile

# Demo Tiltfile
load('ext://restart_process', 'docker_build_with_restart')

allow_k8s_contexts('rancher-desktop')

# --- Helpers ---------------------------------------------------------
def find_service(label_selector, required=False, name='Service'):
    # Discover a Kubernetes service by label selector.
    #
    # Helm charts installed via Rancher Desktop get random release
    # names (e.g. postgresql-1772033328). Searching by label is
    # robust regardless of the release name.
    svc = str(local(
        "kubectl get svc -l " + label_selector +
        " -o jsonpath='{.items[0].metadata.name}'",
        quiet=True,
    )).strip()
    if required and svc == '':
        fail(name + ' not found. Install it via Rancher Desktop ' +
             '(Application Collection).')
    return svc

# --- Service discovery -----------------------------------------------
pg_svc = find_service(
    'app.kubernetes.io/name=postgresql',
    required=True,
    name='PostgreSQL',
)
grafana_svc = find_service('app.kubernetes.io/name=grafana')
prometheus_svc = find_service(
    'app.kubernetes.io/name=prometheus,app.kubernetes.io/component=server',
)

# --- Application -----------------------------------------------------
docker_build_with_restart(
    'message-wall',
    '.',
    entrypoint=['node', 'src/server.js'],
    only=['src/', 'package.json'],
    live_update=[
        sync('./src', '/app/src'),
        run('cd /app && npm install --no-package-lock',
            trigger=['package.json']),
    ],
)

deployment = str(read_file('k8s/appco/deployment.yaml')).replace(
    'PLACEHOLDER_PG_SVC', pg_svc)
service = str(read_file('k8s/appco/service.yaml'))
k8s_yaml([blob(deployment), blob(service), 'k8s/shared/grafana-dashboard.yaml'])

k8s_resource(
    'message-wall-appco',
    port_forwards='3000:3000',
    labels=['app'],
)

# --- Keycloak (no Helm chart — deployed as raw K8s manifest) ---------
# Ensure keycloak DB exists in PostgreSQL
pg_pod = str(local(
    "kubectl get pods -l app.kubernetes.io/name=postgresql "
    "-o jsonpath='{.items[0].metadata.name}'", quiet=True)).strip()
local("kubectl exec " + pg_pod +
    " -- env PGPASSWORD=demo psql -U demo -tc "
    "\"SELECT 1 FROM pg_database WHERE datname='keycloak'\""
    " | grep -q 1 || kubectl exec " + pg_pod +
    " -- env PGPASSWORD=demo psql -U demo -c 'CREATE DATABASE keycloak'",
    quiet=True)

# Realm ConfigMap (auto-imports realm with demo user + OAuth client)
local('kubectl create configmap keycloak-realm '
      '--from-file=message-wall.json=k8s/shared/keycloak-realm.json '
      '--dry-run=client -o yaml | kubectl apply -f -', quiet=True)

# Deploy Keycloak using the Application Collection container image
keycloak_yaml = str(read_file('k8s/appco/keycloak.yaml')).replace(
    'PLACEHOLDER_PG_SVC', pg_svc)
k8s_yaml(blob(keycloak_yaml))

k8s_resource('keycloak-appco', port_forwards='8080:8080', labels=['app'])

# Realm setup via Admin REST API (idempotent fallback)
local_resource(
    'keycloak-realm-setup',
    cmd='bash scripts/setup-keycloak-realm.sh http://localhost:8080 '
        'k8s/shared/keycloak-realm.json',
    labels=['app'],
    resource_deps=['keycloak-appco'],
)

# --- Monitoring (optional) -------------------------------------------
if grafana_svc:
    local_resource(
        'grafana',
        serve_cmd='kubectl port-forward svc/' + grafana_svc + ' 3001:80',
        labels=['monitoring'],
        allow_parallel=True,
        links=['http://localhost:3001',
               'http://localhost:3001/d/message-wall/'],
    )

if prometheus_svc:
    local_resource(
        'prometheus',
        serve_cmd='kubectl port-forward svc/' + prometheus_svc
                  + ' 9090:80',
        labels=['monitoring'],
        allow_parallel=True,
        links=['http://localhost:9090'],
    )

    datasource_cm = """apiVersion: v1
kind: ConfigMap
metadata:
  name: grafana-datasource-prometheus
  labels:
    grafana_datasource: "1"
data:
  prometheus.yaml: |
    apiVersion: 1
    datasources:
      - name: Prometheus
        type: prometheus
        uid: prometheus
        url: http://{svc}:80
        access: proxy
        isDefault: true
        editable: false
""".format(svc=prometheus_svc)

    k8s_yaml(blob(datasource_cm))

    k8s_resource(
        objects=['message-wall-dashboard:configmap',
                 'grafana-datasource-prometheus:configmap'],
        new_name='grafana-config',
        labels=['monitoring'],
        links=['http://localhost:3001/d/message-wall/'],
    )

Wichtige Punkte der Tiltfile:

find_service() Helfer – Dienste, die über die Rancher Desktop UI installiert wurden, haben zufällige Versionsnamen (z. B. grafana-1772033328). Anstatt diese Namen fest einzugeben, entdeckt der Helfer sie über Kubernetes-Labels, die von den Helm-Charts gesetzt werden. Dies ist ein robustes Muster: Die Tiltfile funktioniert unabhängig vom Versionsnamen.

docker_build_with_restart – Die restart_process Erweiterung löst ein Problem, das spezifisch für interpretierte Sprachen ist. Wenn live_update eine Datei in den Container synchronisiert, sieht Node.js sie nicht – der Code ist bereits im Speicher geladen. docker_build_with_restart umschließt den Einstiegspunkt, um den Prozess nach jeder Synchronisierung automatisch neu zu starten. Für kompilierte Sprachen (Go, Rust) ist ein Standard docker_build mit einem Kompilierungsschritt in run() der übliche Ansatz.

Prometheus-Datenquelle als ConfigMap – Anstatt Prometheus in der Grafana UI zu konfigurieren (manuelle Konfiguration geht beim Redeployment verloren), generiert die Tiltfile eine ConfigMap mit dem grafana_datasource: "1"-Label. Der Grafana Sidecar erkennt es und stellt die Verbindung automatisch bereit. Die Prometheus-URL wird dynamisch injiziert: http://<detected-service-name>:80.

links – Jede local_resource und k8s_resource kann klickbare Links im Tilt-Dashboard deklarieren. Sie sehen die URLs für Grafana, Prometheus und das spezifische Dashboard direkt in der Tilt UI.

objects + new_name – ConfigMaps sind keine Workloads (Deployment, StatefulSet…), daher ordnet Tilt sie standardmäßig unter “uncategorized” ein. Die objects Direktive gruppiert sie unter einem expliziten Namen (grafana-config) mit dem monitoring Label.

Keycloak-Implementierung – Da es kein Helm-Chart für Keycloak in der SUSE Application Collection gibt, stellt das Tiltfile es als rohes K8s-Manifest bereit. Zuerst wird sichergestellt, dass eine keycloak Datenbank in PostgreSQL existiert, eine ConfigMap mit dem Realm-JSON erstellt, die Keycloak-Implementierung (wobei PLACEHOLDER_PG_SVC durch den entdeckten Dienstnamen ersetzt wird) bereitgestellt und ein setup-Skript über die Admin-REST-API als idempotente Rückfalloption ausgeführt.

Bedingtheit – Der Überwachungsblock ist bedingt (if grafana_svc / if prometheus_svc). Wenn Prometheus und Grafana nicht installiert sind, funktioniert das Tiltfile trotzdem – nur die App und PostgreSQL sind erforderlich. Einblick ist ein optionales Bonusangebot.

6.10 Die Demo ausführen

# 1. Clone the repo
git clone https://github.com/fxHouard/Rancher-Developer-Access-Demo.git
cd Rancher-Developer-Access-Demo

# 2. Install services via Rancher Desktop (one time only):
#
#    PostgreSQL:
#      Application Collection tab -> search PostgreSQL -> Install
#      Switch to YAML mode, paste values_yaml/postgresql.yaml, Install
#
#    Prometheus:
#      Application Collection tab -> search Prometheus -> Install
#      Switch to YAML mode, paste values_yaml/prometheus.yaml, Install
#
#    Grafana:
#      Application Collection tab -> search Grafana -> Install
#      Switch to YAML mode, paste values_yaml/grafana.yaml, Install

# 3. Start the inner loop:
tilt up

# 4. Press Space to open the Tilt dashboard in your browser

# 5. From the Tilt dashboard, click the links to:
#    -> http://localhost:3000   -- The Message Wall app
#    -> http://localhost:8080   -- Keycloak (admin / admin)
#    -> http://localhost:9090   -- Prometheus (check targets)
#    -> http://localhost:3001   -- Grafana (admin / admin)

# 6. In Grafana: go to Dashboards -> "Message Wall" is already there
#    (or click the direct link in Tilt)

# 7. Post messages on localhost:3000 and watch the metrics
#    update in real time in Grafana

# 8. Change ACCENT_COLOR in src/server.js (line 9)
#    -> save -> ~2 sec -> the color changes

6.11 Was im Hintergrund passiert

1. `tilt up` on the host:
   +-- Auto-detects PostgreSQL (label app.kubernetes.io/name=postgresql)
   +-- Auto-detects Prometheus and Grafana (labels app.kubernetes.io/name=...)
   +-- Creates keycloak DB in PostgreSQL if needed
   +-- docker build message-wall -> image in dockerd local store
   |   +-- k3s sees the image because same store -> imagePullPolicy: IfNotPresent
   +-- kubectl apply deployment + service -> k3s creates the app pod
   |   +-- Pod connects to detected PG service (K8s internal DNS)
   |   +-- Prometheus scrapes the pod (prometheus.io/* annotations)
   +-- Deploys Keycloak (Application Collection image, raw K8s manifest)
   |   +-- Imports realm via ConfigMap volume mount
   |   +-- Runs setup script via Admin REST API (idempotent fallback)
   +-- kubectl apply ConfigMaps (datasource + dashboard)
   |   +-- Grafana sidecars detect and load them
   +-- Port-forward 3000 -> localhost:3000 (app)
   +-- Port-forward 8080 -> Keycloak
   +-- Port-forward 3001 -> Grafana
   +-- Port-forward 9090 -> Prometheus

2. Dev modifies src/server.js:
   +-- Tilt (on host) detects the change (file watcher)
   +-- live_update syncs ./src -> /app/src in the pod (kubectl cp)
   +-- restart_process relaunches `node src/server.js` in the container
   +-- ~2 seconds later: change visible on localhost:3000

3. Observability loop (continuous):
   +-- Prometheus scrapes localhost:3000/metrics every 15-60s
   +-- Grafana queries Prometheus to display dashboards
   +-- Dev sees the impact of their changes in real time

6.12 Portweiterleitung erklärt

Tilt verwaltet die Portweiterleitung automatisch über port_forwards in k8s_resource(). Es ist das Äquivalent von kubectl port-forward, aber in den Lebenszyklus von Tilt integriert (automatisch neu gestartet, wenn das Pod neu erstellt wird).

Vollständige Portweiterleitungskette:

Browser (localhost:3000)
  -> Tilt port-forward
    -> K8s Service (ClusterIP)
      -> Your app pod (:3000)
        -> Connects to PostgreSQL Service (:5432)
          -> PostgreSQL pod

Ihre App im Pod verwendet den internen Kubernetes-DNS, um PostgreSQL zu erreichen:

postgresql://user:pass@demo-db-postgresql.default.svc.cluster.local:5432/mydb

Von Ihrem lokalen Rechner (zum Beispiel für einen SQL-Client): kubectl port-forward svc/demo-db-postgresql 5432:5432.

7. Der vollständige Workflow

# Schritt Werkzeuge Details

1

Code schreiben

VS Code + Erweiterungen

Editor, Autovervollständigung, Lint, Git

2

Iterieren (innerer Loop)

Tilt

Automatisches Erstellen + Live-Synchronisierung + Dashboard

3

Authentifizieren

Keycloak

OAuth2-Login, Bereich automatisch von Tilt bereitgestellt

4

Beobachten

Prometheus + Grafana

Echtzeit-Metriken, automatisch bereitgestellte Dashboards

5

Commit + Push

Git

Quelle der Wahrheit für GitOps

6

Build + Scan (äußere Schleife)

CI-Pipeline + Trivy + Cosign

Schwachstellen + Bildsignierung

7

Bereitstellen

Argo CD

Automatische Synchronisierung Git → Cluster

8

Progressive Bereitstellung

Argo Rollouts

Canary / Blue-Green mit Analyse

8. Weiter gehen

Die obige Demo behandelt die wesentlichen Aspekte der inneren Schleife. Dieser Abschnitt stellt zusätzliche Werkzeuge und Praktiken vor, die den Workflow ergänzen, während Ihr Projekt wächst.

8.1 Dev-Container: die reproduzierbare Umgebung

Das Prinzip: Ihre Entwicklungsumgebung ist im Code definiert (.devcontainer/). Jeder Entwickler, der das Projekt öffnet, erhält genau die gleiche Umgebung, mit den gleichen Werkzeugen, den gleichen Versionen und den gleichen VS Code-Erweiterungen.

Der Dev Container ist ein Entwicklungscontainer – er dient nur zum Programmieren. Er benötigt kein Docker, kubectl oder Helm. Tilt läuft auf dem Host.

.devcontainer/Dockerfile:

FROM dp.apps.rancher.io/containers/nodejs:24-dev

# System tools (available in the SLE_BCI repo)
# gawk: required by VS Code Server (check-requirements.sh)
RUN zypper --non-interactive install -y git openssh make gawk \
    && zypper clean -a

.devcontainer/devcontainer.json:

{
  "name": "Message Wall - Node.js",
  "build": {
    "dockerfile": "Dockerfile"
  },
  "customizations": {
    "vscode": {
      "extensions": [
        "ms-kubernetes-tools.vscode-kubernetes-tools"
      ],
      "settings": {
        "vs-kubernetes.disable-linters": true
      }
    }
  },
  "postCreateCommand": "if [ -f package.json ]; then npm install --no-package-lock; fi"
}

Kein docker, kubectl, helm oder tilt im Container. Tilt läuft auf dem Host. Die Kubernetes-Erweiterung bietet IntelliSense für die Bearbeitung von K8s-Manifesten. Die kubeconfig not found Warnung ist zu erwarten und harmlos – der Cluster-Explorer funktioniert nicht im Container, aber die Autovervollständigung funktioniert.

Wenn VS Code mit einem Container verbunden ist, öffnen sich alle integrierten Terminals im Container. Aber Tilt muss auf dem Host (wo Docker, kubectl und Helm vorhanden sind) ausgeführt werden. Verwenden Sie ein separates Terminal (Terminal.app, iTerm2, Warp, Windows Terminal…) oder ein zweites VS Code-Fenster, das im selben Ordner ohne “Reopen in Container” geöffnet ist.

8.2 Ressourcenanforderungen und -grenzen

In der Demo hat die Implementierung keinen resources-Block aus Gründen der Einfachheit. In der Produktion (oder in gemeinsamen Clustern) sollten Sie sie immer definieren:

resources:
  requests:
    cpu: 100m           # 0.1 vCPU -- scheduler reserves this
    memory: 128Mi       # 128 MB -- guaranteed minimum
  limits:
    cpu: 500m           # 0.5 vCPU -- ceiling, throttled beyond
    memory: 256Mi       # 256 MB -- OOMKill beyond

Ohne requests oder limits kann ein Pod alle Ressourcen des Knotens verbrauchen und andere Workloads beeinträchtigen – das “noisy neighbor” Problem. requests sind für den Scheduler (intelligente Platzierung), limits schützen den Knoten (CPU-Drosselung, OOMKill, wenn der Speicher überschritten wird).

8.3 Testcontainers: Integrationstests

Das Konzept: Testcontainers ist eine Bibliothek, die flüchtige Docker-Container in Ihren Integrationstests hochfährt. Brauchen Sie eine PostgreSQL, um Ihre SQL-Abfragen zu testen? Testcontainers startet eine, führt Ihre Tests aus und zerstört sie, wenn sie abgeschlossen sind.

Warum es wichtig ist:

  • Reproduzierbarkeit: Jeder Test startet eine frische Datenbank – keine Verschmutzung zwischen den Tests.

  • Keine Mocks: Sie testen gegen die echte Datenbank, nicht gegen einen Mock, der abweichen kann.

  • CI-freundlich: funktioniert in GitHub Actions, GitLab CI usw. (benötigt nur Docker).

Testcontainers verwendet den Docker-Daemon des Hosts. Mit Rancher Desktop (dockerd) funktioniert es direkt – keine spezielle Konfiguration erforderlich.

Konfiguration:

# macOS / Linux -- already configured if ~/.rd/bin is in PATH
export DOCKER_HOST=unix://$HOME/.rd/run/docker.sock

Beispiel (Node.js):

const { GenericContainer } = require('testcontainers');
const { Client } = require('pg');

describe('Database integration', () => {
  let container, client;

  beforeAll(async () => {
    container = await new GenericContainer('dp.apps.rancher.io/containers/postgresql:17')
      .withExposedPorts(5432)
      .withEnvironment({ POSTGRES_USER: 'test', POSTGRES_PASSWORD: 'test', POSTGRES_DB: 'test' })
      .start();

    client = new Client({
      host: container.getHost(),
      port: container.getMappedPort(5432),
      user: 'test', password: 'test', database: 'test',
    });
    await client.connect();
  });

  afterAll(async () => {
    await client.end();
    await container.stop();
  });

  test('should insert and retrieve data', async () => {
    await client.query('CREATE TABLE test (id SERIAL, name TEXT)');
    await client.query("INSERT INTO test (name) VALUES ('hello')");
    const result = await client.query('SELECT * FROM test');
    expect(result.rows).toHaveLength(1);
  });
});

Testcontainers vs Tilt+Helm:

Testcontainers Tilt + Helm

Lebenszyklus

Ephemeral (1 Testlauf)

Persistent (Dauer der Entwicklungs-Sitzung)

Daten

Frisch bei jedem Lauf

Persistent (es sei denn, es wird gelöscht)

Verwendung

Integrationstests in CI

Tägliche lokale Entwicklung

8.4 mirrord: lokales Debuggen in einem Remote-Cluster

mirrord ermöglicht es Ihnen, einen lokalen Prozess auszuführen, während Sie ihn mit dem Netzwerk und dem Dateisystem eines Pods in einem Remote-Kubernetes-Cluster verbinden. Der Code läuft lokal, aber “sees” die Cluster-Umgebung.

Kein Bedarf für mirrord, wenn Sie einen lokalen Cluster mit allen Abhängigkeiten haben und Ihre App 1 bis 5 Mikrodienste hat.

mirrord wird interessant, wenn die App 20+ Mikrodienste hat (unmöglich, alles lokal auszuführen), Sie verwaltete Dienste benötigen, die lokal nicht verfügbar sind, oder Sie lokales Debuggen (Haltepunkte in VS Code) im Kontext eines echten Clusters wünschen.

Die gewinnende Kombination – Tilt für die tägliche innere Schleife (lokaler Cluster), mirrord für gelegentliches Debugging in der Staging-Umgebung. Die beiden Tools sind komplementär.

8.5 Helm und Kustomize

Helm ermöglicht es Ihnen, Ihre Kubernetes-Manifeste zu templatisieren und sie als “charts” zu verteilen. Es ist das Äquivalent eines Paketmanagers (npm, zypper…) für Kubernetes. values.yaml passt Implementierungen pro Umgebung (dev, staging, prod) an. Helm verfolgt die bereitgestellten Versionen und ermöglicht Rollback.

Kustomize funktioniert, indem es Patches auf Basis-YAML-Manifeste anwendet. Keine Template-Sprache: Sie wenden deklarative Transformationen an. Nativ in kubectl integriert (kubectl apply -k).

Helm oder Kustomize? – Die beiden schließen sich nicht gegenseitig aus. Ein gängiger Ansatz: Verwenden Sie Helm für externe Charts (Datenbanken, Monitoring) und Kustomize, um Ihre eigenen Manifeste pro Umgebung anzupassen.

8.6 Sicherheit: Trivy und Cosign

Trivy (verfügbar in der Anwendungsammlung) scannt Ihre Container-Images, Kubernetes-Dateien, Abhängigkeiten und IaC-Code, um bekannte Schwachstellen (CVEs), Fehlkonfigurationen und exponierte Geheimnisse zu erkennen.

trivy image dp.apps.rancher.io/containers/nodejs:24
trivy k8s --report summary cluster

Cosign (verfügbar in der Anwendungsammlung) ermöglicht es Ihnen, Ihre Container-Images kryptografisch zu signieren. Es ist ein Pfeiler der Lieferkettensicherheit.

cosign sign --key cosign.key myregistry/myapp:v1.0
cosign verify --key cosign.pub myregistry/myapp:v1.0

8.7 GitOps: Argo CD und Argo Rollouts

GitOps ist das Prinzip, dass Git die einzige Quelle der Wahrheit für den gewünschten Zustand Ihrer Infrastruktur und Anwendungen ist. Ein Implementierungstool überwacht das Git-Repository und gleicht automatisch den Clusterzustand mit dem in Git deklarierten Zustand ab.

Argo CD (verfügbar in der Anwendungsammlung) ist ein deklaratives kontinuierliches Implementierungstool für Kubernetes: deklarativer Zustand in Git, automatische Synchronisierung mit Drift-Erkennung, Multi-Cluster-Unterstützung und eine Web-UI zur Visualisierung.

Argo Rollouts (auch in der Anwendungsammlung) fügt Blue-Green und Canary Implementierungsstrategien zu Kubernetes hinzu, mit automatischer Metrikanalyse, um zu entscheiden, ob eine Implementierung gefördert oder zurückgerollt werden soll.

8.8 Die “12 Factor App” für Kubernetes

  • Konfiguration über die Umgebung: verwenden Sie ConfigMaps und Secrets, codieren Sie niemals Konfiguration fest im Image.

  • Zustandslose Prozesse: Jede Instanz Ihrer Anwendung muss identisch und austauschbar sein.

  • Portbindung: Ihre Anwendung stellt einen Port zur Verfügung, Kubernetes verwaltet das Routing über Services.

  • Protokolle an stdout: Schreiben Sie niemals in Protokolldateien. Lassen Sie Kubernetes / Fluent Bit stdout sammeln.

  • Gesundheitsprüfungen: Implementieren Sie immer Liveness- und Readiness-Probes.

  • Metriken: Stellen Sie einen /metrics Prometheus-Endpunkt zur Verfügung. Observability ist kein Luxus, sondern ein Standard.

8.9 Minimale Images

  • BCI Micro: für statische Binärdateien (Go, Rust). Kein Paketmanager, minimale Angriffsfläche.

  • BCI BusyBox: für Fälle, die eine minimale Shell erfordern.

  • BCI Base: für Fälle, die zypper/RPM erfordern.

  • Multi-Stage-Builds: Mit dem Entwicklungs-Image bauen und das Ergebnis in BCI Micro kopieren.

8.10 Infrastruktur als Code

  • Alles ist in Git: Dockerfiles, Helm-Charts, Kustomize-Overlays, Tiltfiles, devcontainer.json, Grafana-Dashboards.

  • Kein manuelles kubectl apply in Staging/Produktion. Alles läuft über GitOps (Argo CD).

  • Ephemere Umgebungen (Vorschau-Umgebungen) werden automatisch bei jedem PR erstellt.

9. Glossar

Begriff Definition

Inner Loop

Schneller lokaler Entwicklungszyklus: Code, erstellen, bereitstellen, testen

Outer Loop

Automatisierter Post-Commit-Zyklus: CI/CD, Tests, Implementierung

Tilt

Inner Loop-Tool mit live_update und Web-Dashboard

Tiltfile

Tilt-Konfigurationsdatei in Starlark (Python-ähnliche DSL)

live_update

Tilt-Funktion: Dateisynchronisierung in einen Container ohne Neubau

restart_process

Tilt-Erweiterung: startet den Anwendungsprozess nach einem live_update neu

Entwicklungscontainer

Offene Spezifikation zur Definition einer Entwicklungsumgebung in einem Container

mirrord

Verbindet einen lokalen Prozess mit einem Remote-K8s-Cluster-Kontext

Testcontainers

Bibliothek für containerisierte Abhängigkeiten in Tests

Helm

Paketmanager für Kubernetes (Charts)

Kustomize

K8s-Manifestanpassung über Patches/Overlays

Trivy

Schwachstellenscanner für Bilder, Code, IaC

Cosign

Werkzeug zum Signieren/Überprüfen von Container-Images

Argo CD

GitOps-Tool für kontinuierliche Implementierung in Kubernetes

Argo Rollouts

Canary- und Blue-Green-Implementierungen für Kubernetes

GitOps

Paradigm: Git = Quelle der Wahrheit für den Clusterzustand

Keycloak

Open-Source-Identitäts- und Zugriffsmanagement (OAuth2 / OpenID Connect)

Prometheus

Überwachungssystem, das Metriken über HTTP-Scraping sammelt

Grafana

Plattform zur Visualisierung von Metriken (Dashboards)

prom-client

Node.js-Bibliothek zum Bereitstellen von Prometheus-Metriken

Sidecar

Hilfscontainer in einem Pod, der eine ergänzende Aufgabe ausführt

ConfigMap

K8s-Ressource zum Speichern der Konfiguration (hier: Dashboards, Datenquellen)

k3s

Leichtgewichtige Kubernetes-Distribution, die von Rancher Desktop verwendet wird

BCI

Basis-Container-Images von SUSE, Grundlage der Application Collection Images

OCI

Open Container Initiative: Standard für Container-Images

imagePullPolicy

K8s-Richtlinie: IfNotPresent = verwende lokales Image, wenn verfügbar

10. Weiterführende Informationen

Viel Spaß bei der Kubernetes-Entwicklung!