Tegnap kijött a Kyverno 1.17, a lényeg pedig az, hogy a CEL-alapú policy típusok mostantól GA státuszúak. Ha eddig JMESPath-os ClusterPolicy erőforrásokkal dolgoztál, készülj. Hivatalosan deprecated-ek, és a v1.20-ban (2026 október) kikerülnek.

Ma egy teljes napot rászántam egy éles cluster migrálására, amiben kb. 60 szabályzat volt. Így nézett ki a gyakorlatban.


Miért fontos ez?

A Kyverno évek óta JMESPath kifejezéseket használ. Működnek, de Kyverno-specifikusak. A CEL (Common Expression Language) az, amit maga a Kubernetes is használ a ValidatingAdmissionPolicy-hoz az 1.30-as verzió óta. A CEL-re váltással a Kyverno igazodik az upstreamhez, és érezhetően jobb teljesítményt kap.

A régi módszer:

apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
  name: require-labels
spec:
  rules:
    - name: check-team-label
      match:
        any:
          - resources:
              kinds:
                - Pod
      validate:
        message: "A 'team' label kötelező."
        pattern:
          metadata:
            labels:
              team: "?*"

Az új:

apiVersion: policies.kyverno.io/v1
kind: ValidatingPolicy
metadata:
  name: require-labels
spec:
  matchConstraints:
    resourceRules:
      - apiGroups: [""]
        apiVersions: ["v1"]
        resources: ["pods"]
        operations: ["CREATE", "UPDATE"]
  validations:
    - expression: "has(object.metadata.labels) && 'team' in object.metadata.labels && object.metadata.labels['team'] != ''"
      message: "A 'team' label kötelező."

Bőbeszédűbb? Igen. De ugyanaz a nyelv, amit a natív Kubernetes admission policy-knál is használsz, így egy DSL-lel kevesebbet kell fejben tartani.


A migráció: mi történt valójában

1. lépés: Kyverno frissítés

helm repo update kyverno
helm upgrade kyverno kyverno/kyverno \
  --namespace kyverno-system \
  --version 1.17.0 \
  --set admissionController.replicas=3

Maga az upgrade tiszta volt. Nincs CRD ütközés, a helm upgrade-en kívül nem kellett restart. A régi és az új API verzió egyszerre működik, szóval az első napon semmi nem törik el.

2. lépés: Leltár

Mielőtt bármit piszkáltam volna, kigyűjtöttem, mi van:

kubectl get clusterpolicy -o name | wc -l
# 47

kubectl get policy -A -o name | wc -l
# 15

62 policy összesen. Kategorizáltam:

  • Csak validáció (38): egyenes út a ValidatingPolicy-hoz
  • Mutáció (16): mostantól MutatingPolicy, itt lett trükkös
  • Generálás (8): GeneratingPolicy, többnyire ConfigMap és NetworkPolicy generátorok

3. lépés: Az átírás

A validációs policy-knál az új kyverno.io-s migrációs útmutató egész jó. A legtöbb pattern közvetlenül lefordítható:

JMESPath pattern → CEL kifejezés

# Régi: pattern alapú
validate:
  pattern:
    spec:
      containers:
        - resources:
            limits:
              memory: "?*"

# Új: CEL kifejezés
validations:
  - expression: >-
      object.spec.containers.all(c,
        has(c.resources) &&
        has(c.resources.limits) &&
        'memory' in c.resources.limits
      )
    message: "Minden containernek kell memory limit."

Az all() makró a legjobb barátod, amikor containereken iterálsz.

4. lépés: Mutációs policy-k, itt égtem meg

A régi patchStrategicMerge egyszerű volt. Szó szerint leírtad a YAML-t, amit be akartál injektálni. Az új MutatingPolicy CEL mutációkat használ, amik inkább JSONPatch-ek CEL-ben kifejezve:

apiVersion: policies.kyverno.io/v1
kind: MutatingPolicy
metadata:
  name: inject-sidecar-proxy
spec:
  matchConstraints:
    resourceRules:
      - apiGroups: [""]
        apiVersions: ["v1"]
        resources: ["pods"]
        operations: ["CREATE"]
  mutations:
    - patchType: JSONPatch
      jsonPatch:
        expression: >-
          [
            JSONPatch{op: "add", path: "/metadata/labels/injected-proxy", value: "true"},
            JSONPatch{op: "add", path: "/spec/containers/-",
              value: object{
                "name": "proxy-sidecar",
                "image": "envoyproxy/envoy:v1.32-latest",
                "ports": [object{"containerPort": 15001}]
              }
            }
          ]          

Buktató #1: Ha tömbbe patchelsz (pl. container hozzáadás), a /spec/containers/- path működik, de az érték összerakása CEL-ben más, mint sima JSON-ban. Az object{} literál szintaxisát egy ideig tartott megfejteni. A doksi még nem túl bőkezű a komplex, beágyazott objektumos példákkal.

Buktató #2: A patchStrategicMerge-nek nincs közvetlen CEL megfelelője. Ha arra építettél, hogy a strategic merge szemantika szerint olvadnak össze a dolgok (pl. meglévő env változókhoz hozzáadás felülírás nélkül), akkor explicit JSONPatch műveletekre kell átalakítanod. Ez kb. 4 óra volt a napomból.


Namespace-szintű szabályzatok: a multi-tenancy győzelem

A feature, ami a legjobban feldobott: NamespacedMutatingPolicy és NamespacedGeneratingPolicy. Eddig csak cluster adminok írhattak mutációs szabályokat. Mostantól a namespace tulajdonosok is definiálhatják a sajátjaikat:

apiVersion: policies.kyverno.io/v1
kind: NamespacedMutatingPolicy
metadata:
  name: team-defaults
  namespace: team-alpha
spec:
  matchConstraints:
    resourceRules:
      - apiGroups: [""]
        apiVersions: ["v1"]
        resources: ["pods"]
        operations: ["CREATE"]
  mutations:
    - patchType: JSONPatch
      jsonPatch:
        expression: >-
          [
            JSONPatch{op: "add", path: "/metadata/labels/cost-center", value: "alpha-2026"}
          ]          

Nálunk minden csapat namespace-nek van egy dedikált service accountja RBAC-kel a saját Namespaced*Policy erőforrásaihoz. A platform csapat továbbra is a cluster-szintű policy-kat kezeli. Tiszta szétválasztás.


Új CEL függvények, amiket érdemes ismerni

A Kyverno 1.17 tényleg hasznos CEL kiterjesztéseket hoz:

# Érték hash-elése (titkokhoz vagy checksum összehasonlításhoz)
sha256("my-config-data")

# x509 tanúsítványok dekódolása és vizsgálata inline
x509.decode(object.data["tls.crt"]).notAfter

# Időalapú szabályzatok (pl. telepítés tiltása munkaidőn kívül)
time.now().getDayOfWeek() >= 1 && time.now().getDayOfWeek() <= 5

# Beágyazott JSON/YAML parse-olása annotációkból
json.unmarshal(object.metadata.annotations["config"]).replicas > 0

Az x509.decode() zseniális tanúsítvány-validációs policy-khoz. Eddig egy custom controllerrel csináltuk, most háromsoros policy.


Teljesítmény: érezhetően gyorsabb

Tudományos benchmarkom nincs, de a webhook válaszidők a Prometheus dashboardjainkon leestek. Migráció előtt a p99 admission webhook latency kb. 45ms volt. CEL policy-kra váltás után: nagyjából 18ms. A CEL kifejezések egyszer fordulnak le és cache-elődnek, a JMESPath meg minden kiértékeléskor interpretálódott.

Egy clusternél, ami percenként ~200 pod-ot hoz létre, ez összeadódik.


Migrációs checklist

Ha tervezed, itt van, amit az első napon szerettem volna tudni:

  1. Ne kapkodj. Mindkét API egyszerre működik. 2026 októberig van időd.
  2. Kezdd a validációs policy-kkal. Ezek a legegyszerűbben konvertálhatók.
  3. A mutációs policy-kat először Audit módban teszteld. A viselkedés finoman eltérhet a patchStrategicMerge-től.
  4. Használj kubectl apply --dry-run=server-t a CEL szintaktikai hibák kiszűrésére, mielőtt élesbe mennének.
  5. Nézd meg az új policy katalógust. A Kyverno 300+ minta policy-t szállít, immár CEL változatokkal.
  6. Figyeld a deprecation ütemtervet. v1.18 (2026 április) = már csak kritikus javítások a régi API-khoz.

Összegzés

Ez tipikusan olyan upgrade, ami gyorsan megtérül. A CEL igazodás az upstream Kuberneteshez kevesebb kontextusváltást, jobb teljesítményt és valódi multi-tenancy támogatást jelent. A migráció nem fájdalommentes, különösen a mutációs policy-knál, de jól kezelhető, ha fázisokban csinálod.

Ha még Kyverno < 1.16-ot futtatsz, érdemes egyenesen 1.17-re ugrani, most, hogy minden GA. Nincs értelme béta CEL API-kat adoptálni, ha stabilak is elérhetők.

Kezdj el migrálni. A régi API-k nem lesznek itt örökké.