A Kubernetes API kiterjesztése Custom Resource Definition (CRD) segítségével

A Kubernetes napjainkban az egyik legfontosabb eszköz a konténerizált alkalmazások menedzselésére és orchestrálására. Egy rendkívül rugalmas és robusztus platformról van szó, amely deklaratív módon kezeli az infrastruktúrát és az alkalmazásokat. Azonban mi történik akkor, ha a beépített Kubernetes erőforrások (mint például Podok, Deploymentek, Service-ek) nem elegendőek a specifikus igényeink kielégítésére? Ilyenkor lép színre a Custom Resource Definition (CRD), amely lehetővé teszi számunkra, hogy kiterjesszük a Kubernetes API-t saját, egyedi erőforrásainkkal.

Miért van szükség az API kiterjesztésére?

A Kubernetes alapvetően egy deklaratív rendszer. Ez azt jelenti, hogy Ön leírja a kívánt állapotot (pl. „szeretnék egy NGINX szervert 3 replikával”), és a Kubernetes gondoskodik arról, hogy ez az állapot létrejöjjön és fennmaradjon. A platform számos beépített objektummal rendelkezik, amelyek a legtöbb általános feladatot lefedik: alkalmazások futtatása (Deployment, Pod), hálózati hozzáférés (Service, Ingress), konfiguráció (ConfigMap, Secret) stb. De a valós világban gyakran találkozunk olyan domain-specifikus entitásokkal, amelyek nincsenek közvetlenül leképezve ezekre az alapvető építőelemekre.

Képzeljük el, hogy egy összetett adatbázis-kezelő rendszert, például egy MongoDB vagy PostgreSQL klasztert szeretnénk telepíteni és felügyelni a Kubernetesen. A beépített erőforrásokkal ezt megtehetjük, de csak alacsony szinten: Podokat, PersistentVolumeClaim-eket, Service-eket kell manuálisan konfigurálnunk. Az adatbázis-specifikus műveleteket – mint például a biztonsági mentés, a replikáció beállítása, a verziófrissítés, a failover kezelése – mind nekünk kellene manuálisan szkriptelnünk és orchestrálnunk. Ez a megközelítés nehézkes, hibalehetőségekkel teli, és nem illeszkedik a Kubernetes deklaratív filozófiájához.

Itt jön képbe a CRD. A CRD segítségével mi magunk definiálhatjuk ezeket a magasabb szintű absztrakciókat a Kubernetes API-ban. Létrehozhatunk egy „PostgreSQLDatabase” vagy egy „MongoDBCluster” nevű egyedi erőforrást, amely a mi domainünk szempontjából releváns tulajdonságokkal rendelkezik (pl. verzió, méret, replikációs faktor, backup stratégia). Ezáltal a Kubernetes nem csak Podokat, hanem „PostgreSQL adatbázisokat” is képes lesz kezelni, ugyanazzal a deklaratív módszerrel, mint bármely más beépített erőforrást.

Mi is az a Custom Resource Definition (CRD)?

A Custom Resource Definition (CRD) egy olyan speciális Kubernetes erőforrás, amely lehetővé teszi, hogy új típusú erőforrásokat vezessen be a Kubernetes API-ba, anélkül, hogy a Kubernetes forráskódját módosítaná. Amikor létrehoz egy CRD-t, azzal gyakorlatilag utasítja a Kubernetes API szerverét, hogy ismerjen fel egy új objektumtípust, tárolja el a hozzá tartozó adatokat az etcd-ben, és tegye elérhetővé az összes standard Kubernetes API műveleten (GET, LIST, WATCH, CREATE, UPDATE, DELETE) keresztül.

Gondoljon rá úgy, mint egy séma definiálására. Amikor például egy Deploymentet hoz létre, a Kubernetes tudja, hogy annak milyen mezői (pl. `replicas`, `selector`, `template`) lehetnek, és milyen típusúaknak kell lenniük. A CRD pontosan ugyanezt teszi a saját egyedi erőforrásai számára. Meghatározza az egyedi erőforrás (Custom Resource, CR) struktúráját, validációs szabályait és verzióit.

Fontos megkülönböztetni a CRD-t (a definíciót) és a Custom Resource (CR)-t (az egyedi erőforrás példányát). A CRD egyszer hozza létre az API-n belül az új „típust”, míg a CR az adott típusú objektum konkrét példányát jelenti. Ahogy a Deployment a Deployment objektumok „típusa”, és a `my-nginx-app` egy konkrét Deployment, ugyanúgy a „PostgreSQLDatabase” a CRD, és a `production-db-instance` egy konkrét „PostgreSQLDatabase” CR.

A CRD felépítése: Anatómiája egy egyedi erőforrásnak

Egy CRD YAML definíciója számos kulcsfontosságú mezőt tartalmaz, amelyek együttesen írják le az új erőforrást.

1. apiVersion, kind, metadata

Mint minden Kubernetes objektumnál, itt is szükség van ezekre az alapvető azonosítókra. A CRD esetében a `apiVersion` általában `apiextensions.k8s.io/v1`, a `kind` pedig `CustomResourceDefinition`.


apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
  name: blogposts.example.com

2. spec.group

Ez határozza meg az új API csoportot. Hasonlóan a beépített erőforrásokhoz (pl. `apps` csoport a Deployment-hez), itt is megadunk egy egyedi nevet, ami általában a saját domainünket tükrözi, hogy elkerüljük az ütközéseket. Például: `example.com` vagy `database.mycompany.io`.


spec:
  group: example.com

3. spec.names

Ez a szekció definiálja az erőforrás különböző elnevezéseit, amelyekkel az API-n és a kubectl parancson keresztül hivatkozhatunk rá:

  • `plural`: A többes számú alak, például `blogposts`. Ez lesz az URL-ben is használva (`/apis/example.com/v1/blogposts`).
  • `singular`: Az egyes számú alak, például `blogpost`.
  • `kind`: Az erőforrás típusának CamelCase neve, például `BlogPost`. Ez lesz használva a YAML definíció `kind` mezőjében.
  • `shortNames` (opcionális): Rövid aliasok, pl. `bp`. Ez praktikus a kubectl parancsok rövidítéséhez (kubectl get bp).

  names:
    plural: blogposts
    singular: blogpost
    kind: BlogPost
    shortNames:
      - bp

4. spec.scope

Meghatározza, hogy az egyedi erőforrás névterelt (Namespaced) vagy klaszter-szintű (Cluster) lesz-e. A legtöbb alkalmazás-specifikus erőforrás Namespaced, míg az olyan, az egész klaszterre kiható konfigurációk, mint például egy storage osztály, Cluster hatókörűek.


  scope: Namespaced

5. spec.versions

Ez az egyik legfontosabb rész, mivel itt definiálja az API verzióját és az erőforrás sémáját. A Kubernetes támogatja több API verzió fenntartását is, ami segít a visszafelé kompatibilitás biztosításában az API evolúciója során.

  • `name`: Az API verzió neve, pl. `v1`.
  • `served`: Ha `true`, akkor az API szerver kiszolgálja ezt a verziót.
  • `storage`: Ha `true`, akkor az API szerver ebbe a verzióba tárolja az objektumokat az etcd-ben. Pontosan egy verzió lehet `storage: true`.
  • `schema.openAPIV3Schema`: Itt definiálja az egyedi erőforrás struktúráját egy OpenAPI v3 séma segítségével. Ez a séma rendkívül fontos a bemeneti adatok validálásához és a kubectl explain parancs működéséhez. Ez biztosítja, hogy csak érvényes struktúrájú objektumokat lehessen létrehozni.
  • `subresources` (opcionális): Lehetővé teszi, hogy bizonyos beépített al-erőforrásokat (pl. `status`, `scale`) használjon az egyedi erőforráshoz. Ez például hasznos a kubectl scale parancs engedélyezéséhez.

  versions:
    - name: v1
      served: true
      storage: true
      schema:
        openAPIV3Schema:
          type: object
          properties:
            apiVersion:
              type: string
            kind:
              type: string
            metadata:
              type: object
            spec:
              type: object
              properties:
                title:
                  type: string
                  description: A blog post címe
                author:
                  type: string
                  description: A blog post szerzője
                content:
                  type: string
                  description: A blog post tartalma (Markdown)
                published:
                  type: boolean
                  description: Jelezze, hogy a bejegyzés publikálva van-e
                  default: false
              required:
                - title
                - author
                - content
            status:
              type: object
              properties:
                state:
                  type: string
                  description: A blog post aktuális állapota (pl. "draft", "published", "archived")
                publicationDate:
                  type: string
                  description: Publikálás dátuma
                  format: date-time

Egy egyedi erőforrás (CR) létrehozása és használata

Miután létrehoztuk és alkalmaztuk a CRD-t a klaszterünkön (kubectl apply -f my-crd.yaml), az API szerver azonnal felismeri az új erőforrást. Ezt ellenőrizhetjük a kubectl api-resources | grep blogposts paranccsal.

Most már létrehozhatunk egy példányt a BlogPost típusú egyedi erőforrásból:


# my-blogpost.yaml
apiVersion: example.com/v1
kind: BlogPost
metadata:
  name: elso-blogbejegyzsem
  namespace: default
spec:
  title: "A Kubernetes API kiterjesztése CRD-vel"
  author: "Gipsz Jakab"
  content: |
    Ez az első bejegyzésem, amely a Kubernetes CRD-kről szól.
    Nagyon izgalmas téma!
  published: true

Alkalmazzuk a klaszteren:


kubectl apply -f my-blogpost.yaml

És lekérdezhetjük, akárcsak bármely más Kubernetes erőforrást:


kubectl get blogpost
kubectl get bp elso-blogbejegyzsem -o yaml
kubectl describe blogpost elso-blogbejegyzsem

Láthatjuk, hogy az egyedi erőforrásaink ugyanolyan natív módon illeszkednek a Kubernetes ökoszisztémájába, mint a beépített erőforrások.

A Controller szerepe: Az agy az egyedi erőforrás mögött

A CRD önmagában csak a struktúrát és a sémát definiálja. Nem végez semmilyen műveletet. Ahhoz, hogy egy egyedi erőforrás létrehozása, frissítése vagy törlése valós hatást váltson ki a klaszteren belül (pl. Podokat hozzon létre, adatbázist telepítsen, beállítsa a replikációt), szükség van egy controllerre.

A controller egy olyan alkalmazás, amely figyeli (watch) az egyedi erőforrások állapotát a Kubernetes API-n keresztül. Amikor egy CR-en változás történik (pl. új CR jön létre, vagy egy meglévő CR `spec` mezője módosul), a controller észleli ezt a változást. Ekkor elindul a reconciliation loop (egyeztetési ciklus): a controller összehasonlítja a CR-ben leírt kívánt állapotot a klaszter aktuális állapotával, és megteszi a szükséges lépéseket a kívánt állapot eléréséhez. Ez magában foglalhatja Podok, Deploymentek, Service-ek, PersistentVolumeClaim-ek létrehozását, frissítését vagy törlését, vagy akár külső rendszerek (pl. felhőszolgáltatók API-ja) hívását.

Ez a minta az úgynevezett Operator Pattern alapja. Az Operatorok lényegében controller-ek, amelyek egyedi, domain-specifikus tudást kódolnak magukba, hogy automatizálják az összetett alkalmazások (pl. adatbázisok, üzenetsorok) telepítését, menedzselését és működtetését a Kubernetesen. A CRD-k adják az Operatorok számára a „nyelvet”, amellyel a felhasználók deklaratívan leírhatják a kívánt alkalmazás-specifikus állapotot.

A CRD-k előnyei és ereje

  • Rugalmas API kiterjesztés: A Kubernetes alapfunkcióinak módosítása nélkül adhat hozzá új erőforrásokat, amelyek tökéletesen illeszkednek az API-hoz.
  • Deklaratív menedzsment: Lehetővé teszi az egyedi, domain-specifikus erőforrások deklaratív kezelését, ugyanazzal a konzisztens felhasználói élménnyel, mint a beépített Kubernetes erőforrások esetében.
  • Absztrakció és automatizálás: Magasabb szintű absztrakciókat biztosít, elrejtve az alacsony szintű részleteket. Ezzel automatizálhatja az összetett infrastruktúra és alkalmazás műveleteket.
  • Az Operator Pattern alapja: Elengedhetetlen az Operatorok fejlesztéséhez, amelyek a „felhőnatív operátorok” szerepét töltik be, automatizálva a bonyolult alkalmazások életciklusát.
  • Integráció a Kubernetes ökoszisztémába: Az egyedi erőforrások kihasználhatják a Kubernetes beépített funkcióit, mint például a RBAC (szerepkör alapú hozzáférés-vezérlés), audit naplózás, kubectl parancsok, és az API szerver validációs képességei.
  • Verziózás és életciklus-kezelés: A CRD-k támogatják a több API verziót, ami lehetővé teszi az erőforrások API-jának evolúcióját anélkül, hogy megtörné a meglévő kompatibilitást.

Haladó CRD funkciók

A CRD-k nem állnak meg az alapvető séma-definíciónál. Számos haladó funkciót kínálnak a még nagyobb rugalmasságért:

  • Validáló és mutáló Webhookok (Admission Webhooks): Míg az OpenAPI séma alapvető validációt biztosít, a webhookok lehetővé teszik komplex, dinamikus validációs és módosítási logikák implementálását külső HTTP szolgáltatásokon keresztül. Például ellenőrizhetik, hogy egy bizonyos mező értéke egyezik-e egy másik erőforrásban lévő értékkel, vagy alapértelmezett értékeket állíthatnak be a létrehozás során.
  • Al-erőforrások (Subresources): Lehetővé teszi, hogy bizonyos URL útvonalakhoz (pl. `/status`, `/scale`) specifikus viselkedést definiáljon. A `status` al-erőforrás különösen hasznos, mivel a controller ide írja az aktuális állapotot, elkülönítve a felhasználó által kívánt `spec` állapottól. A `scale` al-erőforrás lehetővé teszi az erőforrások skálázását a standard kubectl scale paranccsal.
  • Több verzió kezelése és konverziós webhookok: A CRD-k képesek több API verziót (pl. `v1alpha1`, `v1beta1`, `v1`) egyidejűleg kiszolgálni. Amikor egy felhasználó egy régi verziójú objektumot kér le, de az etcd-ben egy újabb verzió van tárolva, vagy fordítva, a Kubernetes automatikusan konvertálja az objektumot. Komplexebb konverziós logikához konverziós webhookok használhatók.

Gyakorlati tanácsok és legjobb gyakorlatok

  • Tervezze meg az API-t gondosan: Mielőtt elkezdené, gondolja át, milyen mezőkre van szüksége, milyen típusúak legyenek, és milyen validációs szabályok vonatkozzanak rájuk. Az API legyen intuitív és felhasználóbarát.
  • Használjon szigorú OpenAPI sémát: Minél részletesebb és pontosabb a séma, annál kevesebb hibás konfiguráció csúszhat át, és annál jobban működik a kubectl explain.
  • Kezelje a verziókat: Kezdje `v1alpha1` vagy `v1beta1` verzióval a kísérleti fázisban, és lépjen `v1`-re, amikor az API stabil. Tervezze meg az API evolúcióját és a konverziót.
  • Dokumentálja az erőforrásokat: Használja a `description` mezőket az OpenAPI sémában, hogy a kubectl explain parancs hasznos információkat szolgáltasson.
  • Tesztelje alaposan a controllert: A controller a CRD szíve és lelke. Győződjön meg róla, hogy minden élmezőt és hibahelyzetet megfelelően kezel.
  • RBAC: Ne feledkezzen meg a megfelelő szerepkör alapú hozzáférés-vezérlés beállításáról, hogy a felhasználók és szolgáltatásfiókok csak a szükséges jogokkal rendelkezzenek az egyedi erőforrásokhoz.

Valós példák a CRD-k használatára

A CRD-k széles körben elterjedtek a Kubernetes ökoszisztémában. Számos népszerű projekt használja őket az egyedi absztrakciók biztosítására:

  • Prometheus Operator: A Prometheus metrika gyűjtő rendszer Kubernetesen való telepítését és menedzselését automatizálja olyan egyedi erőforrások segítségével, mint a `Prometheus`, `ServiceMonitor`, `Alertmanager`.
  • Istio: A Service Mesh, amely olyan erőforrásokat definiál, mint a `VirtualService`, `Gateway`, `DestinationRule` a hálózati forgalom szabályozására.
  • Crossplane: Egy Control Plane, amely lehetővé teszi, hogy külső felhőszolgáltatásokat (adatbázisok, üzenetsorok stb.) kezeljen Kubernetes erőforrásként, CRD-k segítségével.
  • Adatbázis Operatorok: Számos adatbázis (pl. CrunchyData PostgreSQL Operator, MongoDB Community Operator) használ CRD-ket a komplex adatbázis klaszterek telepítéséhez és életciklus-kezeléséhez.

Összefoglalás

A Custom Resource Definition (CRD) a Kubernetes egyik legerőteljesebb kiterjesztési mechanizmusa, amely radikálisan növeli a platform rugalmasságát és automatizálási képességét. Lehetővé teszi a fejlesztők és üzemeltetők számára, hogy a saját domainjüknek megfelelő absztrakciókat hozzanak létre, és azokat a Kubernetes natív módon kezelje. Ezáltal a Kubernetes nem csupán egy konténer orchestrátor, hanem egy általános célú vezérlősík (control plane) is lesz, amely képes bármilyen típusú infrastruktúra vagy alkalmazás életciklusának menedzselésére. A CRD-k és az azokra épülő Operatorok forradalmasítják a felhőnatív alkalmazások fejlesztését és üzemeltetését, egy olyan jövő felé mutatva, ahol az infrastruktúra menedzsmentje teljesen deklaratív és automatizált.

Leave a Reply

Az e-mail címet nem tesszük közzé. A kötelező mezőket * karakterrel jelöltük