Zum Inhalt

Polycrate Operator

Der Polycrate Operator ist ein Kubernetes Operator, der die automatisierte Verwaltung von Multi-Tenant-Umgebungen über mehrere Systeme hinweg ermöglicht: Keycloak, GitLab, Harbor, ArgoCD und externe Kubernetes Cluster.

Übersicht

Der Operator synchronisiert Custom Resources (CRs) mit dem gewünschten Zustand in den verbundenen Systemen:

┌─────────────────────────────────────────────────────────────────┐
│                    Kubernetes Cluster                           │
│  ┌───────────────────────────────────────────────────────────┐  │
│  │                 polycrate Namespace                        │  │
│  │  ┌─────────────────────────────────────────────────────┐  │  │
│  │  │            Polycrate Operator                        │  │  │
│  │  └─────────────────────────────────────────────────────┘  │  │
│  │           │                                               │  │
│  │           ▼                                               │  │
│  │  ┌─────────────────────────────────────────────────────┐  │  │
│  │  │  Custom Resources (CRs)                              │  │  │
│  │  │  - SoftwareDeliveryPlatform                          │  │  │
│  │  │  - Organization                                       │  │  │
│  │  │  - Contact                                            │  │  │
│  │  │  - ContactGroup                                       │  │  │
│  │  │  - GitLabGroup / HarborProject / ArgoCDProject       │  │  │
│  │  │  - K8sCluster                                         │  │  │
│  │  └─────────────────────────────────────────────────────┘  │  │
│  └───────────────────────────────────────────────────────────┘  │
└─────────────────────────────────────────────────────────────────┘
        │           │           │           │           │
        ▼           ▼           ▼           ▼           ▼
   ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐
   │Keycloak │ │ GitLab  │ │ Harbor  │ │ ArgoCD  │ │K8s Cluster│
   └─────────┘ └─────────┘ └─────────┘ └─────────┘ └─────────┘

Custom Resource Definitions (CRDs)

Der Operator verwaltet 15 verschiedene Custom Resource Typen:

CRD Kurzname Beschreibung
SoftwareDeliveryPlatform sdp Konfiguration der Plattform-Komponenten (Keycloak, GitLab, etc.)
Organization org Multi-System-Organisation (Keycloak-Gruppe, GitLab-Gruppe, Harbor-Projekt, ArgoCD-Projekt)
Contact ct Benutzer-Mapping zu Organisationen und Gruppen
ContactGroup cg Keycloak-Gruppe als Identity Source
GitLabGroup glg Standalone GitLab-Gruppe
HarborProject hp Standalone Harbor-Projekt
ArgoCDProject acp Standalone ArgoCD-Projekt
K8sCluster k8sc Registrierung externer Kubernetes Cluster
OperatorConfig oc, opcfg Operator-weite Konfiguration (Discovery, API-Sync, Local Cluster)
Endpoint ep, pep Endpoint für HTTP-Monitoring (automatisch aus Ingress erstellt)
Backup backup Backup-Status (automatisch aus Velero erstellt)
BackupSchedule bs Backup-Schedule (automatisch aus Velero erstellt)
Certificate cert, pcert TLS-Zertifikat (automatisch aus cert-manager erstellt)
K8sApp app, pca Deployed App (aus Meta-Secrets oder Pod-Labels erkannt)
Artifact art Container-Image im Cluster (cluster-scoped, automatisch aus Pods erstellt)

Installation

1. CRDs installieren

Ab Polycrate CLI 0.30.0 sind die CRDs im polycrate-operator Block enthalten (im crds/-Verzeichnis) und werden beim install-Playbook automatisch angewendet. Der empfohlene Weg ist daher:

# Empfohlen: CRDs werden automatisch bei der Installation angewendet
polycrate run polycrate-operator install

Für manuelle CRD-Installation (z.B. GitOps):

# CRDs direkt aus der CLI installieren (legacy)
polycrate operator install-crds

# Alternativ: CRDs ausgeben und manuell installieren
polycrate operator crds | kubectl apply -f -

# Nur bestimmte CRDs ausgeben
polycrate operator crds --kind Organization
polycrate operator crds --kind OperatorConfig

# Alle verfügbaren CRDs auflisten
polycrate operator crds --list

Für GitOps-Setups, bei denen CRDs separat verwaltet werden, kann die automatische Installation deaktiviert werden:

# workspace.poly
blocks:
  - name: polycrate-operator
    from: cargo.ayedo.cloud/ayedo/k8s/polycrate-operator
    config:
      crds:
        install: false  # CRDs werden separat via GitOps deployed

2. Operator starten

# Lokal ausführen (Development)
polycrate operator run --kubeconfig ~/.kube/config

# Mit spezifischem Kubeconfig
polycrate operator run --kubeconfig /path/to/kubeconfig.yml

# Mit Leader Election (für HA-Deployments)
polycrate operator run --leader-elect

3. SoftwareDeliveryPlatform konfigurieren

apiVersion: polycrate.io/v1alpha1
kind: SoftwareDeliveryPlatform
metadata:
  name: production
  namespace: polycrate
spec:
  keycloak:
    url: "https://keycloak.example.com"
    realm: "acme"
    credentialsRef:
      secretName: keycloak-creds
      clientIdKey: client-id
      clientSecretKey: client-secret

  gitlab:
    url: "https://gitlab.example.com"
    credentialsRef:
      secretName: gitlab-creds
      tokenKey: token

  harbor:
    url: "https://harbor.example.com"
    credentialsRef:
      secretName: harbor-creds
      usernameKey: username
      passwordKey: password

  argocd:
    url: "https://argocd.example.com"
    credentialsRef:
      secretName: argocd-creds
      tokenKey: token
    roles:
      admin:
        policies:
          - "p, proj:{project}:admin, applications, *, {project}/*, allow"
          - "p, proj:{project}:admin, repositories, *, {project}/*, allow"
      developer:
        policies:
          - "p, proj:{project}:developer, applications, get, {project}/*, allow"
          - "p, proj:{project}:developer, applications, sync, {project}/*, allow"
      viewer:
        policies:
          - "p, proj:{project}:viewer, applications, get, {project}/*, allow"

  settings:
    autoCreateRoleSubgroups: true
    defaultRoles:
      - admins
      - developers
      - viewers
    subgroupNamePattern: "{org}-{role}"

Ressourcen erstellen

Organization

Eine Organization erstellt automatisch Ressourcen in allen konfigurierten Systemen:

apiVersion: polycrate.io/v1alpha1
kind: Organization
metadata:
  name: acme-corp
  namespace: polycrate
spec:
  sdp: production
  displayName: "ACME Corporation"

  keycloak:
    groupName: acme-corp
    attributes:
      description: ["Main organization group"]

  gitlab:
    enabled: true
    groupPath: acme-corp
    visibility: private

  harbor:
    enabled: true
    projectName: acme-corp
    storageQuota: "50Gi"

  argocd:
    enabled: true
    projectName: acme-corp
    sourceRepos:
      - "https://gitlab.example.com/acme-corp/*"
    roleBindings:
      - role: admin
        keycloakGroups:
          - acme-corp-admins
      - role: developer
        keycloakGroups:
          - acme-corp-developers

Erstellte Ressourcen:

  • Keycloak: Gruppe acme-corp mit Subgruppen acme-corp-admins, acme-corp-developers, acme-corp-viewers
  • GitLab: Gruppe acme-corp
  • Harbor: Projekt acme-corp mit 50Gi Quota
  • ArgoCD: Projekt acme-corp mit konfigurierten Rollen

Contact

Ein Contact mappt einen Keycloak-Benutzer zu Organisationen:

apiVersion: polycrate.io/v1alpha1
kind: Contact
metadata:
  name: john-doe
  namespace: polycrate
spec:
  keycloak:
    username: john.doe
    email: john.doe@example.com

  organizations:
    - name: acme-corp
      role: developer

  additionalGroups:
    - contactGroup: shared-developers

Automatische Aktionen:

  1. Benutzer in Keycloak nachschlagen (via Username oder Email)
  2. Zu allen referenzierten Organization-Gruppen hinzufügen
  3. Zu allen ContactGroup-Gruppen hinzufügen
  4. GitLab-Gruppenmitgliedschaft synchronisieren

ContactGroup

Eine ContactGroup erstellt eine Keycloak-Gruppe als Identity Source:

apiVersion: polycrate.io/v1alpha1
kind: ContactGroup
metadata:
  name: platform-admins
  namespace: polycrate
spec:
  sdp:
    - production
  keycloak:
    groupName: platform-admins
    attributes:
      description: ["Platform administrators"]

Standalone Ressourcen

GitLabGroup

apiVersion: polycrate.io/v1alpha1
kind: GitLabGroup
metadata:
  name: shared-libs
  namespace: polycrate
spec:
  sdp:
    - production
  groupPath: shared-libs
  visibility: internal

  accessControl:
    - keycloakGroup: platform-admins
      accessLevel: owner

  organizationAccess:
    - organization: acme-corp
      accessLevel: developer

HarborProject

apiVersion: polycrate.io/v1alpha1
kind: HarborProject
metadata:
  name: shared-images
  namespace: polycrate
spec:
  sdp:
    - production
  projectName: shared-images
  public: false
  storageQuota: "100Gi"

  accessControl:
    - keycloakGroup: platform-admins
      role: projectAdmin

  organizationAccess:
    - organization: acme-corp
      role: developer

ArgoCDProject

apiVersion: polycrate.io/v1alpha1
kind: ArgoCDProject
metadata:
  name: infrastructure
  namespace: polycrate
spec:
  sdp:
    - production
  projectName: infrastructure
  description: "Shared infrastructure applications"

  sourceRepos:
    - "https://gitlab.example.com/infrastructure/*"

  destinations:
    - server: https://kubernetes.default.svc
      namespace: "*"
    - clusterRef: production-cluster
      namespace: "*"

  accessControl:
    - keycloakGroup: platform-admins
      role: admin

K8sCluster

Registriert einen externen Kubernetes Cluster:

apiVersion: polycrate.io/v1alpha1
kind: K8sCluster
metadata:
  name: production-cluster
  namespace: polycrate
spec:
  sdp: production
  displayName: "Production Cluster"
  apiServer: "https://api.prod.example.com:6443"

  authentication:
    serviceAccountToken:
      secretRef:
        name: prod-cluster-token
        key: token

  # Oder via Kubeconfig
  # authentication:
  #   kubeconfig:
  #     secretRef:
  #       name: prod-cluster-kubeconfig
  #       key: kubeconfig

  caCertificate: |
    -----BEGIN CERTIFICATE-----
    ...
    -----END CERTIFICATE-----

CLI Commands

polycrate operator crds

Gibt CRD-Definitionen aus:

# Alle CRDs ausgeben
polycrate operator crds

# Bestimmten CRD-Typ ausgeben
polycrate operator crds --kind Organization

# In Datei speichern
polycrate operator crds --output-dir ./crds/

# CRDs auflisten
polycrate operator crds --list

polycrate operator install-crds

Installiert CRDs direkt ins Cluster:

# Mit Standard-Kubeconfig
polycrate operator install-crds

# Mit spezifischer Kubeconfig
polycrate operator install-crds --kubeconfig ~/.kube/admin.yaml

# Dry-run (zeigt was installiert würde)
polycrate operator install-crds --dry-run

polycrate operator run

Startet den Operator:

# Lokal mit Kubeconfig
polycrate operator run --kubeconfig ~/.kube/config

# Mit Leader Election
polycrate operator run --leader-elect

# Mit Metrics aktiviert
polycrate operator run --metrics-bind-address :8080

Optionen:

Flag Standard Beschreibung
--kubeconfig $KUBECONFIG oder ~/.kube/config Pfad zur Kubeconfig
--leader-elect false Leader Election für HA aktivieren
--metrics-bind-address :8080 Metrics Endpoint
--health-probe-bind-address :8081 Health Probe Endpoint

polycrate operator health

Prüft den Health-Status des Operators:

# Lokalen Operator prüfen
polycrate operator health

# Remote-Operator prüfen
polycrate operator health --url http://polycrate-operator.polycrate:8081

polycrate operator status

Zeigt Status aller Operator-Ressourcen:

polycrate operator status

# Ausgabe:
# Polycrate Operator Status
# =========================
# Cluster: https://kubernetes.default.svc
#
# SoftwareDeliveryPlatforms
# -------------------------
#   NAME        NAMESPACE    PHASE   KEYCLOAK  GITLAB  HARBOR  ARGOCD
#   production  polycrate    Ready   ✓         ✓       ✓       ✓
#
# Organizations
# -------------
#   NAME       NAMESPACE    SDP         PHASE
#   acme-corp  polycrate    production  Ready
#
# ...

Reconciliation-Logik

Erstellung

  1. Organization: Erstellt Keycloak-Gruppe → GitLab-Gruppe → Harbor-Projekt → ArgoCD-Projekt
  2. Contact: Sucht Keycloak-User → Fügt zu Gruppen hinzu → Synchronisiert GitLab-Mitgliedschaft
  3. ContactGroup: Erstellt Keycloak-Gruppe

Löschung

Alle CRs verwenden Finalizer für sauberes Cleanup:

  1. Organization löschen: ArgoCD-Projekt → Harbor-Projekt → GitLab-Gruppe → Keycloak-Gruppe (in umgekehrter Reihenfolge)
  2. Contact löschen: Entfernt aus allen Gruppen und Projekten

Status-Updates

Jeder Controller aktualisiert den Status der CR:

status:
  phase: Ready  # oder: Provisioning, Error, Deleting
  keycloakGroupID: "abc-123"
  gitlabGroupID: 42
  harborProjectID: 7
  argoCDProjectCreated: true
  conditions:
    - type: Ready
      status: "True"
      reason: Provisioned
      message: "All organization resources provisioned"

Rate Limiting & Error Handling

Der Operator implementiert intelligentes Rate Limiting:

  • Base Delay: 5 Sekunden
  • Max Delay: 60 Sekunden (Exponential Backoff)
  • Max Concurrent Reconciles: 1 pro Controller

Bei Fehlern (z.B. Keycloak nicht erreichbar) wird die Reconciliation mit exponentiell wachsendem Delay wiederholt.

Multi-SDP Support

Einige CRs können mehrere SDPs referenzieren für Cross-Platform-Erstellung:

apiVersion: polycrate.io/v1alpha1
kind: ContactGroup
metadata:
  name: global-admins
spec:
  sdp:
    - production
    - staging
    - development
  keycloak:
    groupName: global-admins

Dies erstellt die Gruppe in allen drei SDP-Instanzen.

OperatorConfig: Zentrale Discovery-Konfiguration

Die Discovery wird über eine OperatorConfig CR konfiguriert. Diese ist ein Singleton (Name: default, Namespace: polycrate).

apiVersion: polycrate.io/v1alpha1
kind: OperatorConfig
metadata:
  name: default
  namespace: polycrate
spec:
  # API-Sync Konfiguration
  api_sync:
    enabled: true
    api_url: "https://api.polycrate.io"
    credentials_ref:
      secret_name: polycrate-api-creds
      token_key: token
    # workspace_id und organization_id werden NICHT mehr im Spec konfiguriert!
    # Diese Werte werden automatisch vom Agent Token abgeleitet und im Status gespeichert.
    # Siehe "Auto Workspace Resolution" weiter unten.

  # Lokales Cluster bei der API registrieren
  # Wird ignoriert wenn API bereits ein Cluster für diesen Workspace hat
  local_cluster:
    enabled: true
    cluster_name: "my-workspace"      # Optional: Wird ignoriert wenn Cluster bereits existiert

  # Endpoint-Discovery (Ingress → API)
  endpoint_discovery:
    enabled: true
    watch_namespaces: []  # Leer = alle Namespaces
    ignore_namespaces:    # Diese Namespaces werden ignoriert
      - kube-system
      - kube-public
      - polycrate
    ingress_classes: []   # Leer = alle Ingress-Klassen
    default_check_interval: 60

  # App-Discovery (Meta-Secrets + Pod-Labels → API)
  app_discovery:
    enabled: true
    watch_namespaces: []
    ignore_namespaces:
      - kube-system
      - kube-public
    label_discovery_enabled: true  # Label-basierte K8sApp Discovery (ab 0.29.17)
    stale_cleanup_minutes: 10     # Intervall fuer Stale-Sweep (ab 0.29.17)

  # Node-Discovery (Nodes → API)
  node_discovery:
    enabled: true
    label_selector: ""

  # Backup-Discovery (Velero → API)
  backup_discovery:
    enabled: true
    velero_namespace: velero
    ignore_namespaces: []
    cnpg_enabled: true

Namespace-Filterung

Die Namespace-Filterung funktioniert für alle Discovery-Typen gleich:

Konfiguration Verhalten
watch_namespaces: [] Alle Namespaces überwachen
watch_namespaces: [prod, staging] Nur diese Namespaces
ignore_namespaces: [kube-system] Diese Namespaces immer ignorieren

Wichtig: ignore_namespaces wird von watch_namespaces subtrahiert. Wenn ein Namespace in beiden Listen ist, wird er ignoriert.

Local Cluster Registration

Der Operator kann das Cluster, in dem er läuft, mit der Polycrate API verknüpfen:

Idempotenz-Logik:

  1. Prüft ob in der API bereits ein Cluster für diesen Workspace existiert
  2. Falls ja: API-Cluster hat Vorrang, cluster_name wird ignoriert
  3. Falls nein und cluster_name gesetzt: Neues Cluster wird angelegt
  4. Falls nein und cluster_name nicht gesetzt: Kein Cluster wird angelegt

Die aufgelöste Cluster-ID wird im OperatorConfig.status.local_cluster gespeichert für idempotente Operationen.

Wichtig: Die Kubeconfig wird nicht automatisch synchronisiert – dies übernimmt der Git-Sync der Workspaces.

Auto Workspace Resolution (ab 0.29.0)

Ab Version 0.29.0 werden workspace_id und organization_id automatisch vom Agent Token abgeleitet.

Wie funktioniert es:

  1. Der Operator sendet einen Health-Report an die API mit dem konfigurierten Agent Token
  2. Die API erkennt anhand des Tokens den zugehörigen Workspace und die Organization
  3. Die API gibt workspace_id, workspace_name, organization_id und organization_name in der Health-Response zurück
  4. Der Operator speichert diese Werte im OperatorConfig.status.api_sync

Vorteile:

  • Keine manuelle UUID-Konfiguration mehr erforderlich
  • Token-basierte Authentifizierung = automatische Workspace-Zuordnung
  • Reduzierte Fehlerquellen bei der Konfiguration

Status-Felder:

status:
  api_sync:
    workspace_id: "550e8400-e29b-41d4-a716-446655440000"
    workspace_name: "production"
    organization_id: "6ba7b810-9dad-11d1-80b4-00c04fd430c8"
    organization_name: "acme-corp"
    resolved_at: "2026-01-06T14:30:00Z"

Migration von älteren Versionen:

Falls in älteren Versionen workspace_id und organization_id im Spec konfiguriert waren, können diese Felder nach dem Update auf 0.29.0 entfernt werden. Die Werte werden automatisch aus dem Token abgeleitet.


Discovery: Operator-Driven API-Synchronisation

Der Operator erkennt automatisch Kubernetes-Ressourcen und synchronisiert sie direkt mit der Polycrate API. Im Gegensatz zu server-side Import geschieht die Synchronisation in Echtzeit durch den Operator.

┌─────────────────┐     ┌─────────────────┐     ┌─────────────────┐
│  K8s Ressource  │     │    Operator     │     │  Polycrate API  │
│  (Ingress, etc) │     │   Controller    │     │   (Django)      │
└─────────────────┘     └─────────────────┘     └─────────────────┘
        │                       │                       │
        │  1. Watch             │                       │
        │◄──────────────────────│                       │
        │                       │  2. Create/Update     │
        │                       │──────────────────────►│
        │  3. Annotate          │  4. Response: id      │
        │  (id, synced-at)      │◄──────────────────────│
        │◄──────────────────────│                       │
        │                       │                       │
        │  [Deletion]           │  5. Delete            │
        │  Finalizer Cleanup    │──────────────────────►│
        │◄──────────────────────│                       │

Erkannte Ressourcen

K8s Ressource API-Ziel Discovery Controller
Ingress Endpoint EndpointDiscoveryController
Polycrate Meta-Secret K8sApp K8sAppDiscoveryController
Pod mit k8sapps.polycrate.io/name Label K8sApp K8sAppLabelDiscoveryController
Node Host HostDiscoveryController
Velero Backup Backup BackupDiscoveryController
Velero Schedule BackupSchedule BackupDiscoveryController
cert-manager Certificate Certificate CertificateDiscoveryController

API-Sync und Selbstreparatur (ab 0.30.4)

Der Operator hält discovered Ressourcen automatisch mit der API in Einklang – inkl. Selbstreparatur bei Abweichungen:

Ressource Verhalten
Endpoint API-Existenzprüfung: Vor jedem Sync prüft der Operator, ob der Endpoint in der API noch existiert. Wenn die API den Endpoint gelöscht hat (z.B. durch Reconciliation oder manuell), wird er automatisch neu angelegt.
K8sApp Adopt Existing: Wenn eine K8sApp bereits in der API existiert (z.B. durch Workspace-Sync und API-Reconciliation aus Block-Instanzen), übernimmt der Operator deren API-ID statt einen doppelten Eintrag zu erstellen.

Praktische Auswirkung:

  • Endpoints bleiben nach API-Brown-Outs oder manueller Löschung nicht dauerhaft „failed“ – der Operator repariert sie beim nächsten Reconcile.
  • K8sApp-Duplikate entstehen nicht mehr, wenn Workspace und API vor dem Operator-Sync aktualisiert wurden.

Label-basierte K8sApp Discovery (ab 0.29.17)

Neben der bestehenden Secret-basierten Erkennung (Polycrate CLI Meta-Secrets) kann der Operator auch Pods erkennen, die mit dem Label k8sapps.polycrate.io/name versehen wurden. So koennen Apps in der Polycrate API registriert werden, die nicht ueber die Polycrate CLI deployed wurden.

Verwendung

Pods (bzw. Deployments/StatefulSets) mit folgendem Label versehen:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-app
  namespace: my-namespace
spec:
  template:
    metadata:
      labels:
        k8sapps.polycrate.io/name: my-app
    spec:
      containers:
        - name: app
          image: my-registry/my-app:latest

Regeln

  • Der Label-Wert muss innerhalb eines Namespaces eindeutig auf eine App zeigen
  • Mehrere Pods mit dem gleichen Label-Wert im selben Namespace = 1 K8sApp (mehrere Replicas)
  • Wenn der gleiche Label-Wert in mehreren Namespaces vorkommt, wird die App ignoriert (Cross-Namespace-Konflikt)
  • Fuer Apps in mehreren Namespaces: Disjunkte Namen verwenden (my-app-ns-a, my-app-ns-b)
  • Wenn eine App auch ueber die Polycrate CLI deployed wurde (Meta-Secret existiert), hat die Secret-Discovery Vorrang

Konfiguration

app_discovery:
  enabled: true
  label_discovery_enabled: true  # Default: true
  watch_namespaces: []
  ignore_namespaces:
    - kube-system
    - kube-public

Unterschiede zur Secret-basierten Discovery

Eigenschaft Secret-basiert Label-basiert
Quelle Polycrate CLI Meta-Secret Pod mit k8sapps.polycrate.io/name Label
Block-Kind polycrate, helm, etc. external
Block-Version aus Secret nicht verfuegbar
Pod-Status alle Pods im Namespace nur Pods mit passendem Label
Cleanup bei Secret-Loeschung wenn keine passenden Pods mehr existieren

Pod-Status: Job- und CronJob-Pods ausgeschlossen (ab 0.29.16)

Der K8sApp-Pod-Status beruecksichtigt keine Pods von Jobs oder CronJobs – z.B. Velero Backup- oder Maintain-Jobs. Diese transienten Pods wuerden die Metriken verfaelschen (Status „Completed“/„Failed“). Nur Pods von Deployments, StatefulSets und DaemonSets fliessen in den K8sApp-Status ein.


Endpoint-K8sApp-Assoziation (ab 0.29.17)

Endpoints aus der Ingress Discovery koennen einer K8sApp zugeordnet werden. Dazu muss das Ingress-Objekt das Label k8sapps.polycrate.io/name tragen:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: my-app-ingress
  labels:
    k8sapps.polycrate.io/name: my-app  # Verknuepfung mit K8sApp
spec:
  rules:
    - host: my-app.example.com
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: my-app
                port:
                  number: 80

Die Zuordnung wird im Endpoint CR Status gespeichert und an die API uebermittelt. Dies ermoeglicht spaeter praezisere Downtime Detection pro K8sApp.


Stale-Sweep und Ressourcen-Cleanup (ab 0.29.17)

Alle Discovery-Controller verfuegen ueber einen periodischen Stale-Sweep, der verwaiste Custom Resources aufraeumt. Dies ist ein Safety-Net fuer Szenarien, in denen Source-Objekte geloescht werden, ohne dass der Operator die Loeschung direkt mitbekommt.

Funktionsweise

  1. Aktive Loeschung: Wenn ein Source-Objekt (Ingress, Secret, etc.) geloescht wird und der Operator laeuft, werden die zugehoerigen CRs sofort aktiv geloescht
  2. Stale-Sweep: Periodisch prueft jeder Discovery-Controller, ob die Source-Objekte seiner CRs noch existieren. Verwaiste CRs werden automatisch geloescht
  3. Finalizer: Der Sync-Controller eines geloeschten CRs sorgt via Finalizer fuer die Entfernung des API-Objekts

Konfiguration

Das Sweep-Intervall ist pro Discovery-Controller konfigurierbar:

endpoint_discovery:
  stale_cleanup_minutes: 10  # Default: 10

app_discovery:
  stale_cleanup_minutes: 10  # Default: 10

backup_discovery:
  stale_cleanup_minutes: 10  # Default: 10

certificate_discovery:
  stale_cleanup_minutes: 10  # Default: 10

Scope

Der Stale-Sweep behandelt ausschliesslich discovered Objekte (Label polycrate.io/discovered=true). API-zugewiesene Objekte (z.B. Endpoints die ueber die API konfiguriert wurden) haben einen eigenen Lifecycle und werden nicht vom Stale-Sweep betroffen.


Endpoint Discovery: Ingress → API Endpoint

Der Operator überwacht Ingress-Objekte und erstellt automatisch Endpoints in der Polycrate API für HTTP-Monitoring.

Alle verfügbaren Annotations

Annotation Typ Default Beschreibung
endpoints.polycrate.io/enabled String "true" Discovery aktivieren/deaktivieren
endpoints.polycrate.io/ignore String "false" Diesen Ingress ignorieren
endpoints.polycrate.io/path String / HTTP-Pfad für Health-Check
endpoints.polycrate.io/timeout String "30" Timeout in Sekunden
endpoints.polycrate.io/interval String "60" Check-Intervall in Sekunden
endpoints.polycrate.io/expected-status String "200" Erwarteter HTTP-Status

Endpoint Custom Resources

Der Operator erstellt für jeden Hostname im Ingress eine separate Endpoint Custom Resource. Die API-ID wird im Status der Endpoint CR gespeichert, nicht als Annotation auf dem Ingress.

Beispiel 1: Minimale Konfiguration

Der einfachste Fall - Endpoint wird mit Defaults erstellt:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: webapp
  namespace: production
  # Keine Annotations nötig - Defaults werden verwendet
spec:
  ingressClassName: nginx
  rules:
    - host: app.example.com
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: webapp
                port:
                  number: 80

Ergebnis: Endpoint mit GET / auf https://app.example.com:443, Timeout 30s, Intervall 60s.

Beispiel 2: Custom Health-Check Pfad

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: api-service
  namespace: production
  annotations:
    # Health-Check auf /api/health statt Root
    endpoints.polycrate.io/path: "/api/health"
spec:
  ingressClassName: nginx
  tls:
    - hosts:
        - api.example.com
      secretName: api-tls
  rules:
    - host: api.example.com
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: api
                port:
                  number: 8080

Ergebnis: Endpoint mit GET /api/health auf https://api.example.com:443.

Beispiel 3: Kritischer Service mit kurzem Intervall

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: payment-gateway
  namespace: production
  annotations:
    # Kritischer Service: Häufigere Checks
    endpoints.polycrate.io/path: "/health/ready"
    endpoints.polycrate.io/interval: "30"
    endpoints.polycrate.io/timeout: "10"
    endpoints.polycrate.io/expected-status: "200"
spec:
  ingressClassName: nginx
  tls:
    - hosts:
        - pay.example.com
      secretName: payment-tls
  rules:
    - host: pay.example.com
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: payment-api
                port:
                  number: 443

Ergebnis: Endpoint mit 30s Intervall (statt 60s), 10s Timeout, erwartet HTTP 200.

Beispiel 4: Body-Validierung für Deep Health-Check

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: database-api
  namespace: production
  annotations:
    endpoints.polycrate.io/path: "/health/deep"
    endpoints.polycrate.io/expected-status: "200"
    # Prüft ob "database":"connected" im Response-Body enthalten ist
    endpoints.polycrate.io/expected-body: '"database":"connected"'
spec:
  ingressClassName: nginx
  tls:
    - hosts:
        - db-api.example.com
      secretName: db-api-tls
  rules:
    - host: db-api.example.com
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: db-api
                port:
                  number: 8080

Ergebnis: Check ist nur erfolgreich wenn HTTP 200 UND Body enthält "database":"connected".

Beispiel 5: Ingress von Discovery ausschließen

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: internal-admin
  namespace: kube-system
  annotations:
    # Diesen Ingress NICHT monitoren
    endpoints.polycrate.io/ignore: "true"
spec:
  ingressClassName: nginx
  rules:
    - host: admin.internal.local
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: admin-dashboard
                port:
                  number: 80

Ergebnis: Kein Endpoint wird erstellt. Nützlich für interne Services oder Test-Umgebungen.

Beispiel 6: Langsamer Backend-Service

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: report-generator
  namespace: production
  annotations:
    # Report-Generierung braucht länger
    endpoints.polycrate.io/path: "/api/health"
    endpoints.polycrate.io/timeout: "120"
    endpoints.polycrate.io/interval: "300"
spec:
  ingressClassName: nginx
  tls:
    - hosts:
        - reports.example.com
      secretName: reports-tls
  rules:
    - host: reports.example.com
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: report-service
                port:
                  number: 8080

Ergebnis: 120s Timeout, 5-Minuten-Intervall für langsame Services.

Beispiel 7: Redirect-fähiger Endpoint (3xx erlauben)

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: legacy-app
  namespace: production
  annotations:
    endpoints.polycrate.io/path: "/"
    # Redirect ist OK (z.B. HTTP→HTTPS oder /→/login)
    endpoints.polycrate.io/expected-status: "302"
spec:
  ingressClassName: nginx
  rules:
    - host: legacy.example.com
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: legacy-app
                port:
                  number: 80

Beispiel 8: Komplettes Produktions-Setup

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: main-api
  namespace: production
  labels:
    app: main-api
    environment: production
  annotations:
    # === Polycrate Endpoint Discovery ===
    endpoints.polycrate.io/path: "/api/v1/health"
    endpoints.polycrate.io/timeout: "15"
    endpoints.polycrate.io/interval: "30"
    endpoints.polycrate.io/expected-status: "200"
    endpoints.polycrate.io/expected-body: '"status":"healthy"'

    # === Nginx Ingress Controller ===
    nginx.ingress.kubernetes.io/proxy-body-size: "50m"
    nginx.ingress.kubernetes.io/proxy-read-timeout: "60"

    # === Cert-Manager ===
    cert-manager.io/cluster-issuer: "letsencrypt-prod"
spec:
  ingressClassName: nginx
  tls:
    - hosts:
        - api.mycompany.com
      secretName: api-tls-cert
  rules:
    - host: api.mycompany.com
      http:
        paths:
          - path: /api
            pathType: Prefix
            backend:
              service:
                name: api-service
                port:
                  number: 8080
          - path: /docs
            pathType: Prefix
            backend:
              service:
                name: docs-service
                port:
                  number: 80

Endpoint Custom Resource

Für jeden Hostname in einem Ingress erstellt der Operator eine separate Endpoint Custom Resource:

apiVersion: polycrate.io/v1alpha1
kind: Endpoint
metadata:
  name: app-example-com
  namespace: production
  labels:
    endpoints.polycrate.io/source-ingress: webapp
    operator.polycrate.io/discovered: "true"
spec:
  displayName: "app.example.com"
  remoteAddress: "app.example.com"
  remotePort: 443
  kind: "http"
  tls: true
  path: "/api/health"
  timeout: 30
  interval: 60
  expectedStatusCodes: [200]
status:
  phase: "synced"
  apiID: "550e8400-e29b-41d4-a716-446655440000"
  configHash: "abc123..."

Vorteile des CRD-Modells:

  • Klare 1:1 Zuordnung: Jeder Hostname = eine CR = eine API-ID
  • Garbage Collection: OwnerReferences ermöglichen automatisches Cleanup
  • Einfaches Debugging: kubectl get endpoints.polycrate.io zeigt alle Endpoints
# Alle Endpoint CRs anzeigen
kubectl get endpoints.polycrate.io -A

# Details einer Endpoint CR
kubectl describe endpoint app-example-com -n production

Endpoint CRs nicht manuell ändern

Die Endpoint CRs werden vom Operator verwaltet. Änderungen an Annotations auf dem Ingress werden automatisch synchronisiert.


Endpoint Monitoring: Operator → API → Agent

Der Operator ist der erste Schritt in der Monitoring-Pipeline. Nach der Synchronisation mit der API übernehmen Monitoring-Agents die eigentlichen HTTP-Checks.

Architektur-Übersicht

┌─────────────────────────────────────────────────────────────────┐
│                    Kubernetes Cluster                           │
│  ┌─────────────────────────────────────────────────────────────┐│
│  │  Ingress                  Polycrate Operator                ││
│  │  + Annotations    ───►    Endpoint Discovery                ││
│  │                           + API Sync                        ││
│  └─────────────────────────────────────────────────────────────┘│
└─────────────────────────────────────────────────────────────────┘
        │                              │
        │                              ▼
        │                     ┌─────────────────┐
        │                     │  Polycrate API  │
        │                     │  - Endpoints    │
        │                     │  - Agent-Zuweis.│
        │                     └─────────────────┘
        │                              │
        │                              ▼
        │                     ┌─────────────────┐
        │◄────────────────────│ Monitoring Agent│
        │   HTTP Check        │ - Fetch Config  │
        │                     │ - Execute Check │
        │                     │ - Prometheus    │
        └─────────────────────┴─────────────────┘

Datenfluss im Detail

Schritt Komponente Aktion
1 Ingress Annotation endpoints.polycrate.io/path=/health gesetzt
2 Operator Erkennt Ingress, erstellt Endpoint CRD mit spec.path
3 Operator Synchronisiert CRD mit API (spec.http.path)
4 API Speichert Endpoint, weist Agents zu
5 Agent Fragt zugewiesene Endpoints ab (inkl. spec)
6 Agent Baut Check-URL: https://host:443/health
7 Agent Führt HTTP-Check aus, exposed Prometheus-Metriken

Änderungen propagieren

Wenn Sie eine Annotation ändern, wird die Änderung automatisch propagiert:

# Annotation ändern
kubectl annotate ingress my-app \
  endpoints.polycrate.io/path="/api/v2/health" \
  --overwrite

Propagierungs-Kette:

  1. Sofort: Kubernetes triggert Operator-Reconciliation
  2. Sofort: Operator erkennt geändertes path, aktualisiert CRD
  3. Sofort: CRD-Änderung triggert API-Sync
  4. ~60s: Agent holt bei nächstem Refresh neue Konfiguration
  5. Nächster Check: Agent prüft gegen neue URL

Latenz

Annotation-Änderungen sind typischerweise innerhalb von 1-2 Minuten aktiv.

Prometheus-Metriken

Die Monitoring-Agents exposen Check-Ergebnisse als Prometheus-Metriken:

# Endpoint-Verfügbarkeit
probe_success{endpoint="api-example-com", organization="acme-corp"}

# Response-Zeit in Sekunden
probe_duration_seconds{endpoint="api-example-com"}

# HTTP Status Code
probe_http_status_code{endpoint="api-example-com"}

Diese Metriken werden von VictoriaMetrics/Prometheus gescraped und stehen für Alerting und Dashboards zur Verfügung.

→ Ausführliche Agent-Dokumentation: Polycrate API - Endpoint Monitoring


Finalizer: Automatisches Cleanup

Der Operator setzt einen Finalizer auf alle entdeckten Ressourcen:

metadata:
  finalizers:
    - endpoints.polycrate.io/cleanup

Workflow bei Deletion:

  1. User löscht Ingress: kubectl delete ingress webapp
  2. Kubernetes setzt deletionTimestamp auf Ingress
  3. Operator erkennt Deletion, führt Cleanup durch:
  4. Löscht Endpoint aus Polycrate API via DELETE /api/v1/endpoints/{id}/
  5. Operator entfernt Finalizer
  6. Kubernetes löscht Ingress-Objekt

Dies stellt sicher, dass API-Objekte immer mit ihren K8s-Quellen synchron bleiben.


K8sApp Discovery: Meta-Secrets → API

Polycrate Blocks erstellen Meta-Secrets die vom Operator als K8sAppInstances synchronisiert werden.

Meta-Secret Format

apiVersion: v1
kind: Secret
metadata:
  name: polycrate-myapp-meta
  namespace: production
  labels:
    app.kubernetes.io/managed-by: polycrate
    polycrate.io/type: meta
data:
  # Base64-encoded
  organization: YWNtZS1jb3Jw    # acme-corp
  workspace: cHJvZHVjdGlvbg==  # production
  block: bXlhcHA=              # myapp
  name: bXlhcHA=               # myapp
  namespace: cHJvZHVjdGlvbg==  # production

Der Operator:

  1. Findet Secrets mit Label polycrate.io/type: meta
  2. Löst organization und workspace Namen zu UUIDs auf (API-Lookup)
  3. Erstellt/aktualisiert K8sAppInstance in API

Host Discovery: Nodes → API

Kubernetes Nodes werden automatisch als Hosts in der API erfasst.

Gemappte Felder

Node-Feld Host-Feld Quelle
metadata.name name, hostname Node Name
status.addresses[ExternalIP] default_ipv4 Node IP
status.capacity.cpu resource_cpu_cores CPU Cores
status.capacity.memory resource_memory Memory (MB)
status.nodeInfo.architecture resource_cpu_architecture Architecture
spec.providerID provider_id Cloud Provider ID

Backup Discovery: Velero → API

Velero Backups und Schedules werden automatisch zur API synchronisiert.

Backup-Mapping

Velero Backup API Backup Mapping
metadata.name name Direkt
status.phase status Completed→completed, Failed→failed
spec.ttl retention_policy TTL als String
status.startTimestamp started_at ISO 8601
status.completionTimestamp completed_at ISO 8601
status.progress.itemsBackedUp items_backed_up Integer

Schedule-Mapping

Velero Schedule API BackupSchedule Mapping
metadata.name name Direkt
spec.schedule schedule_cron Cron-Expression
spec.paused paused Boolean
status.lastBackup.startTime last_backup_at Timestamp
status.lastBackup.name last_backup_name String

Certificate Discovery: cert-manager → API

Der Operator überwacht cert-manager Certificate CRs und synchronisiert sie mit der Polycrate API für zentrales TLS-Zertifikatsmanagement.

Voraussetzungen

  • cert-manager muss im Cluster installiert sein
  • Der Operator erkennt automatisch ob cert-manager CRDs vorhanden sind
  • Falls cert-manager nicht installiert ist, wird der CertificateDiscoveryController übersprungen

Architektur

┌─────────────────────────────────────────────────────────────────┐
│                    Kubernetes Cluster                            │
│                                                                  │
│  ┌──────────────────┐     ┌─────────────────────────────────┐   │
│  │ cert-manager     │     │      Polycrate Operator          │   │
│  │ Certificate CR   │────►│  CertificateDiscoveryController  │   │
│  │ (cert-manager.io)│     │           ▼                      │   │
│  └──────────────────┘     │  polycrate.io/Certificate CR     │   │
│                           │           ▼                      │   │
│                           │  CertificateController           │   │
│                           │           │                      │   │
│                           └───────────┼──────────────────────┘   │
└───────────────────────────────────────┼──────────────────────────┘
                               ┌─────────────────┐
                               │  Polycrate API  │
                               │  /certificates/ │
                               └─────────────────┘

Zwei-Controller-Architektur

Controller Watchet Erstellt/Aktualisiert
CertificateDiscoveryController cert-manager Certificate polycrate.io Certificate CR
CertificateController polycrate.io Certificate API-Objekt via REST

Vorteile:

  • CRD-basiert: Zertifikate sind als Kubernetes-Ressourcen sichtbar (kubectl get certificates.polycrate.io)
  • Finalizer-Cleanup: Automatische API-Deletion bei K8s-Deletion
  • Change Detection: Hash-basierte Änderungserkennung verhindert unnötige API-Updates
  • Inventarprüfung: API-Objekte werden bei jedem Reconcile auf Existenz geprüft

Certificate CRD

Für jedes cert-manager Certificate erstellt der Operator eine polycrate.io/Certificate CR:

apiVersion: polycrate.io/v1alpha1
kind: Certificate
metadata:
  name: certmanager-production-api-example-com-tls
  namespace: production
  labels:
    certificates.polycrate.io/issuer: letsencrypt-production
    certificates.polycrate.io/source: api-example-com-tls
    certificates.polycrate.io/ready: "true"
    operator.polycrate.io/discovered: "true"
spec:
  name: api-example-com-tls
  display_name: "api.example.com-tls"
  namespace: production
  secret_name: api-example-com-tls
  dns_names:
    - api.example.com
  issuer_name: letsencrypt-production
  issuer_kind: clusterissuer
  issuer_group: cert-manager.io
  certificate_status: ready
  is_ready: true
  not_before: "2024-01-01T00:00:00Z"
  not_after: "2024-04-01T00:00:00Z"
  renewal_time: "2024-03-01T00:00:00Z"
  source_cert_manager:
    name: api-example-com-tls
    namespace: production
    uid: "abc-123-..."
    revision: 1
status:
  phase: Synced
  sync_status: synced
  api_id: "550e8400-e29b-41d4-a716-446655440000"
  config_hash: "abc123..."
  last_synced_at: "2024-01-15T10:30:00Z"

API-Mapping

cert-manager Certificate Polycrate Certificate CR API Certificate
metadata.name spec.source_cert_manager.name - (Referenz)
spec.secretName spec.secret_name secret_name
spec.dnsNames spec.dns_names dns_names
spec.ipAddresses spec.ip_addresses ip_addresses
spec.issuerRef.name spec.issuer_name issuer_name
spec.issuerRef.kind spec.issuer_kind issuer_kind
status.notBefore spec.not_before not_before
status.notAfter spec.not_after not_after
status.renewalTime spec.renewal_time renewal_time
Ready Condition spec.is_ready, spec.certificate_status is_ready, certificate_status

Status-Mapping

cert-manager Status certificate_status
Ready=True ready
Ready=False, Reason=Issuing pending
Ready=False, Reason=Failed failed
Ready=True, NotAfter < now expired
Ready=True, NotAfter < now+30d expiring_soon

OperatorConfig: Certificate Discovery

apiVersion: polycrate.io/v1alpha1
kind: OperatorConfig
metadata:
  name: default
  namespace: polycrate
spec:
  # ... andere Konfiguration ...

  # Certificate-Discovery (cert-manager → API)
  certificate_discovery:
    enabled: true
    watch_namespaces: []      # Leer = alle Namespaces
    ignore_namespaces:        # Diese Namespaces ignorieren
      - kube-system
      - cert-manager
    issuer_filter:            # Optional: Nur bestimmte Issuers
      include_issuers: []     # Leer = alle Issuers
      exclude_issuers:        # Diese Issuers ignorieren
        - selfsigned-issuer

CLI-Commands

# Alle Certificate CRs anzeigen
kubectl get certificates.polycrate.io -A

# Certificate-Details anzeigen
kubectl describe certificate.polycrate.io certmanager-production-api-example-com-tls -n production

# API-Sync-Status prüfen
kubectl get certificates.polycrate.io -A -o custom-columns=\
  NAME:.metadata.name,\
  NAMESPACE:.metadata.namespace,\
  ISSUER:.spec.issuer_name,\
  READY:.spec.is_ready,\
  STATUS:.spec.certificate_status,\
  SYNC:.status.sync_status,\
  API_ID:.status.api_id

Verwendung in der Polycrate API

Die synchronisierten Zertifikate sind in der Polycrate API unter /api/v1/certificates/ verfügbar:

  • Zentrales Zertifikatsmanagement: Alle Cluster-Zertifikate auf einen Blick
  • Ablaufwarnungen: Automatische Benachrichtigungen bei expiring_soon
  • Compliance: Übersicht über alle TLS-Endpunkte und deren Zertifikate
  • Korrelation: Verknüpfung mit Endpoints und K8sClusters

K8sApp Discovery: Deployed Blocks → API

Der Operator erkennt automatisch deployte Polycrate Blocks anhand der Meta-Secrets (*.poly) und erstellt K8sApp Custom Resources.

Architektur

┌─────────────────────────────────────────────────────────────────┐
│                    Kubernetes Cluster                            │
│                                                                  │
│  ┌──────────────────┐     ┌─────────────────────────────────┐   │
│  │ Meta-Secret      │     │      Polycrate Operator          │   │
│  │ (*.poly)         │────►│  K8sAppDiscoveryController       │   │
│  │                  │     │           ▼                      │   │
│  └──────────────────┘     │  polycrate.io/K8sApp CR          │   │
│                           │           ▼                      │   │
│                           │  K8sAppController                │   │
│                           │           │                      │   │
│                           └───────────┼──────────────────────┘   │
└───────────────────────────────────────┼──────────────────────────┘
                               ┌─────────────────┐
                               │  Polycrate API  │
                               │  /k8sapps/      │
                               └─────────────────┘

K8sApp CRD

Für jedes Meta-Secret erstellt der Operator eine K8sApp CR:

apiVersion: polycrate.io/v1alpha1
kind: K8sApp
metadata:
  name: nginx-ingress
  namespace: production
  labels:
    k8sapps.polycrate.io/block: nginx-ingress
    k8sapps.polycrate.io/kind: helm
    k8sapps.polycrate.io/type: ingress-controller
    operator.polycrate.io/discovered: "true"
  ownerReferences:
    - apiVersion: v1
      kind: Secret
      name: nginx-ingress.poly
      uid: abc-123-...
spec:
  block:
    name: "nginx-ingress"
    display_name: "NGINX Ingress Controller"
    version: "1.2.0"
    app_version: "1.9.6"
    from: "cargo.ayedo.cloud/ayedo/k8s/nginx-ingress"
    type: "ingress-controller"
    flavor: "nginx"
    chart:
      name: "ingress-nginx"
      version: "4.9.0"
      repo_url: "https://kubernetes.github.io/ingress-nginx"
  workspace:
    name: "production"
    organization: "acme-corp"
  action:
    name: "install"
    status: "success"
    last_executed_at: "2025-12-20T10:00:00Z"
status:
  phase: Synced
  installed: true
  api_id: "550e8400-e29b-41d4-a716-446655440000"
  sync_status: synced
  artifacts:
    - name: "cargo-ayedo-cloud-library-nginx-1-25-3"
      image: "cargo.ayedo.cloud/library/nginx:1.25.3"
      pod_count: 3
  artifact_count: 2

CLI-Commands

# Alle K8sApps anzeigen
kubectl get k8sapps -A

# Ausgabe:
# NAMESPACE   NAME             BLOCK            VERSION   ARTIFACTS   PHASE    AGE
# prod        nginx-ingress    nginx-ingress    1.2.0     3           Synced   7d
# prod        redis            redis            7.2.0     1           Synced   14d

# Details anzeigen
kubectl describe k8sapp nginx-ingress -n prod

Installation-Status Ableitung

Der Operator leitet den Installation-Status aus dem letzten Action-Run ab:

action_name action_status Ergebnis
install success installed=true
install running installation_running=true
install failed installation_failed=true
uninstall success uninstalled=true

Block-ID Verknüpfung

Bei der API-Synchronisierung wird automatisch die Block-ID aufgelöst:

  1. Workspace aus spec.workspace.name + spec.workspace.organization finden
  2. Block aus spec.block.name im Workspace finden
  3. K8sApp mit Block-ID an API senden

Dies ermöglicht vollständige Korrelation zwischen K8sApp ↔ Block ↔ Workspace in der API.


Artifact Discovery: Container Images → API

Der Operator trackt automatisch alle Container-Images im Cluster und synchronisiert sie mit der API.

Besonderheiten

  • Cluster-scoped: Artifacts sind cluster-weit, nicht namespace-gebunden
  • Kein OwnerRef: Pods können aus vielen Namespaces kommen
  • Archivierung: Bei CR-Löschung wird das API-Objekt NICHT gelöscht (Archiv-Zwecke)
  • Stale-Cleanup: CRs werden nach 1 Stunde ohne aktive Pods automatisch entfernt

Artifact CRD

apiVersion: polycrate.io/v1alpha1
kind: Artifact
metadata:
  name: cargo-ayedo-cloud-library-nginx-1-25-3
  labels:
    artifacts.polycrate.io/registry: cargo.ayedo.cloud
    artifacts.polycrate.io/repository: library-nginx
    artifacts.polycrate.io/tag: "1.25.3"
    operator.polycrate.io/discovered: "true"
spec:
  image: "cargo.ayedo.cloud/library/nginx:1.25.3"
  registry:
    hostname: "cargo.ayedo.cloud"
    port: 443
    scheme: "https"
  repository:
    path: "library/nginx"
    name: "nginx"
    namespace: "library"
  tag: "1.25.3"
  digest: "sha256:abc123..."
status:
  phase: Discovered
  used_in_namespaces:
    - name: production
      pod_count: 3
      first_seen_at: "2025-12-20T10:00:00Z"
      last_seen_at: "2025-12-26T15:30:00Z"
    - name: staging
      pod_count: 1
  used_by_k8sapps:
    - name: nginx-ingress
      namespace: production
      k8s_app_id: "550e8400-..."
  first_discovered_at: "2025-12-20T10:00:00Z"
  last_seen_at: "2025-12-26T15:30:00Z"
  total_pod_count: 4
  api_id: "660e8400-..."
  sync_status: synced

CLI-Commands

# Alle Artifacts anzeigen
kubectl get artifacts

# Ausgabe:
# NAME                                      IMAGE                                      PODS   PHASE
# cargo-ayedo-cloud-library-nginx-1-25-3    cargo.ayedo.cloud/library/nginx:1.25.3    5      Discovered
# docker-io-library-redis-7-2               redis:7.2                                  2      Discovered

# Details anzeigen
kubectl describe artifact cargo-ayedo-cloud-library-nginx-1-25-3

Image-Parsing

Der Operator parst Container-Images vollständig:

Image Registry Repository Tag
nginx:1.25 docker.io library/nginx 1.25
cargo.ayedo.cloud/ayedo/polycrate:0.28.0 cargo.ayedo.cloud ayedo/polycrate 0.28.0
ghcr.io/org/app@sha256:abc ghcr.io org/app - (digest)

Bidirektionale Verknüpfung

Artifacts und K8sApps sind bidirektional verknüpft:

  • Artifact.status.used_by_k8sapps[]: Welche K8sApps nutzen dieses Image?
  • K8sApp.status.artifacts[]: Welche Images nutzt diese K8sApp?

Die Verknüpfung basiert auf Namespace-Matching.

OperatorConfig: Artifact Discovery

apiVersion: polycrate.io/v1alpha1
kind: OperatorConfig
metadata:
  name: default
  namespace: polycrate
spec:
  artifact_discovery:
    enabled: true
    watch_namespaces: []      # Leer = alle Namespaces
    ignore_namespaces:
      - kube-system
      - kube-public
    exclude_registries:       # System-Images ignorieren
      - registry.k8s.io
      - k8s.gcr.io
    cleanup:
      enabled: true
      stale_threshold_hours: 1  # Nach 1h ohne Pods löschen
    sync_to_api: true

Use Cases

  • Security Auditing: Welche Images laufen im Cluster? Von welchen Registries?
  • Dependency Tracking: Welche K8sApps nutzen welche Images?
  • Compliance: Nachweis aller Software-Artefakte im Cluster
  • Update-Planung: Welche Apps sind von einem Image-Update betroffen?

Siehe auch