Kubernetes: hogyan marad meg az adat, ha egy Pod törlődik?
Legutóbb a Kubernetes Deployments 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:
apiVersion: v1
kind: Pod
metadata:
name: pelda-app
spec:
containers:
- name: app
image: nginx
volumeMounts:
- mountPath: /cache
name: cache-volume
volumes:
- name: cache-volume
emptyDir: {}
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.
