Das Problem: ein Wert für zwei Container
Ein über den OperatorHub installierter Operator läuft als Pod, oft mit zwei Containern: manager für die eigentliche Operator-Logik und kube-rbac-proxy als Sidecar, der den Metrics-Endpunkt schützt.
Der konkrete Fall
- Pod
k10-kasten-operator-…-controller-manager-…hat zwei Container - Container
managerfordert 800m CPU an, der Sidecar nur 10m - Ziel: nur
managerauf 400m senken - Setzt man den Wert in der Subscription (Web-Console → Operator → Subscription → Resources), landen beide Container bei 400m
Wer steuert was
OLM im Überblick
Der Operator Lifecycle Manager installiert, aktualisiert und überwacht Operatoren. Er besteht aus zwei Controllern – und fünf Objekten, die man auseinanderhalten muss.
Catalog Operator
Löst Abhängigkeiten auf, erzeugt InstallPlans und beobachtet Kataloge auf neue Versionen.
OLM Operator
Beobachtet CSVs und führt deren Install-Strategie aus: legt Deployments, RBAC und alles Weitere an.
Die beteiligten Objekte
| Objekt | Kurzname | Aufgabe | Bild |
|---|---|---|---|
| CatalogSource | catsrc | Katalog mit verfügbaren Operator-Paketen und Versionen | Versandkatalog |
| Subscription | sub | „Paket X aus Channel Y, Updates automatisch oder manuell“ | Abo |
| InstallPlan | ip | Berechnete Liste der Ressourcen für eine Installation oder ein Update | Lieferschein |
| ClusterServiceVersion | csv | Beschreibung einer konkreten Operator-Version: Deployment-Spec, RBAC, CRDs, Metadaten | Bauplan |
| OperatorGroup | og | Legt fest, welche Namespaces der Operator beobachtet | Zuständigkeitsbereich |
Ablauf einer Installation
- Subscription anlegenPer Web-Console oder YAML.
- InstallPlan entstehtDer Catalog Operator findet in der CatalogSource die passende Version.
- FreigabeBei
installPlanApproval: Automaticsofort, beiManualerst nach Bestätigung. - CRDs, RBAC und CSV werden angelegtDurch den InstallPlan.
- Deployment entstehtDer OLM Operator liest die CSV und erzeugt daraus das Deployment des Operators.
- Operator-Pod startetAus dem Deployment.
Nützliche Befehle
oc get sub,ip,csv -n <namespace>
oc get csv -n <namespace> -o wide
oc describe sub <name> -n <namespace>
Die CSV: Original, nicht Kopie
Die ClusterServiceVersion ist das zentrale Objekt. Sie beschreibt genau eine Version eines Operators, z. B. k10-kasten-operator-….vX.Y.Z – inklusive der vollständigen Deployment-Spezifikation.
Wichtige Felder
| Feld | Inhalt |
|---|---|
spec.install.spec.deployments[] | Vollständige Deployment-Spezifikation des Operators, inklusive Container, Images und Resources |
spec.install.spec.permissions…/clusterPermissions | Role- und ClusterRole-Regeln |
spec.customresourcedefinitions.owned | CRDs, die der Operator verwaltet |
spec.version, spec.replaces | Versionskette für Upgrades |
Wer gewinnt?
OLM gleicht das Deployment ständig mit der CSV ab.
| Änderung an | Ergebnis |
|---|---|
| Deployment | wird von OLM zurückgesetzt – steht nicht in der CSV |
| CSV | wird sofort ins Deployment ausgerollt |
| Operator-Upgrade | OLM legt eine neue CSV mit neuem Namen an; die alte samt allen manuellen Änderungen verschwindet |
Container und CPU-Requests einer CSV anzeigen
CSV=$(oc get csv -n kasten-io -o name | grep k10-kasten-operator-)
oc get $CSV -n kasten-io -o jsonpath='{range .spec.install.spec.deployments[*]}{.name}{"\n"}{range .spec.template.spec.containers[*]} {.name}: {.resources.requests.cpu}{"\n"}{end}{end}'
Liefert pro Deployment die Container in ihrer Reihenfolge – daraus ergibt sich der Index für den Patch in Abschnitt 4.
Warum die Subscription nicht reicht
Die Subscription bietet unter spec.config Overrides für das Operator-Deployment. Sie liegen über der CSV und überstehen damit auch Upgrades – haben aber keinen Container-Selektor.
Verfügbare Overrides in spec.config
env,envFromvolumes,volumeMountsresourcesnodeSelector,tolerations,affinity
Der Haken
Laut Red-Hat-Dokumentation gelten die Werte aus spec.config.resources für alle Container im Pod, den OLM erzeugt.
apiVersion: operators.coreos.com/v1alpha1
kind: Subscription
metadata:
name: <subscription-name>
namespace: kasten-io
spec:
channel: stable
name: <package-name>
source: <catalog-source>
sourceNamespace: openshift-marketplace
config:
resources:
requests:
cpu: 400m # gilt für manager UND kube-rbac-proxy
Einmalige Lösung: CSV patchen
Pro Container lässt sich der Wert nur in der CSV ändern. Das wirkt sofort – hält aber nur bis zum nächsten Operator-Upgrade.
Schritt 1 · Subscription-Override entfernen
Sonst überschreibt die Subscription den Patch wieder für alle Container.
oc patch sub <subscription-name> -n kasten-io --type=json \
-p '[{"op":"remove","path":"/spec/config/resources"}]'
Schritt 2 · Index des Containers ermitteln
Mit dem Befehl aus Abschnitt 2. Der JSON-Patch adressiert Container über ihre Position in der Liste, nicht über ihren Namen.
Schritt 3 · Nur diesen Container patchen
Beispiel: Deployment 0, Container 1.
oc patch $CSV -n kasten-io --type=json -p '[
{"op":"replace",
"path":"/spec/install/spec/deployments/0/spec/template/spec/containers/1/resources/requests/cpu",
"value":"400m"}
]'
replace durch add ersetzen, falls noch kein requests.cpu gesetzt ist. Liegt ein CPU-Limit unter 400m, dieses ebenfalls anpassen.
Schritt 4 · Ergebnis am Pod prüfen
oc get pod -n kasten-io -l control-plane=controller-manager \
-o jsonpath='{range .items[0].spec.containers[*]}{.name}: {.resources.requests.cpu}{"\n"}{end}'
Abgrenzung: Operator-Pod vs. Kasten-Services
Veeam Kasten besteht aus zwei Ebenen, die leicht verwechselt werden. Für die Anwendung selbst gibt es einen sauberen, dokumentierten Weg – für den Operator-Pod nicht.
| Ebene | Beispiele | Verwaltet von | Resources anpassen über |
|---|---|---|---|
| Operator | k10-kasten-operator-…-controller-manager | OLM (CSV) | CSV-Patch bzw. Kyverno |
| Kasten-Anwendung | catalog-svc, jobs-svc, executor-svc, Prometheus, Worker-Pods | Kasten-Operator anhand der K10-CR | Helm-Values in der K10-CR |
Resources der Kasten-Anwendung
Veeam dokumentiert die Anpassung pro Deployment und Container über Helm-Values in der K10-CR:
resources:
catalog-svc:
catalog-svc:
requests:
cpu: 300m
memory: 1.5Gi
Weitere Stellschrauben laut Kasten-Doku
| Wert | Wirkt auf |
|---|---|
global.resources | globaler Fallback mit niedrigster Priorität |
prometheus.server.resources | Prometheus-Pod |
genericVolumeSnapshot.resources | alle temporären Worker-Pods |
ActionPodSpec / ActionPodSpecBinding | Worker-Pods granular pro Pod-Typ, Namespace oder Policy – erfordert workerPodCRDs.enabled=true |
workerPodMetricSidecar.resources | Metrics-Sidecar der Worker-Pods |
Dauerhafte Lösung: Kyverno-Mutate-Policy
Kyverno läuft als Admission-Webhook. Legt OLM eine neue CSV an oder ändert eine bestehende, setzt Kyverno den gewünschten Wert, bevor das Objekt gespeichert wird. Es gibt kein Zeitfenster mit dem alten Wert.
Warum nicht einfach ArgoCD?
ArgoCD verwaltet Objekte über ihren Namen. Die CSV heißt nach jedem Upgrade anders (…vX.Y.1 → …vX.Y.2). Ein Patch in Git trifft die neue CSV nicht, Self-Heal hilft hier also nicht. ArgoCD verwaltet stattdessen die Kyverno-Policy – und die bleibt bei Operator-Upgrades unverändert.
Die Policy
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: k10-operator-manager-cpu
annotations:
policies.kyverno.io/title: Kasten-Operator manager CPU-Request
policies.kyverno.io/description: >-
Setzt den CPU-Request des Containers "manager" im Kasten-Operator
auf 400m, unabhängig von der CSV-Version.
spec:
rules:
- name: manager-cpu-400m
match:
any:
- resources:
kinds: ["operators.coreos.com/v1alpha1/ClusterServiceVersion"]
namespaces: ["kasten-io"]
names: ["k10-kasten-operator-*"]
operations: ["CREATE", "UPDATE"]
mutate:
foreach:
- list: "request.object.spec.install.spec.deployments"
foreach:
- list: "element.spec.template.spec.containers"
preconditions:
all:
- key: "{{ element.name }}"
operator: Equals
value: manager
patchesJson6902: |-
- op: add
path: /spec/install/spec/deployments/{{elementIndex0}}/spec/template/spec/containers/{{elementIndex1}}/resources/requests/cpu
value: 400m
Was die Policy tut
| Teil | Wirkung |
|---|---|
match | Nur CSVs des Kasten-Operators in kasten-io. Der Wildcard-Name trifft jede Version. |
äußeres foreach | Läuft über alle Deployments der CSV. |
inneres foreach | Läuft über alle Container des jeweiligen Deployments. |
preconditions | Filtert auf den Container manager – seine Position in der Liste ist egal. |
elementIndex0 / elementIndex1 | Indizes der äußeren und inneren Schleife für den JSON-Patch-Pfad. |
op: add | Setzt den Wert, ob er schon existiert oder nicht – vorausgesetzt, resources.requests ist als Objekt vorhanden. |
Einführung Schritt für Schritt
Schritt 1 · Containernamen prüfen
Mit dem Befehl aus Abschnitt 2. Heißt der Container anders, value: manager in der Policy anpassen.
Schritt 2 · Subscription-Override entfernen
spec.config.resources aus der Subscription löschen – sonst liegt der Wert für alle Container wieder darüber (Befehl in Abschnitt 4, Schritt 1).
Schritt 3 · Policy per ArgoCD ausrollen
Zum Beispiel im Repo unter policies/kyverno/.
Schritt 4 · Bestehende CSV einmal anstoßen
Admission-Webhooks greifen nur bei Änderungen. Die bereits vorhandene CSV muss deshalb einmal angefasst werden:
oc annotate $CSV -n kasten-io kyverno-touch="$(date +%s)" --overwrite
Schritt 5 · Ergebnis prüfen
# In der CSV
oc get $CSV -n kasten-io -o jsonpath='{range .spec.install.spec.deployments[*].spec.template.spec.containers[*]}{.name}: {.resources.requests.cpu}{"\n"}{end}'
# Am laufenden Pod
oc get pod -n kasten-io -l control-plane=controller-manager \
-o jsonpath='{range .items[0].spec.containers[*]}{.name}: {.resources.requests.cpu}{"\n"}{end}'
# Kyverno-Events
oc get events -n kasten-io --field-selector reason=PolicyApplied
Hinweise
- Copied CSVs: Bei Install-Mode
AllNamespaceskopiert OLM die CSV in jeden Namespace. Die Einschränkung aufnamespaces: ["kasten-io"]verhindert, dass Kyverno diese Kopien mutiert. - Status-Updates: OLM aktualisiert den CSV-Status häufig. Das läuft über die
/status-Subresource und löst die Policy nicht aus. - Limits: Soll auch das Limit angepasst werden, einen zweiten Patch-Eintrag für
/resources/limits/cpuergänzen. - Support: Kyverno ist nicht Teil der Red-Hat-Subscription. Nested
foreachmitelementIndex0/1setzt eine aktuelle Kyverno-Version voraus – die Policy zuerst auf einem Testcluster prüfen.
failurePolicy auf Ignore, legt OLM die CSV ohne Mutation an. Kein Fehler, keine Warnung – der Operator läuft einfach wieder mit 800m. Nach jedem Upgrade die Werte kontrollieren.Alternativen im Vergleich
Kyverno ist nicht die einzige Option. Welche passt, hängt davon ab, ob eine Zusatzkomponente akzeptabel ist und wie oft der Operator aktualisiert wird.
| Variante | Überlebt Upgrade | Zeitfenster mit altem Wert | Zusatzkomponente | Aufwand |
|---|---|---|---|---|
Subscription config.resources | ja | nein | keine | gering, aber nur für alle Container |
| CSV manuell patchen | nein | ja, bis manuell gepatcht | keine | bei jedem Upgrade |
CSV patchen + installPlanApproval: Manual + Runbook | nein (bewusst nachgezogen) | kurz | keine | pro Upgrade ein Schritt |
| CronJob, der die aktuelle CSV sucht und patcht | ja | ja, bis zum nächsten Lauf | keine | einmalig, RBAC für CSV nötig |
| Kyverno-Mutate-Policy | ja | nein | Kyverno | einmalig |
CronJob-Variante als Skizze
Sucht die aktuelle CSV, ermittelt den Index von manager und patcht gezielt diesen Container:
CSV=$(oc get csv -n kasten-io -o name | grep k10-kasten-operator-)
IDX=$(oc get $CSV -n kasten-io -o json \
| jq '.spec.install.spec.deployments[0].spec.template.spec.containers | map(.name) | index("manager")')
oc patch $CSV -n kasten-io --type=json \
-p "[{\"op\":\"add\",\"path\":\"/spec/install/spec/deployments/0/spec/template/spec/containers/$IDX/resources/requests/cpu\",\"value\":\"400m\"}]"
Benötigt einen ServiceAccount mit get, list, patch auf clusterserviceversions.operators.coreos.com im Namespace kasten-io.
Kurzfassung
Das Wichtigste in fünf Sätzen.
- Das Deployment eines OLM-Operators ist nur eine Kopie.Das Original ist die CSV.
- Subscription-Overrides überstehen Upgrades– gelten aber für alle Container im Pod.
- CSV-Patches wirken pro Container– gehen aber beim Upgrade verloren.
- Kasten-Services werden über die K10-CR konfiguriertPro Container, upgradefest – betrifft aber nicht den Operator-Pod.
- Kyverno mutiert jede neue CSV beim AnlegenWerte pro Container bleiben dauerhaft gesetzt, ohne Zeitfenster und GitOps-tauglich.