Modul 8 — Orchestrace: Kubernetes
38. Persistent Volumes a stavové aplikace
Jak Kubernetes řeší perzistentní úložiště pro Pody pomocí PersistentVolume a PersistentVolumeClaim a jak fungují stavové aplikace pomocí StatefulSet.
Úvod a kontext
Pody jsou efemérní stejně jako kontejnery — když Kubernetes Pod smaže
a vytvoří nový (například při rolling update nebo po pádu uzlu), local
disková data uvnitř Podu zmizí. Pro bezstavové webové aplikace to
nevadí, ale databáze, message queue nebo cokoliv, co si musí pamatovat
data mezi restarty, potřebuje úložiště nezávislé na životním cyklu
konkrétního Podu — obdobu Docker named volumes, jen v měřítku celého
clusteru, kde Pod může být naplánován na kterýkoliv z mnoha uzlů.
Teorie
PersistentVolume a PersistentVolumeClaim
Kubernetes odděluje jak je úložiště fyzicky poskytnuto od jak ho
aplikace požaduje, pomocí dvou objektů:
- PersistentVolume (PV) — reprezentuje skutečný kus úložiště v
clusteru (disk v cloudu, NFS share, lokální disk). Vytváří ho
obvykle administrátor clusteru nebo automaticky provisioner. - PersistentVolumeClaim (PVC) — "požadavek" na úložiště, který
vytváří vývojář/aplikace ("potřebuji 10 GiB úložiště, které přežije
restart Podu"). Kubernetes najde (nebo dynamicky vytvoří) odpovídající
PV a naváže ho na PVC.
Tento model odpovídá tomu, jak Pod žádá CPU/paměť přes resources —
aplikace deklaruje potřebu, cluster ji uspokojí z dostupných zdrojů.
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: db-data
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 10Gi
storageClassName: standard
StorageClass a dynamické provisioning
V praxi se PV zřídka vytváří ručně — clustery mají definované
StorageClass objekty, které popisují, jak automaticky (dynamicky)
vytvořit nový PV při vzniku PVC (např. v cloudu automaticky zřídit
nový EBS/Persistent Disk odpovídající velikosti). storageClassName v
PVC odkazuje na tuto třídu; PV pak vznikne samo, bez ručního zásahu
administrátora.
Access Modes
- ReadWriteOnce (RWO) — svazek může mountnout k zápisu jen jeden
uzel najednou (typické pro blokové cloudové disky, např. databáze). - ReadOnlyMany (ROX) — víc uzlů může mountnout jen ke čtení.
- ReadWriteMany (RWX) — víc uzlů může mountnout k zápisu současně
(vyžaduje síťový souborový systém typu NFS, ne obyčejný blokový disk).
Reclaim Policy
Když je PVC smazán, co se stane s daty na PV, závisí na reclaim
policy: Delete (výchozí u dynamicky provisionovaných svazků — disk
se fyzicky smaže), nebo Retain (disk zůstane zachován, ale
odpojen — musí ho ručně znovu přiřadit administrátor). Pro produkční
databáze se často vědomě nastavuje Retain, aby náhodné smazání PVC
nesmazalo i data.
Použití PVC v Podu
spec:
containers:
- name: db
image: postgres:16
volumeMounts:
- name: data
mountPath: /var/lib/postgresql/data
volumes:
- name: data
persistentVolumeClaim:
claimName: db-data
StatefulSet: Deployment pro stavové aplikace
Obyčejný Deployment se pro stavové aplikace (databáze, distribuované
fronty) často nehodí, protože jeho Pody jsou vzájemně zaměnitelné a
mají náhodné jméno. StatefulSet poskytuje navíc:
- stabilní, předvídatelné jméno Podu (
db-0,db-1,db-2
místo náhodného sufixu), - stabilní síťovou identitu přes tzv. headless Service,
- vlastní PVC pro každou repliku, které přežije restart a zůstane
spárováno se "svým" Podem (db-0má vždy stejná data, i po
restartu), - řízené, sekvenční spouštění a mazání replik (užitečné např. pro
primární/replikovanou topologii, kde pořadí startu záleží).
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: db
spec:
serviceName: db
replicas: 3
selector:
matchLabels:
app: db
template:
metadata:
labels:
app: db
spec:
containers:
- name: db
image: postgres:16
volumeMounts:
- name: data
mountPath: /var/lib/postgresql/data
volumeClaimTemplates:
- metadata:
name: data
spec:
accessModes: ["ReadWriteOnce"]
resources:
requests:
storage: 10Gi
volumeClaimTemplates zajistí, že se pro každou repliku (db-0,
db-1, db-2) automaticky vytvoří samostatný PVC a ten zůstává s ní
svázaný napříč restarty.
Praktický příklad
kubectl apply -f statefulset.yaml
kubectl get pods
# db-0 Running
# db-1 Running
# db-2 Running
kubectl get pvc
# data-db-0 Bound 10Gi
# data-db-1 Bound 10Gi
# data-db-2 Bound 10Gi
# smazání Podu db-0 — StatefulSet ho nahradí novým se stejným jménem
# a stejným PVC, tedy se stejnými daty
kubectl delete pod db-0
kubectl get pods
# db-0 se znovu objeví s totožnou identitou i daty
Shrnutí
PersistentVolume a PersistentVolumeClaim oddělují fyzické úložiště od
požadavku aplikace na úložiště, obvykle s dynamickým provisioningem
přes StorageClass. Access mode určuje, kolik uzlů smí svazek
současně mountovat a jak; reclaim policy určuje osud dat po smazání
PVC. Pro databáze a jiné stavové služby se místo Deploymentu používá
StatefulSet, který dává každé replice stabilní jméno a vlastní
perzistentní PVC, jenž s ní zůstává spárovaný napříč restarty.
Kontrolní otázky
- Jaký je rozdíl v roli mezi PersistentVolume a
PersistentVolumeClaim? - Kdy použijete access mode ReadWriteOnce a kdy ReadWriteMany?
- Proč se pro databázi v Kubernetes obvykle používá StatefulSet
místo Deploymentu? - Mini cvičení: napište StatefulSet se 2 replikami jednoduchého
image (např.busyboxse smyčkou zapisující čas do souboru) s
volumeClaimTemplateso velikosti 1Gi, nasaďte ho a příkazem
kubectl get pvcověřte, že vznikly dva samostatné PVC, jeden pro
každou repliku.
Lekce na sebe nejsou zamčené — libovolnou lekci můžete otevřít i označit jako hotovou v jakémkoliv pořadí.