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-corpmit Subgruppenacme-corp-admins,acme-corp-developers,acme-corp-viewers - GitLab: Gruppe
acme-corp - Harbor: Projekt
acme-corpmit 50Gi Quota - ArgoCD: Projekt
acme-corpmit 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:
- Benutzer in Keycloak nachschlagen (via Username oder Email)
- Zu allen referenzierten Organization-Gruppen hinzufügen
- Zu allen ContactGroup-Gruppen hinzufügen
- 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¶
- Organization: Erstellt Keycloak-Gruppe → GitLab-Gruppe → Harbor-Projekt → ArgoCD-Projekt
- Contact: Sucht Keycloak-User → Fügt zu Gruppen hinzu → Synchronisiert GitLab-Mitgliedschaft
- ContactGroup: Erstellt Keycloak-Gruppe
Löschung¶
Alle CRs verwenden Finalizer für sauberes Cleanup:
- Organization löschen: ArgoCD-Projekt → Harbor-Projekt → GitLab-Gruppe → Keycloak-Gruppe (in umgekehrter Reihenfolge)
- 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:
- Prüft ob in der API bereits ein Cluster für diesen Workspace existiert
- Falls ja: API-Cluster hat Vorrang,
cluster_namewird ignoriert - Falls nein und
cluster_namegesetzt: Neues Cluster wird angelegt - Falls nein und
cluster_namenicht 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:
- Der Operator sendet einen Health-Report an die API mit dem konfigurierten Agent Token
- Die API erkennt anhand des Tokens den zugehörigen Workspace und die Organization
- Die API gibt
workspace_id,workspace_name,organization_idundorganization_namein der Health-Response zurück - 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¶
- Aktive Loeschung: Wenn ein Source-Objekt (Ingress, Secret, etc.) geloescht wird und der Operator laeuft, werden die zugehoerigen CRs sofort aktiv geloescht
- Stale-Sweep: Periodisch prueft jeder Discovery-Controller, ob die Source-Objekte seiner CRs noch existieren. Verwaiste CRs werden automatisch geloescht
- 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.iozeigt 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:
- Sofort: Kubernetes triggert Operator-Reconciliation
- Sofort: Operator erkennt geändertes
path, aktualisiert CRD - Sofort: CRD-Änderung triggert API-Sync
- ~60s: Agent holt bei nächstem Refresh neue Konfiguration
- 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:
Workflow bei Deletion:
- User löscht Ingress:
kubectl delete ingress webapp - Kubernetes setzt
deletionTimestampauf Ingress - Operator erkennt Deletion, führt Cleanup durch:
- Löscht Endpoint aus Polycrate API via
DELETE /api/v1/endpoints/{id}/ - Operator entfernt Finalizer
- 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:
- Findet Secrets mit Label
polycrate.io/type: meta - Löst
organizationundworkspaceNamen zu UUIDs auf (API-Lookup) - 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:
- Workspace aus
spec.workspace.name+spec.workspace.organizationfinden - Block aus
spec.block.nameim Workspace finden - 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?