Legutóbb a KubernetesDeployments világába néztünk bele, most nézzünk egy újabb fejezetet: mi történik az adatokkal, amikor egy container vagy Pod eltűnik.
A containerek eredetileg úgy lettek megtervezve, hogy ideiglenesek, azaz transient jellegűek legyenek. Ha egy container újraindul vagy törlődik, minden benne tárolt adat elvész vele együtt. Ez remekül működik stateless alkalmazásoknál, de egy adatbázis, egy feltöltött fájl vagy egy session cache esetében ez komoly probléma. Erre a problémára ad választ a Kubernetes Volume koncepciója.
A Volume alapjai
A Volume egy olyan könyvtár, amelyet a Kubernetes elérhetővé tesz a Pod konténerei számára, és amelynek élettartama a Pod élettartamához kötődik, nem az egyes konténerekéhez. Ha egy container a Pod-on belül újraindul, az adat megmarad, mert a Volume túléli a container újraindítását.
A Volume definiálásához három dolog szükséges: egy név, egy típus és egy mount point, vagyis hogy a container fájlrendszerében hol jelenjen meg. Ugyanaz a Volume több container között is megosztható egy Pod-on belül, ami praktikus container-to-container kommunikációra is használható.
A legegyszerűbb típus az emptyDir, amely egy üres könyvtárat hoz létre, és a Pod törlésekor a tartalma is eltűnik. Egy egyszerű példa:
Ez a Pod egy /cache könyvtárat hoz létre a containeren belül, amely addig él, amíg maga a Pod fut. Van még a hostPath típus is, amely a node fájlrendszeréről mountol be egy erőforrást, illetve léteznek cloud-specifikus típusok is, mint az AWS EBS, az Azure Disk vagy a GCP Persistent Disk. Ezeket ma már jellemzően a CSI, vagyis Container Storage Interface szabvány mögött érdemes elérni, mert ez teszi lehetővé, hogy a storage gyártók egységes drivereket fejlesszenek, függetlenül a Kubernetes core kódjától.
Fontos tudni, hogy a Volume-ok között nincs beépített concurrency védelem. Ha két container ugyanabba a megosztott Volume-ba ír, semmi nem védi meg őket attól, hogy felülírják egymás adatait. Ezt a Kubernetes szándékosan nem oldja meg helyetted, ezt az alkalmazás szintjén kell kezelni.
Amikor a Pod-nál tovább kell élnie az adatnak
Az emptyDir és a hostPath jó megoldás ideiglenes adatokra, de mi van, ha az adatnak túl kell élnie a Pod törlését is? Erre való a Persistent Volume, röviden PV.
A Persistent Volume egy tárolási absztrakció, amely függetlenül létezik a Pod-tól. A Pod nem közvetlenül a PV-t használja, hanem egy Persistent Volume Claim, azaz PVC objektumon keresztül igényli azt, megadva a szükséges méretet és hozzáférési módot. A cluster ezután megkeresi és hozzárendeli a megfelelő PV-t a Claim-hez.
A hozzáférési módnak három típusa van:
A ReadWriteOnce esetén egyetlen node írhatja a Volume-ot.
A ReadOnlyMany esetén több node olvashatja.
A ReadWriteMany esetén pedig több node is írhatja egyszerre.
A perzisztens tárolásnak több fázisa van:
A Provision során létrejön a PV, akár előre a cluster adminisztrátora által, akár dinamikusan a cloud provider felől.
A Bind fázisban a cluster összeköti a PVC-t egy megfelelő PV-vel.
A Use fázisban a Pod ténylegesen használja a tárhelyet.
A Release során a PVC törlésével felszabadul a kötés.
Végül a Reclaim fázis dönt arról, mi történjen az adattal: megmaradjon Retain policy mellett, törlődjön Delete policy mellett, vagy egy régebbi, ma már kivezetés alatt álló megoldásként, a Recycle töröljön mindent és váljon újra felhasználhatóvá.
Dynamic Provisioning: amikor nem kell kézzel PV-t létrehozni
Ha minden PV-t egyesével kellene manuálisan létrehozni, az gyorsan kezelhetetlenné válna egy nagyobb clusterben. Erre a problémára ad megoldást a Dynamic Provisioning: a StorageClass API objektum meghatároz egy provisionert és a hozzá tartozó paramétereket, a PVC pedig ezen keresztül automatikusan kap egy új PV-t, amikor szükség van rá.
Ez a gyakorlatban azt jelenti, hogy egy fejlesztőnek elég csak egy PVC-t igényelnie a megfelelő StorageClass-szal, és a mögöttes tárhely, legyen szó AWS EBS volumeról, Azure Disk-ről vagy GCP Persistent Diskről, automatikusan létrejön a cloud providernél.
Amire érdemes figyelni
Az egyik dolog, amit rendszeresen visszatérő jelenség, a Reclaim Policy beállítása. Ha egy PV Retain policyt kap, a mögöttes tárhely a PVC törlése után is megmarad, és tovább számlázza a cloud provider, csendben, a háttérben. Fejlesztői környezetekben ez könnyen elszabadulhat, ha senki nem takarítja el az elfelejtett PV-ket.
A másik gyakori csapda, amikor valaki ReadWriteMany hozzáférést feltételez egy olyan storage típusnál, amely csak ReadWriteOnce-t támogat. Ez általában akkor derül ki, amikor egy második Pod egy másik node-on FailedAttachVolume hibával nem tud elindulni.
Ebben a cikkben szándékosan nem tértem ki a StorageClass részletes paraméterezésére, sem a snapshot és backup stratégiákra. Ezek fontosak lesznek, amint éles, több node-os környezetben kell megtervezni a tárolást, de kezdésnek elég, ha érted az alapfogalmakat és a köztük lévő kapcsolatot.
Összegezve
A Volume, a Persistent Volume és a Persistent Volume Claim hármasa adja a Kubernetes tárolási modelljének a gerincét. Ha ezt a három fogalmat és az egymáshoz való viszonyukat érted, onnantól már csak a konkrét cloud provider driverek sajátosságait kell megismerned, és azok jellemzően jól dokumentáltak mind AWS, mind Azure, mind GCP oldalon.
Nézzünk egy újabb fejezetet a Kubernetes világából. Eddig szó volt arról, mi történik valójában egy Deployment mögött, aztán körbejártuk a workloadokat – a DaemonSeteket, StatefulSeteket és az autoscalingot -, majd a namespace-ek rendteremtő szerepét is megnéztük. A mai témám szorosan kapcsolódik mindehhez: mi történik akkor, amikor egy alkalmazás már nem egy-két manifestből áll, hanem tucatnyiból, és ezeket kell valahogy kezelhető állapotban tartani.
Ez a kérdés az utóbbi időben egyre fontosabb, ahogy egyre több AI szolgáltatás működik a Kubernetes cluster-eken is. Egy ilyen rendszer – modell-kezelő szolgáltatás, adatfeldolgozó pipeline, külső API, felügyelet – könnyen tíz-húsz külön manifestet igényel, ezek pedig gyorsan elburjánzanak, ha nincs mögöttük rendszerezettség. Erre a problémára született két, ma is aktívan használt eszköz: a Helm és a Kustomize.
Mielőtt összecsapnak a fejünk felett a hullámok
Egy éles, több komponensből álló alkalmazásnak szinte mindig van saját Deployment, Service, ConfigMap, Secret és gyakran Ingress manifestje is. Ez fejlesztői gépen még átlátható, de amint verziózni, több környezetben – fejlesztés, teszt, éles – telepíteni, majd frissíteni is kell ezeket, a kézi YAML szerkesztés hamar kezelhetetlenné és problémaforrássá válik. Ennek megoldására használjuk a két, egymástól eltérő filozófiájú eszközt a Kubernetes világában: a Helm és a Kustomize.
A Helm mint csomagkezelő
A Helm működési modellje sokat emlékeztet a hagyományos csomagkezelőkre, mint amilyen a yum vagy az apt Linux alatt. Egy Helm chart egy archivált gyűjteménye azoknak a Kubernetes manifest-eknek, amelyek együtt alkotnak egy alkalmazást. Ahelyett, hogy külön-külön kellene alkalmazni a Deployment, a Service és a ConfigMap fájlokat, a Helm ezeket egyetlen állományba csomagolja, amit egyetlen paranccsal lehet telepíteni, frissíteni vagy visszaállítani egy korábbi verzióra.
Ez a megközelítés több gyakorlati előnnyel jár. A chartok verziózhatók, tehát pontosan tudni lehet, melyik alkalmazásverzió fut a clusterben. Ha egy frissítés problémát okoz, a rollback paranccsal gyorsan vissza lehet állni egy stabil állapotra, minimalizálva a leállást és a kieséset. A konfiguráció a values.yaml fájlon vagy parancssori paramétereken keresztül környezetenként testreszabható, így ugyanaz a chart más beállításokkal futtatható fejlesztői és éles környezetben is. A Helm emellett jól illeszkedik a CI/CD folyamatokba, mögötte pedig egy aktív közösség áll, amely rengeteg előre elkészített chartot biztosít gyakori alkalmazásokhoz.
Egy tipikus chart felépítése viszonylag egyszerű logikát követ. A Chart.yaml fájl a metaadatokat tartalmazza, mint a chart neve, verziója és kulcsszavai.
apiVersion: v2
name: hello-world
description: A Helm chart for Kubernetes
type: application
version: 0.1.0
appVersion: "1.16.0"
A values.yaml azokat az alapértelmezett kulcs-érték párokat tartja, amelyeket a telepítés során lehet felülírni.
A templates mappa tartalmazza magukat a manifesteket – például egy deployment.yaml, egy svc.yaml, egy configmap.yaml vagy egy secrets.yaml fájlt -, amelyek Go templating szintaxist használnak. Ez azt jelenti, hogy a manifestekben szereplő változók, mint egy jelszó vagy egy név, a values.yaml-ból töltődnek be a telepítés pillanatában. Egy jó chart README.md fájlt is tartalmaz, amiben gyakran olyan előfeltételek szerepelnek, mint egy szükséges persistent volume megléte, ezért telepítés előtt mindig érdemes ezt átolvasni.
A chartokat repository-k tárolják, amelyek technikailag egyszerű HTTP szerverek egy index fájllal és a chartok tarballjaival. Mielőtt hozzáadnál egy repository-t, a helm search hub paranccsal az Artifact Hubon kereshetsz. Ha hozzáadtál egy repository-t, például a helm repo add paranccsal, utána a helm search repo segítségével kereshetsz benne, majd a talált chartot egyetlen helm install paranccsal telepítheted. A telepítés kimenetét mindig érdemes alaposan átnézni, mert gyakran ez tartalmazza az első nyomokat arra, ha egy szükséges cluster-erőforrás hiányzik.
A Kustomize más filozófiája
A Kustomize más utat választott. Míg a Helm templating nyelvet használ a változók behelyettesítésére, a Kustomize semmilyen sablon szintaxist nem igényel. Ehelyett egy alap, úgynevezett base konfigurációt definiálsz, majd overlay-ekkel írod felül vagy egészíted ki azt környezetenként – mondjuk a replikák számát, az image taget vagy egy címkét. A módosítások stratégiai merge és patch technikákkal történnek, nem szöveghelyettesítéssel.
Ennek gyakorlati előnye, hogy a Kustomize a kubectl része 1.14-es verziótól kezdve, tehát nincs szükség külön telepítésre – bár egy önálló bináris is elérhető, ha fejlettebb funkciókra van szükséged. A kubectl kustomize dir paranccsal megnézheted a végeredményt, a kubectl apply -k dir paranccsal pedig alkalmazhatod a clusteren.
A kustomization.yaml és a bázis-overlay felépítés
A Kustomize szíve a kustomization.yaml fájl, amely felsorolja, mely erőforrásokat kell kezelni, és milyen módosításokat kell rájuk alkalmazni. A jól szervezett projekt mappastruktúrája jellemzően egy base mappát tartalmaz a közös konfigurációval, illetve külön overlays/dev és overlays/prod mappákat a környezet-specifikus eltérésekkel, elkerülve ezzel a YAML fájlok másolgatását. A kustomization.yaml-ban beállítható például egy namePrefix, ami minden erőforrás nevéhez hozzáfűz egy előtagot – egy myapp-deployment nevű erőforrásból így lesz lf-myapp-deployment -, illetve közös címkék és annotációk is hozzáadhatók minden erőforráshoz, ami a clusteren belüli szűréshez és szervezéshez hasznos. A patchek finomhangolt, egyedi módosításokra valók, mint egy környezeti változó hozzáadása, míg a transzformerek szélesebb körű, minden erőforrásra vonatkozó módosításokat végeznek. A Kustomize emellett generátorokat is kínál ConfigMapek és Secretek dinamikus létrehozására, akár literál értékekből, akár fájlokból.
Nincs egyetlen helyes válasz. A Helm akkor kiváló választás, amikor egy alkalmazást csomagként szeretnél telepíteni, verziózni és mások számára újrafelhasználhatóvá tenni – gondolj például egy adatbázis motorra. A Kustomize akkor kényelmesebb, amikor saját, meglévő YAML fájljaidat szeretnéd környezetenként kis mértékben testre szabni, sablonok használata nélkül.
A kettő egyébként nem is zárja ki egymást: gyakori előfordul, hogy egy Helm chartot Kustomize-zal utólag testre szabnak.
Amit tapasztalatból mindenképp kiemelnék: sokan telepítenek egy közösségi chartot anélkül, hogy elolvasnák a README-t vagy átnéznék a values.yaml alapértelmezett értékeit. Ez ott szokott fájni, amikor kiderül, hogy egy alapértelmezett jelszó vagy egy nem megfelelő erőforrásigény került éles környezetbe. Ugyanígy a Kustomize overlay-eknél is érdemes tudatosan megtervezni az alap és a környezet-specifikus rétegek határát, különben pont az a rugalmasság vész el, amiért ezeket az eszközöket eredetileg bevezették: az átláthatóság és a megismételhetőség.
Egy ideje már nem írtam cikket a Kubernetes-ről, pedig mint tudjátok szeretem ezt a témát. Amikor a Kubernetes API-ról írtam, sokan kérdezték, hogy jó, de mi történik egy deployment esetén valójában, amikor kiadunk egy kubectl apply parancsot. Most erről szeretnék írni nektek: mi zajlik a színfalak mögött, amikor egy Deployment-et létrehozunk, frissítünk, vagy éppen visszaállítunk egy korábbi verzióra.
Mi történik, amikor létrehozunk egy Deployment-et
A Deployment egy YAML vagy JSON specifikációból épül fel. Amint bekerül a clusterbe, a controller automatikusan létrehoz egy ReplicaSet-et, az pedig legenerálja a Podokat. Ha egy egyszerű nginx web szervert szeretnénk futtatni, a parancs ennyi:
A rendszer válasza egyszerű visszaigazolás, hogy a deployment létrejött. Ha meg akarjuk nézni, mi került létre a háttérben, a kubectl get deployments,rs,pods -o yaml paranccsal kérhetjük le a teljes objektumfát. Én gyakran ezzel kezdek, amikor egy hibát próbálok visszakövetni, mert így látom, hogy a Deployment, a ReplicaSet és a Pod pontosan hogyan kapcsolódik egymáshoz.
Hogyan is néz ez akkor ki? Mik a fő összetevői?
A metadata blokk – mit érdemes tudni róla
Minden objektumnak van egy metadata szekciója, amiben nem a működést, hanem az azonosítást és a nyomon követést segítő adatok vannak. Itt találjuk a labeleket, az annotációkat, a létrehozás időpontját (creationTimestamp), valamint egy uid mezőt, amely az objektum egész életciklusa alatt egyedi marad. A generation mező azt mutatja, hányszor módosították az objektumot – ez praktikus, ha egy rollout történetét szeretnénk visszakövetni.
Fontos különbség, hogy az annotációk nem használhatók objektumok kiválasztására kubectl paranccsal, ellentétben a labelekkel. Ezt sokan összekeverik kezdőként, pedig a különbség lényegi: az annotáció információt hordoz, a label viszont szelekciós eszköz.
A spec – itt dől el, hogyan frissül a rendszer
A Deployment specifikációjában két külön spec blokk van: az egyik a ReplicaSet-et, a másik a Podot konfigurálja. A ReplicaSet szintű spec tartalmazza a replikák számát (replicas), a selector.matchLabels mezőt, amely meghatározza, mely Podokat tekinti a rendszer a sajátjának, valamint a frissítési stratégiát.
A strategy mező alapértelmezetten RollingUpdate, ami azt jelenti, hogy a frissítés fokozatosan történik: a maxSurge határozza meg, hány új Pod jöhet létre a régiek törlése előtt, a maxUnavailable pedig azt, hány Pod lehet átmenetileg nem elérhető. Ha ezt Recreate-re állítjuk, a rendszer előbb töröl minden meglévő Podot, és csak azután hozza létre az újakat – ez egyszerűbb, de rövid kiesést okoz.
A Pod template – a konténer tényleges beállításai
A Deployment egyik legfontosabb része a Pod template, mert ez határozza meg, milyen konténer fut valójában. Itt szerepel az image neve és verziója, az imagePullPolicy, amely azt szabályozza, mikor töltse le újra a rendszer az image-et, valamint a restartPolicy, amely biztosítja, hogy egy leállt konténer automatikusan újrainduljon.
Érdemes megjegyezni, hogy a resources mező alapértelmezetten üres. Ez azt jelenti, hogy ha nem állítunk be CPU vagy memória limitet, a konténer korlátlanul foglalhatja ezeket az erőforrásokat. Ez az egyik leggyakoribb kezdő hiba, amit én is sokszor láttam: valaki elindít egy tesztelési célú Podot limit nélkül, és napok múlva veszi észre, hogy az felzabálja a node erőforrásait.
A status – amit a rendszer visszamond
A status blokk nem konfiguráció, hanem visszajelzés. Az availableReplicas és a readyReplicas összevetésével látjuk, hogy a kívánt állapot valóban létrejött-e. A conditions mezőben szöveges üzenetek is megjelennek, például hogy a Deployment elérte a minimális elérhetőséget, vagy hogy egy új ReplicaSet sikeresen kigördült. Az observedGeneration pedig azt mutatja, hányszor követte a rendszer a konfiguráció változását – ez jó kiindulópont, ha egy rollout állapotát szeretnénk diagnosztizálni.
A replikák száma egy egyszerű paranccsal módosítható:
kubectl scale deploy/dev-web --replicas=4
Ha a replikák számát nullára állítjuk, a konténerek megszűnnek, de a Deployment és a ReplicaSet objektum megmarad – ez pontosan az, ami a háttérben történik, amikor egy Deployment-et törlünk.
Nem minden mező módosítható szabadon, egyes értékek immutable-ek, ez verziófüggő. Az image verziójának módosítása viszont mindig lehetséges, és kubectl edit deployment paranccsal élőben is elvégezhető. Egy ilyen módosítás automatikusan elindítja a rolling update-et.
Ha valami elromlik – rollback
Az egyik legmegnyugtatóbb tulajdonsága a Deployment-eknek, hogy a korábbi ReplicaSet verziók megmaradnak, így vissza lehet állítani egy működő állapotot. Ha egy image frissítés hibás verzióra mutat, és a Podok ImagePullBackOff állapotba kerülnek, a kubectl rollout undo deployment/ghost paranccsal egyszerűen visszaléphetünk. Konkrét revízióra is visszaállhatunk a --to-revision opcióval. A kubectl rollout pause és resume parancsok pedig lehetővé teszik, hogy egy rollout közepén megállítsuk, majd később folytassuk a folyamatot.
DaemonSet – amikor minden node-on kell egy Pod
A DaemonSet más logikát követ, mint a Deployment: biztosítja, hogy minden node-on pontosan egy Pod fusson ugyanazzal az image-dzsel. Ha új node kerül a clusterbe, a DaemonSet automatikusan odatelepíti a Podot, ha egy node kikerül, a Pod is törlődik vele. Ez tipikusan logolási vagy metrika-gyűjtő ügynökök esetén hasznos, ahol fontos, hogy minden node-on futnia kelljen az adott komponensnek, anélkül, hogy erről manuálisan kellene gondoskodni.
Labelek – a cluster rendezésének kulcsa
A labelek nem API objektumok, mégis a Kubernetes-alapú üzemeltetés egyik legfontosabb eszközei. Bármilyen objektumhoz rendelhetünk kulcs-érték párokat, és ezek alapján szűrhetünk, csoportosíthatunk. A kubectl get pods -l run=ghost parancs pontosan ezt teszi lehetővé. Fontos, hogy egy Deployment label selectora apps/v1 API verziótól kezdve immutable, tehát létrehozás után már nem módosítható.
A labelek gyakorlati haszna a nodeSelector alkalmazásánál a legszemléletesebb: ha egy node-hoz disktype: ssd labelt rendelünk, egy Pod specifikációjában megadhatjuk, hogy csak ilyen node-ra kerüljön ki. Ez egyszerű, de sokat elárul arról, hogy a Kubernetes tervezésekor mennyire tudatosan gondolták végig a rugalmas, ám átlátható erőforrás-kezelést.
És mi a lényeg?
A Deployment látszólag egyszerű objektum, de a mögötte húzódó réteges struktúra – metadata, spec, template, status – valójában egy jól megtervezett állapotgép. Aki most kezd Kubernetes-szel dolgozni, annak érdemes megszokni, hogy minden változás egy új ReplicaSet-et generál, és hogy a resources mező üresen hagyása előbb-utóbb kellemetlen meglepetést hoz. Ez az egyik legjellemzőbb kezdő csapda, amivel én is sokszor szembesültem: a rendszer működik, csak épp senki nem korlátozta, mennyi erőforrást használhat.
Ha valaki mélyebben szeretné megérteni ezt a réteges logikát, a managed Kubernetes szolgáltatások, mint az AzureAKS, az AWS EKS vagy a Google CloudGKE, jó kiindulópontot adnak, mert ugyanezt az alapstruktúrát használják, csak a klaszter üzemeltetését veszik le a fejlesztő kezéből.
A Kubernetes számomra egy megunhatatlan téma. Nem csupán azért, mert a mikroszolgáltatások futtatásának központi eleme, hanem egy olyan izgalmas világ, ami komplexitása ellenére, logikusan működik.
A vállalatok digitális jelenlétének erősítésében ma már kulcsszerepet játszik az, hogy az alkalmazások gyorsan telepíthetők, skálázhatók és megbízhatóan működtethetők legyenek. A Kubernetes pontosan erre van kitalálva. Egy jól felépített rendszerben az alkalmazások nem egyetlen szerveren futnak, hanem egy cluster több node-ján oszlanak el. Ez a megközelítés nemcsak nagyobb rendelkezésre állást biztosít, hanem lehetővé teszi a dinamikus skálázást és az automatizált működést is.
Ma néhány olyan Kubernetes API objektumot fogunk megnézni, amelyek az alkalmazások futtatásának és működtetésének alapját jelentik. Ezek az objektumok határozzák meg, hogyan indulnak el a Pod-ok, hogyan skálázódnak az alkalmazások, hogyan futnak batch feladatok, illetve hogyan kezelhető a hozzáférés a cluster erőforrásaihoz.
Deployment és az alkalmazások telepítése
Amikor egy alkalmazást telepítünk Kubernetes-ben, ritkán hozunk létre közvetlenül Pod-ot. A gyakorlatban szinte mindig egy magasabb szintű vezérlő objektumot használunk.
A leggyakoribb ilyen objektum a Deployment. A Deployment egy controller, amely a ReplicaSetek és a Podok állapotát kezeli. Ez a magasabb szintű absztrakció lehetővé teszi, hogy az alkalmazások frissítése, skálázása és adminisztrációja rugalmasabb legyen.
A működés láncolata a következő:
Deployment → ReplicaSet → Pod
A Pod a Kubernetes legkisebb kezelhető egysége. Egy Pod tipikusan egy vagy több konténert tartalmaz, amelyek együtt futnak és ugyanazt a hálózati valamint tárolási környezetet használják.
A ReplicaSet feladata, hogy biztosítsa a kívánt számú Pod folyamatos működését. Ha például három Pod futását határozzuk meg, a ReplicaSet gondoskodik arról, hogy mindig három példány fusson. Ha egy Pod leáll, a rendszer automatikusan újat indít.
A Deployment ezen a szinten egy további irányítási réteget ad. Lehetővé teszi például a rolling update frissítéseket, amikor az új verziók fokozatosan kerülnek bevezetésre anélkül, hogy az alkalmazás leállna.
DaemonSet: Pod minden node-on
Bizonyos típusú alkalmazásoknak minden node-on futniuk kell egy clusterben. Erre szolgál a DaemonSet.
A DaemonSet biztosítja, hogy egy adott Pod minden node-on fusson a clusterben. Amikor egy új node kerül a clusterbe, a DaemonSet automatikusan elindítja rajta a megfelelő Podot. Amikor pedig egy node eltávolításra kerül, a hozzá tartozó Pod is megszűnik.
Ez a megközelítés különösen hasznos olyan rendszerszintű komponensek esetében, mint például:
loggyűjtő rendszerek
monitoring agentek
biztonsági ellenőrző komponensek
Ezeknek az alkalmazásoknak minden node-on jelen kell lenniük ahhoz, hogy teljes képet kapjanak a cluster állapotáról.
StatefulSet: állapotot kezelő alkalmazások
A legtöbb konténeres alkalmazás stateless módon működik, vagyis a Podok felcserélhetők. Egy Pod megszűnése vagy újraindulása nem jelent problémát.
Vannak azonban olyan alkalmazások, ahol a Pod identitása fontos. Ilyenek például az adatbázisok.
Ezek kezelésére szolgál a StatefulSet. A StatefulSet olyan Kubernetes workload objektum, amely állapotot kezelő alkalmazások működtetésére készült.
A StatefulSet egyik legfontosabb tulajdonsága, hogy minden Pod egyedi identitással rendelkezik. Ez az identitás három elemből áll:
stabil tároló
stabil hálózati azonosító
sorszámozás (ordinal)
A Podok tipikusan sorban indulnak el, például:
app-0
app-1
app-2
Az új Pod csak akkor indul el, ha az előző már sikeresen fut. Ez eltér a Deployment viselkedésétől, ahol a Pod-ok párhuzamosan indulnak.
Ez a viselkedés kulcsfontosságú olyan rendszerek esetében, ahol az indulási sorrend vagy az állapotmegőrzés kritikus.
Autoscaling: automatikus skálázás
A Kubernetes egyik legerősebb képessége az automatikus skálázás.
Az egyik leggyakrabban használt megoldás a Horizontal Pod Autoscaler, röviden HPA. Ez az objektum automatikusan növeli vagy csökkenti a Podok számát egy Deployment, ReplicaSet vagy Replication Controller esetében.
Alapértelmezés szerint a HPA a CPU használat alapján skáláz. Ha a CPU kihasználtság eléri a 80 százalékot, a rendszer új Pod-okat indíthat. A metrikákat a kubelet gyűjti, majd a Metrics Server API-n keresztül érhetők el.
Amikor több Pod-ra van szükség, a rendszer azonnal reagál. Ha viszont csökkenteni kell a Pod-ok számát, a HPA alapértelmezés szerint 300 másodpercet vár, mielőtt új döntést hozna.
A Kubernetes-ben létezik egy másik autoscaling mechanizmus is, a Cluster Autoscaler. Ez már nem Pod-okat, hanem node-okat kezel.
Ha egy Pod nem helyezhető el a cluster-en a rendelkezésre álló erőforrások miatt, a Cluster Autoscaler új node-okat hozhat létre. Ha pedig a node-ok kihasználtsága alacsony, a rendszer idővel eltávolíthatja őket.
Ez különösen fontos felhő környezetben, ahol a nem használt erőforrások költséget jelentenek.
Jobs és CronJobs
Nem minden Kubernetes workload egy folyamatosan futó alkalmazás.
Vannak olyan feladatok, amelyeknek csak egyszer kell lefutniuk, vagy meghatározott időpontokban kell végrehajtódniuk. Erre szolgálnak a Job és a CronJob objektumok.
A Job egy batch feldolgozási mechanizmus, amely meghatározott számú Pod sikeres lefutását biztosítja. Ha egy Pod hibával áll le, a rendszer újraindítja addig, amíg a feladat sikeresen be nem fejeződik.
A Job specifikációjában két fontos paraméter található:
parallelism: ez határozza meg, hogy hány Pod futhat egyszerre.
completions: hány sikeres futás szükséges a Job befejezéséhez.
A CronJob a Linux cron működéséhez hasonló időzített futtatást biztosít. Ugyanazt az időszintaxist használja, így például könnyen létrehozható egy napi vagy óránként futó feladat.
Fontos megjegyezni, hogy egy CronJob esetében a futó Podnak idempotensnek kell lennie, mert bizonyos esetekben előfordulhat, hogy egy feladat kétszer is elindul.
RBAC: hozzáférések kezelése
Egy Kubernetes clusterben a biztonság és a hozzáféréskezelés kulcsfontosságú kérdés.
ClusterRoleBinding (cluster szintű szerepkör-hozzárendelés)
Ezek segítségével meghatározhatjuk, hogy egy felhasználó vagy szolgáltatás milyen műveleteket hajthat végre a cluster-ben.
Például létrehozhatunk egy Role-t, amely csak Pod-ok olvasását engedélyezi egy adott namespace-ben. Egy másik Role pedig lehetőséget adhat Deployment objektumok létrehozására, de például Service objektumokra már nem.
A RoleBinding és a ClusterRoleBinding feladata az, hogy ezeket a szerepköröket felhasználókhoz vagy szolgáltatásfiókokhoz rendeljék.
Ez a modell lehetővé teszi a legkisebb szükséges jogosultság elvének alkalmazását, ami alapvető biztonsági gyakorlat a modern infrastruktúrákban.
Összegzés
A Kubernetes működésének megértéséhez elengedhetetlen az API objektumok ismerete. A Deployment, DaemonSet, StatefulSet, Job, valamint az autoscaling és az RBAC mind olyan alapvető építőelemek, amelyek meghatározzák, hogyan futnak és működnek az alkalmazások egy clusterben.
A Deployment segít az alkalmazások verziókezelésében és skálázásában. A DaemonSet biztosítja a node-szintű komponensek működését. A StatefulSet lehetővé teszi az állapotot kezelő rendszerek stabil működését. A Job és a CronJob batch feldolgozási feladatokat old meg, míg az autoscaling mechanizmusok a dinamikus terheléshez igazítják az infrastruktúrát.
Végül az RBAC gondoskodik arról, hogy a hozzáférések biztonságosan és kontrollált módon legyenek kezelve.
Ha megértjük ezeknek az objektumoknak a szerepét, akkor már nemcsak alkalmazásokat tudunk futtatni Kubernetesben, hanem valóban képesek leszünk megbízható, skálázható és biztonságos rendszereket építeni.
Lassan egy éve, hogy elkezdtem írni a Kubernetes-ről és annak architektúrájáról, a microservice-alapú rendszerek működéséről és arról, hogyan vált a Kubernetes a modern alkalmazásfejlesztés egyik alappillérévé. Beszéltünk a klaszterek működéséről, a podok életciklusáról, a vezérlőkomponensek szerepéről.
Ezeken felül van egy réteg, amely mindezt összefogja. Beszéltünk már erről is több szempontból, de úgy éreztem érdemes további figyelem ennek a központi elemnek. Mert enélkül sem a kubectl, sem a vezérlők, sem az automatizmusok nem működnének.
Ez a réteg a Kubernetes API.
Olyan ez, mint egy jól szervezett város központi ügyfélszolgálata. Bármit szeretnénk elintézni – új erőforrást létrehozni, meglévőt módosítani, állapotot lekérdezni –, mindent ezen keresztül teszünk. A Kubernetes valójában egy API-vezérelt rendszer. Minden művelet, amit végrehajtunk, végső soron egy API-hívás.
Nézzük meg, hogyan érhetők el az API-erőforrások, milyen speciális végpontok léteznek, hogyan kapcsolódik ehhez a Swagger és az OpenAPI, valamint mit jelent az API-k érettségi modellje.
API erőforrások és a kubectl szerepe
A Kubernetes által publikált összes API-erőforrás elérhető a kubectl eszközön keresztül. A parancs alapformátuma:
kubectl [command] [type] [name] [flag]
A kubectl help parancs részletes információt ad az elérhető műveletekről és erőforrástípusokról.
A rendszer által elérhető API-erőforrások listája folyamatosan változhat, de az alapvető típusok közé tartoznak például:
pods (po)
services (svc)
deployments (deploy)
replicasets (rs)
statefulsets
daemonsets (ds)
jobs
cronjobs
configmaps (cm)
secrets
namespaces (ns)
nodes (no)
persistentvolumes (pv)
persistentvolumeclaims (pvc)
resourcequotas (quota)
limitranges (limits)
networkpolicies (netpol)
clusterroles
clusterrolebindings
roles
rolebindings
customresourcedefinition (crd)
Ez a lista jól mutatja, hogy a Kubernetes nem csupán podokat kezel. A klaszter működéséhez szükséges biztonsági, hálózati, tárolási és jogosultsági objektumok mind API-erőforrásként jelennek meg.
Fontos megérteni, hogy a kubectl valójában csak egy kliens az API server felé. Amikor például kiadjuk a következő parancsot:
kubectl get pods
a háttérben egy HTTP GET kérés történik az API server irányába. A kubectl nem tart fenn külön adatbázist, nem cache-el erőforrásokat önállóan. Minden információ az API-n keresztül érkezik.
Ez a modell teszi lehetővé, hogy a Kubernetes teljesen deklaratív és automatizálható rendszer legyen. Ugyanazokat az API-hívásokat használhatja egy operátor, egy CI/CD pipeline vagy egy egybinárisos vezérlőalkalmazás is.
További API-műveletek erőforrásokon
Az alapvető REST műveleteken túl a Kubernetes API speciális végpontokat is biztosít bizonyos erőforrásokhoz.
Például elérhetjük egy konténer naplóit közvetlen API-hívással:
GET /api/v1/namespaces/{namespace}/pods/{name}/log
Ez funkcionálisan megegyezik a következő paranccsal:
kubectl logs firstpod
Ha a konténer nem ír standard output-ra, akkor természetesen nem lesznek elérhető logok.
Hasonló módon létezik exec végpont is:
GET /api/v1/namespaces/{namespace}/pods/{name}/exec
Ez teszi lehetővé, hogy parancsot hajtsunk végre egy futó podban, például diagnosztikai célból.
Emellett létezik watch mechanizmus is:
GET /api/v1/watch/namespaces/{namespace}/pods/{name}
A watch végpont folyamatosan streameli az erőforrás változásait. Ez kulcsfontosságú a vezérlők működésében. A Kubernetes kontrollerei nem ciklikusan lekérdezik az állapotot, hanem figyelik az eseményeket, és a változásokra reagálnak.
Ez az eseményvezérelt működés biztosítja a rendszer hatékonyságát és skálázhatóságát.
Swagger és OpenAPI a Kubernetesben
A Kubernetes teljes API-ja eredetileg Swagger specifikáció alapján készült, és az idő múlásával az OpenAPI irányába fejlődött.
Ez rendkívül fontos, mert az OpenAPI leírás lehetővé teszi klienskód automatikus generálását. Ha rendelkezésre áll a specifikáció, abból generálható Go, Python, Java vagy más nyelvű klienskönyvtár.
A stabil erőforrás-definíciók elérhetők a hivatalos dokumentációban. Emellett a Swagger UI segítségével böngészhetők az API-csoportok, megtekinthetők a végpontok, paraméterek és válaszstruktúrák.
Ez a fajta formális API-leírás teszi lehetővé, hogy a Kubernetes ökoszisztéma ennyire gazdag legyen. Az operátorok, kliensek, SDK-k és automatizációs eszközök mind ugyanarra a formálisan definiált API-ra épülnek.
API-csoportok és verziózás
A Kubernetes API nem egy monolitikus struktúra. API-csoportokra és verziókra bontva épül fel.
Az API-csoportok és verziók használata lehetővé teszi, hogy a fejlesztés előrehaladjon anélkül, hogy egy meglévő API-csoport módosulna. Ez segíti a skálázható fejlesztést és a csapatok közötti munkamegosztást.
Fontos, hogy az API és a Kubernetes szoftververziója csak közvetetten kapcsolódik egymáshoz. Nem minden szoftverfrissítés jelent API-törést.
A Kubernetes API JSON és Google Protobuf szerializációs formátumokat használ, amelyek a kiadási irányelvekhez igazodnak.
Az API-verziók három érettségi szintbe sorolhatók:
Alpha
Beta
Stable
Alpha
Az alpha jelölésű funkciók kísérleti állapotban vannak. Alapértelmezetten le vannak tiltva. Hibásak lehetnek, bármikor változhatnak vagy eltűnhetnek, és nem garantált a visszafelé kompatibilitás.
Csak teszt klaszterben javasolt a használatuk, amelyet gyakran újraépítenek.
Beta
A beta szintű funkciók már jobban teszteltek, és alapértelmezetten engedélyezettek. A változások során figyelnek a visszafelé kompatibilitásra, de még nem tekinthetők teljesen stabilnak.
Előfordulhatnak hibák vagy viselkedésbeli módosulások.
Stable
A stable verziókat csak egy szám jelöli, például v1. Ezek stabil API-k, amelyekre hosszú távon lehet építeni. Jelenleg a v1 az egyetlen stabil verzió.
A verziózási rendszer biztosítja, hogy a klaszterben futó alkalmazások ne törjenek el egy frissítés során, és a platform evolúciója kontrollált módon történjen.
Miért fontos ez a gyakorlatban?
Ha Kubernetes környezetben dolgozol, akkor valójában folyamatosan az API-val dolgozol, akár tudatosan, akár nem.
Amikor YAML fájlt alkalmazol, amikor egy CI/CD pipeline deployol, amikor egy operátor létrehoz egy egyedi erőforrást CRD-n keresztül, minden az API-n keresztül történik.
Az API-csoportok és verziók ismerete segít:
• megérteni, hogy egy erőforrás mennyire stabil • eldönteni, hogy production környezetben használható-e • tervezni a frissítési stratégiát • automatizálási eszközöket építeni
A Kubernetes nem egyszerűen konténer-orchestration eszköz. Egy deklaratív, API-vezérelt platform, amely formálisan definiált interfészeken keresztül működik.
Ha ezt a réteget érted, akkor nem csak használod a klasztert, hanem érted is, hogyan gondolkodik.
És ez az a pont, ahol a Kubernetes már nem csak technológia, hanem architektúra.
Senki sem szereti a rendetlenséget. Akkor sem, ha nem vagyunk rendmániások. Valahol mindannyiunknak szüksége van arra a fajta belső nyugalomra, amit az ad, hogy a dolgok a helyükön vannak. Egy rendezett tér nem csak esztétikai kérdés: segít tisztábban gondolkodni, könnyebben eligazodni, és biztonságérzetet ad a mindennapokban.
Nincs ez másképp a Kubernetes cluster esetében sem. Amikor egyre több alkalmazást, podot, service-t és konfigurációt indítunk el, hamar rájövünk, hogy a rendszer saját “lakói” is igénylik a strukturáltságot. A Kubernetes pedig erre egy elegáns, mégis egyszerű megoldást kínál: a namespace-eket, amelyek láthatatlanul, de nagyon is hatékonyan teremtik meg azt a rendezettséget, amelyre egy növekvő clusternek szüksége van.
Mi az a namespace?
A Kubernetesben a namespace egy logikai szeparációs mechanizmus, amely csoportokra bontja a cluster erőforrásait. A fogalom eredetileg a Linux kernel világából származik: ott is az izoláció a cél, vagyis hogy különböző folyamatok saját, elkülönített erőforrás-nézetet kapjanak.
A Kubernetes ezt továbbgondolja: a namespace nem csupán technikai elszeparálás, hanem egy szervezési, erőforrás-kontroll és biztonsági keret is.
Lényeg:
Minden API-hívás egy namespace-en belül történik, hacsak nem adunk meg külön mást. Például: https://<api-server>/api/v1/namespaces/default/pods
A namespace lehetővé teszi a kvóták és limitációk alkalmazását egy adott csoport erőforrásaira.
Később az access control – például RBAC – is működhet namespace-szinten.
Ha csak néhány erőforrás van a clusterben, akkor a szükségessége nem mindig látszik. De nagyobb vállalati környezetben a namespace az egyik legfontosabb szervezési eszköz.
A Kubernetes alapértelmezett namespace-ei
Amikor egy új clustert létrehozunk, Kubernetes négy namespace-t hoz létre automatikusan. Ezek előre definiált szerepet töltenek be, és fontos, hogy ismerjük őket.
default
Az alapértelmezett namespace. Ha nem adunk meg explicit namespace-t egy API-hívásban vagy egy YAML-ben, minden ide kerül.
kube-system
Itt futnak a rendszer- és infrastruktúra szintű komponensek. Maga a Kubernetes működéséhez szükséges podok találhatók itt, például a DNS, a kontrollerek, scheduler stb.
kube-public
Ez egy mindenki számára olvasható namespace (még hitelesítetlen felhasználók számára is). Tipikusan olyan információkat tartalmaz, amelyeknek publikusnak kell lenniük.
kube-node-lease
Ez tárolja a node-ok „lease” objektumait. A control plane ezzel követi a node egészségi állapotát, gyorsabban és hatékonyabban, mint korábban.
Hogyan dolgozunk namespace-ekkel?
A namespace-ek egy része kimondottan szervezési célokat szolgál: a fejlesztői, tesztelési és éles környezet könnyen elkülöníthető, de akár csapatonként, projektenként vagy üzleti funkcióként is létrehozhatunk új namespace-eket.
A legfontosabb alapműveletek:
Meglévő namespace-ek listázása
kubectl get ns
Új namespace létrehozása
kubectl create ns sajat-projekt
Namespace részletes leírása
Megmutatja többek között a címkéket, annotációkat, kvótákat, limiteket.
kubectl describe ns sajat-projekt
Namespace tartalmának YAML formátumú lekérése
kubectl get ns/sajat-projekt -o yaml
Namespace törlése
kubectl delete ns sajat-projekt
Namespace használata YAML fájlokban
Ha egy erőforrást szeretnénk egy konkrét namespace-ben létrehozni, azt a metadata blokkban kell megadni:
apiVersion: v1
kind: Pod
metadata:
name: redis
namespace: sajat-projekt
Ez a mindennapi Kubernetes fejlesztés egyik alapja: a pod encapsulation, a resource isolation és a cluster szervezése így lesz konzisztens, rendezett és biztonságos.
pod encapsulation: A „pod-beágyazás” azt jelenti, hogy a Kubernetes egyetlen kezelhető egységbe, az úgynevezett Podba foglal egy vagy több szorosan együttműködő konténert, a közösen használt tárolót és hálózati erőforrásokat. Ez lehetővé teszi, hogy konténerek egységes egészként működjenek: közösen használják az olyan erőforrásokat, mint a tároló vagy a hálózat, miközben a rendszer egy csomóponton (node) együtt ütemezi és kezeli őket. Ez a megközelítés jelentősen leegyszerűsíti az alkalmazások telepítését és skálázását.
Mikor érdemes namespace-t használni?
A namespace akkor segít igazán, ha:
több csapat dolgozik ugyanabban a clusterben,
több környezetet szeretnénk egymástól elszeparálni (dev, test, staging, prod),
erőforráskvótákat kell alkalmazni (CPU, memória, storage),
korlátozni akarjuk az erőforrások láthatóságát vagy módosíthatóságát,
Kisebb clusterben nem mindig tűnik létkérdésnek, de hosszú távon a namespace az egyik legfontosabb szervezési eszköz, ami segít megelőzni a káoszt.
Összegzés
A namespace látszólag egy apró részlet a Kubernetesben, mégis az egész ökoszisztéma egyik legfontosabb alapköve. Rendet teremt, felelősségi köröket választ szét, erőforrásokat szabályoz, és előkészíti a terepet a biztonságos, skálázható működéshez.
Ahogy tovább haladunk a Kubernetes mélyebb rétegei felé, újabb olyan elemeket fogunk megismerni, amelyek pontosan ilyen csendben, mégis hatalmas erővel segítik a fejlesztőket, üzemeltetőket és szervezeteket abban, hogy a microservice-ek világában stabil rendszereket építsenek.
Amikor legutóbb a Kubernetes API-ról mint „a kommunikáció idegrendszeréről” írtam, sok visszajelzést kaptam arról, mennyire segített érthetővé tenni a fürt működését. Most innen folytatjuk a történetet. Az előző cikkben is sok mindent megmutattam, hogy érthetőbbé tegyem a cluster belső működését, és most megvizsgáljuk, hogyan zajlik valójában az információáramlás a Kubernetes belső világában.
Ennek a cikknek a célja, hogy az API működésének gyakorlati oldalát mutassa be: hogyan jelenik meg mindez a legegyszerűbb kapszula létrehozásánál, mit csinál a kubectl valójában a háttérben, hogyan lehet a klaszteren kívülről hozzáférni az API-szerverhez, és mire szolgál a mindenki által használt ~/.kube/config fájl.
A Kubernetesben minden objektum, minden módosítás, minden lekérdezés API-hívások sorozata. Ha értjük ezt a réteget, a rendszer teljes működése világossá válik.
1. A kapszula mint API-objektum: a legkisebb egység
Az előző cikkben már beszéltünk arról, hogy a kapszula a Kubernetes legkisebb futtatási egysége. Az alábbi példa egy minimális, mégis rendkívül tanulságos kapszula-definíciót mutat be:
Ez a néhány sor már minden lényeges elemet tartalmaz:
apiVersion – melyik API-csoportot használja az objektum;
kind – az erőforrás típusa (Pod);
metadata – az objektum azonosító adatai;
spec – a kapszulában futó konténerek és paramétereik.
A létrehozás és lekérdezés mind API-hívások sorozatán keresztül történik:
kubectl create -f elsopod.yaml
kubectl get pods
kubectl get pod elsopod -o yaml
kubectl get pod elsopod -o json
A külvilág számára ezek egyszerű parancsoknak tűnnek, de valójában a kubectl az API-szerverhez küld lekérdezéseket és módosítási kéréseket.
2. Hogyan kommunikál valójában a kubectl?
A Kubernetes minden erőforrást RESTful API-n keresztül kezel. Ez azt jelenti, hogy a kubectl működése valójában nem más, mint HTTP-hívások generálása az API-szerver felé – tipikusan JSON formátumú kommunikációval.
Ha szeretnénk még többet megtudni arról, mit csinál a kubectl a háttérben, akkor kapcsoljuk be a részletes – verbose – naplózást:
a két fél között TLS-sel védett HTTP-forgalom zajlik.
Ez a tudás fontos, mert így értjük meg igazán, mi történik akkor, amikor mi „csak” egy új kapszulát hozunk létre vagy lekérjük a futó erőforrásokat.
3. Hozzáférés a Kuberneteshez a klaszteren kívülről
A legtöbb adminisztrációs feladat a kubectl használatával történik, de akár közvetlenül curl-lel is kommunikálhatnánk a Kubernetes API-szerverével. A gond csak az, hogy ehhez hitelesített, TLS-sel védett kapcsolat kell. És mit kell tudni a klaszterhez tartozó API-król?
A klaszter API végpontjának adatai a kubectl config view kimenetében találhatók.
A kliens a hitelesítési adatokat a ~/.kube/config fájlból olvassa ki.
E nélkül a fájl nélkül a hozzáférés legfeljebb korlátozott, „insecure” módon lehetséges, amellyel a legtöbb művelet nem érhető el.
Ezért mondjuk, hogy a kubeconfig a hozzáférés kulcsa: nélküle a klaszter elérhetetlen lenne.
4. A kubeconfig felépítése és jelentése
A ~/.kube/config fájl a Kuberneteshez való hozzáférés központi eleme. A benne található adatok határozzák meg:
melyik klaszterhez csatlakozunk,
milyen felhasználó nevében tesszük ezt,
milyen hitelesítési adatokat használunk,
és milyen kontextusban fut a kubectl.
A kubeconfig több fő részből áll, amelyek együtt írják le a kapcsolat minden aspektusát. Egy alap struktúra így néz ki:
Ahogy minden Kubernetes-objektumnál, itt is meg kell határozni, hogy a fájl melyik API-verzió szerint értelmezendő. A kubeconfig esetében ez tipikusan v1.
clusters
A klaszter(ek) eléréséhez szükséges adatok:
server – az API-szerver címe, amelyhez a kubectl csatlakozik;
certificate-authority-data – a CA tanúsítvány, amely biztosítja, hogy a kliens a megfelelő API-szerverhez kapcsolódjon, és a kapcsolat hiteles legyen.
Ezek alapján a kubectl tudja, hová küldje a kéréseit.
users
Itt találhatók a kliens hitelesítési adatai. Tipikusan:
kliensoldali tanúsítvány,
privát kulcs,
vagy token.
A Kubernetes ebben a részben tárolja, hogy a felhasználó milyen módon igazolja magát a klaszter felé.
contexts
A context egy hármas kapcsolat:
melyik klasztert használjuk,
melyik felhasználó nevében,
és milyen alapbeállításokkal (pl. namespace).
Ez teszi lehetővé, hogy ugyanarról a gépről több klaszterrel is dolgozhassunk, akár eltérő jogosultságokkal.
current-context
Ez mondja meg, hogy a kubectl éppen melyik contextet használja alapértelmezésként. Ha nem adunk meg külön kapcsolót minden parancsnál, akkor ez a context érvényesül.
preferences
Ritkán használt beállítások, például megjelenítési opciók. A legtöbb esetben üres marad.
5. Miért fontos mindezt érteni?
A kubeconfig nem csupán technikai részlet: a Kubernetes működésének egyik kulcsdarabja. Ez határozza meg, hogy:
melyik klaszterrel kommunikálsz,
milyen jogosultsággal,
milyen biztonsági réteg alatt.
Ha a kubeconfigot érted, akkor magabiztosan tudsz klaszterek között váltani, hibákat diagnosztizálni, saját API-hívásokat küldeni, vagy akár több környezetet is kezelni ugyanazon a gépen.
A történet pedig itt még nem ér véget – a Kubernetes mélyebb rétegei csak most kezdenek igazán érdekessé válni.
Ha elég időt töltünk Kubernetes környezetben, egy ponton elkerülhetetlenül rájövünk, hogy a sok látható elem – kapszulák, szolgáltatások, vezérlők, automatizmusok – mögött van valami közös, csendben működő hatalom. Valami, ami minden változtatást, minden lekérdezést, minden döntést összeköt. Ez az API.
Egy láthatatlan infrastruktúra-háló, amely összefogja a fürt egészét, irányítja az adatáramlást, és biztosítja, hogy a rendszer minden része ugyanazt a nyelvet beszélje. Amikor ezt megértjük, nem csak használjuk a Kubernetest – elkezdjük igazán érteni.
Az API a Kubernetes motorja
A Kubernetes teljes architektúrája API-alapú. A központi komponens, a kube-apiserver, felel azért, hogy a fürtben futó összes komponens — a vezérlősík elemei és a külső kliensek — megbízhatóan kommunikáljanak egymással. Minden, amit a kubectl paranccsal végzünk, valójában egy REST-alapú API hívás, amely HTTP metódusokat (GET, POST, DELETE stb.) használ.
Aki szeretne mélyebben belelátni a működésbe, kipróbálhatja a curl-alapú lekérdezéseket is. A megfelelő tanúsítványok birtokában például így kérhetjük le az aktuális kapszulák (Pods) listáját:
Ezek a hívások teszik lehetővé, hogy akár automatizált rendszerek, akár fejlesztői eszközök biztonságosan kapcsolódjanak a Kubernetes API-hoz.
A RESTful szemlélet ereje
A Kubernetes API RESTful, vagyis állapotmentes és erőforrás-orientált. Minden objektum – például egy kapszula vagy egy szolgáltatás – egy konkrét API-végpont (endpoint) mögött található. A /api/v1/pods például a kapszulákhoz tartozó végpont, ahol a GET lekérdezés listát ad, a POST pedig új kapszulát hoz létre. Ez a megközelítés lehetővé teszi, hogy a Kubernetes könnyen integrálható legyen bármely modern fejlesztési vagy üzemeltetési eszközzel.
Jogosultságok és hozzáférés-ellenőrzés
A Kubernetes egyik legfontosabb biztonsági alapelve, hogy minden felhasználó csak azt tehessen meg, amire jogosultsága van. Ezt az RBAC (Role-Based Access Control) rendszer szabályozza, de már a gyakorlati munkához is jól jön, ha gyorsan ellenőrizni tudjuk, mire van engedélyünk.
A kubectl auth can-i parancs pontosan erre való:
kubectl auth can-i create deployments
yes
kubectl auth can-i create deployments --as robert
no
kubectl auth can-i create deployments --as robert --namespace developer
yes
A fenti példában látható, hogy a „robert” nevű felhasználó csak a developer névtérben (namespace) hozhat létre új Deployment objektumokat.
A Kubernetes három fő API-t biztosít az engedélyek ellenőrzésére:
API típus
Funkció
SelfSubjectAccessReview
Ellenőrzi, hogy az aktuális felhasználó végrehajthat-e egy adott műveletet.
LocalSubjectAccessReview
Ugyanez, de egy konkrét névtérre korlátozva.
SelfSubjectRulesReview
Megmutatja, milyen műveleteket hajthat végre a felhasználó egy névtérben.
Ez a felépítés biztosítja, hogy a jogosultságok átláthatóak és ellenőrizhetőek legyenek, ami különösen fontos nagyvállalati környezetben.
Optimista konkurencia – amikor több kéz nyúl ugyanahhoz az objektumhoz
A Kubernetes nem zárja le az erőforrásokat szerkesztés közben. Ehelyett az úgynevezett optimista konkurenciakezelést (Optimistic Concurrency) használja, amely a resourceVersion értékre támaszkodik.
Amikor valaki módosít egy objektumot, a rendszer ellenőrzi, hogy a resourceVersion azóta megváltozott-e. Ha igen, 409 CONFLICT hibát kapunk, ami jelzi, hogy az objektumot időközben más is frissítette. Ez a módszer különösen fontos nagy fürtök esetén, ahol több automatizált folyamat és emberi adminisztrátor is dolgozik egyszerre ugyanazokon az erőforrásokon.
A resourceVersion értéket az etcd adatbázis kezeli, és egyedileg azonosítja az adott objektumot a névtér és a típus alapján. A lekérdezések (GET, WATCH) nem változtatják ezt az értéket, csak a módosítások (UPDATE, PATCH, DELETE).
Annotációk – amikor a metaadat többet mond, mint ezer címke
A Kubernetes-ben a címkék (labels) segítségével szűrhetünk és csoportosíthatunk objektumokat. Az annotációk (annotations) viszont nem keresésre, hanem metaadatok tárolására szolgálnak. Ezek lehetnek időbélyegek, kapcsolódó objektumokra mutató hivatkozások, vagy akár az adott erőforrásért felelős fejlesztő e-mail-címe.
Az annotációk kulcs–érték párok formájában tárolódnak, és ember számára is olvashatóak. Ez különösen hasznos lehet integrációs vagy üzemeltetési eszközök számára, mivel így minden releváns információ közvetlenül az objektumhoz kapcsolható.
Példa annotációk létrehozására és módosítására:
kubectl annotate pods --all description='Production Pods' -n prod
kubectl annotate --overwrite pod webpod description='Old Production Pod' -n prod
kubectl annotate -n prod pod webpod description-
Az annotációk segítségével tehát kontextust adhatunk az erőforrásainkhoz – anélkül, hogy az API működését befolyásolnánk.
Összegzés
A Kubernetes API nem csupán egy technikai interfész, hanem a platform idegrendszere. A RESTful megközelítés, a precíz hozzáférés-kezelés, az optimista konkurencia és a rugalmas annotációk mind azt a célt szolgálják, hogy a rendszergazdák és fejlesztők hatékonyan, biztonságosan és átláthatóan kezeljék a komplex felhős környezeteket.
Aki megérti az API működését, valójában a Kubernetes egészét érti meg. És bár a kapszulák futtatása látványosabbnak tűnhet, az igazi varázslat mégis itt, az API hívások szintjén történik.
Több tucat cikket olvashattatok tőlem a felhőszolgáltatások alapfogalmairól, és arról is, hogyan kommunikálnak egymással a különböző rendszerek. Ebben a cikkben egy olyan területet hozok közelebb, amely látszólag egyszerűnek tűnik, mégis meglepően sok félreértés forrása.
Egy saját történettel kezdem: amikor először készítettem több rétegű felhős alkalmazást, órákon át kerestem, miért nem érhető el a szolgáltatásom. A hiba mindössze annyi volt, hogy egy helytelenül megadott URL miatt teljesen más címre irányítottam a kéréseket. Ez volt az első alkalom, amikor igazán megértettem, mennyire fontos a pontos URL-használat.
A felhőben dolgozó szakemberek nap mint nap találkoznak API-végpontokkal, szolgáltatási URL-ekkel, konténerek belső hivatkozásaival és különböző load balancer címsémákkal. Ezek mind egy közös alapelvre épülnek: az URL szerkezetére. Ahhoz, hogy valaki magabiztosan mozogjon bármelyik felhős platformon, elengedhetetlen, hogy pontosan értse, mit is jelent egy URL, és hogyan működik.
Mi az az URL és miért létezik?
Az URL (Uniform Resource Locator) egy szabványos formátum, amely meghatározza, hogy az interneten vagy egy privát hálózaton belül hol található egy erőforrás, és milyen protokollon keresztül lehet elérni. A weboldalak címe, egy API végpontja, egy belső szolgáltatás címe: mind URL.
Példa: https://api.evolvia.hu/gyakorlat/42
Ez nem egy véletlenszerű karakterhalmaz, hanem precízen meghatározott elemekből áll.
Egy URL szerkezete
Egy tipikus URL több kötelező és opcionális részből épül fel:
https://cloudmentor.hu:443/eleresi/ut/?lekerdezes=ertek#szekcio
└───┬──┘└─────┬──────┘└─┬─┘└────┬────┘└───────┬───────┘└──┬───┘
Protokoll Domain Port Útvonal Query Fragment
Az egyes részek szerepe:
Protokoll Meghatározza, milyen szabályrendszerrel történik a kommunikáció. Leggyakoribb: http, https
Domain vagy IP-cím A cím, amelyhez a kérés érkezik. Példák: example.com 192.168.1.10 localhost – saját gépre mutat
Port A szerveren futó adott szolgáltatás eléréséhez szükséges. HTTP: 80 HTTPS: 443 API-k esetén gyakran egyedi, például: http://localhost:8080
Útvonal (Path) Az erőforrás helye a szerveren belül. Példa: /api/v1/orders
Query paraméterek Opcionális adatok a kéréshez kapcsolódóan. Példa: ?sort=asc&page=2
Fragment Oldalon belüli hivatkozás, például egy szakaszra ugráshoz.
Gyakori URL-típusok és példák
1. Helyi fejlesztés: localhost http://localhost:3000/api/test Ez a saját gépre mutat, amit fejlesztők naponta használnak alkalmazások és API-k tesztelésére.
2. IP-cím alapú elérés http://10.0.0.5:8080/health Jellemző konténerek, virtuális gépek vagy belső hálózati szolgáltatások esetén.
3. Felhős API-végpontok https://myapp.azurewebsites.net/api/login https://abc123.execute-api.eu-west-1.amazonaws.com/prod/items Ezek minden felhőszolgáltató esetén hasonló logikát követnek.
4. Belső szolgáltatás hivatkozása Kubernetesben http://redis-master.default.svc.cluster.local:6379 Ez jól mutatja, hogy az URL nem csak internetes cím lehet, hanem klaszteren belüli erőforrás is.
Miért fontos ez a felhőben dolgozó szakemberek számára?
Egy felhőmérnök, DevOps vagy SRE munkája szinte minden nap érinti az URL-eket. API-k hívása, szolgáltatások összekapcsolása, webhookok beállítása, konténerek közötti kommunikáció, gateway routerek konfigurálása: mind olyan feladat, ahol egy hibás karakter is működésképtelenné tehet rendszereket.
Pontosan értve az URL szerkezetét:
gyorsabban lehet hibát keresni
megbízhatóbban lehet szolgáltatásokat összekötni
tisztábban értelmezhetők logok és monitoring adatok
könnyebbé válik a skálázható rendszertervezés
A felhőben minden kommunikáció URL-ekre épül. Aki érti az alapokat, stabil alapot kap a magasabb szintű architektúrákhoz.
Leggyakoribb hibák kezdők körében
Rosszul megadott protokoll: http helyett https
Port kihagyása olyan szolgáltatásnál, ahol nem alapértelmezett (alapértelmezett portok például: 80 – HTTP, 443 – HTTPS)
Query paraméterek helytelen formázása
Localhost és külső elérési címek összekeverése
Privát IP és publikus IP nem megfelelő használata
Ezek mind egyszerű hibák, mégis órákat vehetnek el a hibakeresésből.
HTTP és HTTPS közötti különbség
A webes kommunikáció két leggyakrabban használt protokollja a HTTP és a HTTPS. Bár a két rövidítés csak egyetlen betűben tér el, a mögöttük lévő technológiai különbség alapvetően meghatározza a biztonságot, a hitelesítést és az adatok védelmét. Felhőben dolgozó szakembereknek ez kiemelten fontos, hiszen az alkalmazások, API-k és háttérszolgáltatások nagy része érzékeny adatokat kezel.
HTTP – titkosítás nélküli kommunikáció
A HTTP (Hypertext Transfer Protocol) az alapvető webes protokoll, amely szabályozza, hogyan kommunikál a kliens és a szerver. A HTTP-ben az adatok titkosítatlan formában utaznak, vagyis bárki, aki valamilyen módon hozzáfér a hálózati forgalomhoz, elméletben képes lehet kiolvasni a küldött vagy fogadott tartalmakat. Ez ma már csak fejlesztési, belső hálózati vagy nagyon specifikus esetekben elfogadható.
HTTPS – titkosított és hitelesített kapcsolat
A HTTPS (HTTP Secure) ugyanezt a kommunikációs modellt használja, de kiegészül TLS-alapú titkosítással. A TLS (Transport Layer Security) gondoskodik arról, hogy a kliens és a szerver között áthaladó adatok ne legyenek olvashatók harmadik fél számára. Emellett a szerver hitelesítése is megtörténik tanúsítványok segítségével.
Ez azt jelenti, hogy:
a forgalom titkosított
a kliens meggyőződik arról, hogy valóban a megfelelő szerverhez csatlakozik
az adatok nem módosíthatók észrevétlenül útközben
Miért számít ez a felhőben?
A modern felhőalapú rendszerekben elképzelhetetlen HTTPS nélkül dolgozni. API-k, belső menedzsment felületek, mikroszolgáltatások közötti kommunikáció: mind olyan elemek, ahol a biztonság és az integritás prioritás.
A HTTPS használata azért kritikus:
védi a hitelesítési adatokat
megakadályozza az adatok lehallgatását
biztosítja, hogy a kliens valós szolgáltatással kommunikál
megfelel biztonsági előírásoknak és iparági szabványoknak
Gyakorlati különbségek a fejlesztő szemszögéből
A HTTPS URL-ek https:// előtaggal kezdődnek, a HTTP pedig http:// formát használ
A HTTPS alapértelmezett portja 443, míg a HTTP-é 80
HTTPS esetén szükség van tanúsítványra, amely lehet publikusan hitelesített vagy saját aláírású
Összefoglalás
Az URL nem pusztán egy webcím. Ez a modern internet egyik legfontosabb építőköve. A felhőben dolgozó szakemberek számára pedig különösen lényeges alapelem, hiszen minden szolgáltatás, API, konténer és infrastruktúra modul ezen keresztül kommunikál. Aki tisztában van az URL felépítésével és működésével, sokkal tudatosabban és gyorsabban fogja megérteni a felhős rendszerek belső működését.
Nagyon sok cikken keresztül ismerkedtünk már meg a Kubernetes alapjaival, azzal, hogyan működik a fürt (cluster) és miként kommunikálnak egymással a kapszulák (pods).
Most azonban kicsit messzebbre tekintünk, a történelem és a technológia határára, ahol megszületett a modern konténeres világ egyik előfutára – az Apache Mesos.
Képzeljünk el egy korszakot, amikor a nagyvállalatok még kísérleteztek azzal, hogyan lehetne hatékonyan kihasználni a szervererőforrásokat, hogyan lehetne a számítási kapacitást „elosztani” több gép között. Ebben a világban született a Mesos – és ebből nőtt ki később a Kubernetes.
A Mesos nem volt más, mint egy korai próbálkozás arra, hogy egységes erőforrás-kezelést biztosítson több gép, több alkalmazás és több adatközpont között. A Kubernetes később hasonló célokat tűzött ki, de egészen más filozófiával.
Mi a közös a Mesos és a Kubernetes között?
Távolról nézve, a Kubernetes nem különbözik alapjaiban más klaszterkezelő rendszerektől. Mindkettőben megtaláljuk azokat az alapkomponenseket, amelyek nélkülözhetetlenek egy elosztott rendszerhez:
Központi vezérlő (control plane), amely API-n keresztül kommunikál és szabályozza a működést.
Ütemező (scheduler), amely meghatározza, hogy az egyes feladatok mely csomópontokon fussanak.
Tartós állapotkezelés (persistent state), amely megőrzi a klaszter konfigurációját és állapotát.
A különbségek azonban a részletekben rejlenek. A Mesos az állapot tárolására Apache ZooKeeper-t használ, míg a Kubernetes ugyanezt a szerepet az etcd nevű kulcs-érték alapú adatbázissal valósítja meg. Ez az apró különbség nagy hatással van a rendszer rugalmasságára és egyszerűségére.
Mesos architektúra röviden
A Mesos a Apache Software Foundation egyik korai projektje volt, amely a nagyvállalati adatközpontok hatékony kihasználására született. A rendszer két fő komponensre épül:
Mesos Master – a központi vezérlő egység, amely felügyeli a rendelkezésre álló erőforrásokat, kiosztja azokat, és kezeli az ütemezést.
Mesos Agent (korábban Slave) – a munkavégző csomópont, amely futtatja az alkalmazásokat vagy szolgáltatásokat.
A Mesos önmagában nem futtat alkalmazásokat, hanem más keretrendszereket (framework-eket) szolgál ki, mint például Marathon, Chronos vagy akár Hadoop. Ezek a keretrendszerek kommunikálnak a Mesos API-ján keresztül, és rajta keresztül ütemezik a feladatokat a klaszter gépeire.
Kubernetes: az új szemlélet
A Kubernetes ebből a modellből indult ki, de teljesen más irányba vitte tovább a koncepciót. Míg a Mesos inkább általános erőforrás-menedzsment rendszer volt, a Kubernetes alkalmazáscentrikus megközelítést választott. A célja az volt, hogy a fejlesztők és az üzemeltetők ne gépeket, hanem alkalmazásokat kezeljenek.
A Kubernetes minden eleme – a kapszulák (pods), szolgáltatások (services), vezérlők (controllers) – API-n keresztül vezérelhető, és ez a tiszta API-orientált szemlélet tette lehetővé az automatizálást, az önjavítást és a dinamikus skálázást.
Összegzés – két világ találkozása
Ha valaki ismeri az olyan rendszereket, mint az OpenStack vagy a CloudStack, az könnyen ráismer a közös vonásokra: mindegyik esetében van egy vezérlő komponens, vannak munkavégző egységek, és szükség van hálózatkezelésre, valamint állapotmegőrzésre. Ami igazán megkülönbözteti a Kubernetest a Mesostól, az a hibatűrés, az önfelfedezés, és a skálázhatóság természetes támogatása.
A Mesos megmutatta, hogyan lehet egy klaszter erőforrásait megosztani. A Kubernetes pedig megmutatta, hogyan lehet ugyanezt egyszerűen, biztonságosan és automatizáltan megvalósítani.
A technológiai fejlődés történetében ritkán látunk olyan folytonosságot, mint ami a Mesos és a Kubernetes között húzódik. Egyik a másik alapjait rakta le, és bár a Mesos ma már inkább a történelem része, hatása még mindig érezhető minden modern konténeres környezetben.
A Kubernetes nem forradalmat csinált – hanem evolúciót indított el.