Naučíte sa
- Vytvoriť trvalý zväzok.
- Vytvoriť aplikáciu, ktorá vie uchovať svoj stav vo zväzku.
- používať objekty
StatefulSet
,PersistentVolumeClaim
,PersistentVolume
.
Trvalé zväzky a dáta Kubernetes
Vo svete Kubernetes musíme rátať s tým, že kontajner sa môže naštartovať na ktoromkoľvek uzle a kedykoľvek môže skončiť svoju činnosť. To nie je problém v prípade, že kontajner iba spracúva požiadavky a posiela odpovede, napr. vykonáva nejaké výpočty. Komplikácia nastáva, ak kontajner ukladá dôležité dáta.
Ak výstup aplikácie závisí iba od vstupu tak vravíme, že aplikácia je bezstavová - nič okrem vstupu neovplyvňuje výstup. Príkladom môže byť služba na kompresiu obrázkov - z nekomprimovaného obrázku na vstupe vie vyrobiť komprimovaný obrázok a nepotrebuje žiadne ďalšie údaje. Ak kontajner nemá svoj stav, tak je v zásade jedno, na ktorom uzle beží.
Ak kontajner ukladá a číta nejaké dáta a dáta ovplyvňujú výsledok spracovania, vravíme že má svoj stav. Stav je množina dát ktorá je dôležitá pre výsledok spracovania. Príkladom je databáza - podľa príkazov upravuje alebo číta množinu súborov v nejakom adresári. Je jasné, že nastanú problémy, ak databáza prestane fungovať na jednom uzle a presunie sa na druhý ak sa nepresunú aj súbory ktoré predstavujú stav databázy.
Väčšinou sa tento problém rieši tak, že dôležité súbory vyjadrujúce stav sa nachádzajú na osobitnom mieste na to určenom, napríklad na sieťovom súborovom systéme ktorý je prístupný zo všetkých uzlov. Ak vieme správne oddeliť stav od zvyšku kontajnera, tak je možné ľahko reštartovať pod na inom uzle, lebo dôležité dáta zostávajú stále na jednom mieste.
Trvalé zväzky
Trvalé zväzky (PersistentVolumes
) sú spôsob, ako oddeliť stav aplikácie od kontajnera.
PersistentVolume
je typ objektu, ktorý vyjadruje jedno miesto kde je možné uložiť dáta - celý disk, adresár, sieťový disk alebo zdieľaný adresár v sieťovom súborovom systéme.
Poznáme viac druhov trvalých zväzkov podľa toho, aký zdroj reprezentujú:
hostPath
: adresár na aktuálnom uzle (použiteľné len pre jednouzlový klaster)localPersistentVolume
: adresár alebo disk na konkrétnom uzle.iSCSI
: sieťový disk storage servra s protokolom iSCSINFS
: zdieľaný sieťový adresár UNIXGlusterFS
: distribuovaný súborový systémRBD
: blokové zariadenie distribuovaného súborového systému Ceph- rôzne iné spôsoby pre rôznych poskytovateľov (Azure, Amazon,Google.. )
Oficiálna dokumentácia trvalých zväzkov
Druh trvalého zväzku vyberieme podľa toho, akú diskovú kapacitu máme k dispozícii. Objekt s trvalým zväzkom vieme vytvoriť ručne alebo automaticky podľa požiadavky.
Trvalý zväzok v Docker Engine
Pokiaľ používame inštaláciu Kubernetes pomocou Docker Engine tak trvalý zväzok implementujeme pomocou hostPath
.
Viac nájdete v tutoriáli.
Vytvorte si konfiguračný súbor desktoppv1.yaml
s trvalým zväzkom.
apiVersion: v1
kind: PersistentVolume
metadata:
name: desktoppv1
labels:
type: local
spec:
storageClassName: local
capacity:
storage: 1Gi
accessModes:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Delete
hostPath:
path: "/tmp/desktoppv1"
Trvalé zväzky v klastri nepatria do žiadneho menného priestoru,
Takto si vytvoríte trvalý zväzok:
kubectl apply -f desktoppv1.yaml
kubectl get pv
Trvalý zväzok vyjadrí, že je dostupný priestor v konkrétnom adresári na virtuálnom stroji kde beží Kuberntes a "obalí" ho kubernetes objektom typu PersistentVolume
. Ak chceme tento priestor využiť v niektorom kontajneri, musíme vytvoriť mapovanie.
Na konfiguráciu automatického prideľovania slúži objekt typu StorageClass
. Ak je na to systém nakonfigurovaný, tak sa automaticky z dostupnej diskovej kapacity vyhradí časť podľa požiadavky.
Ak nie, tak potom systém čaká na to aby administrátor vytvoril priestor (adresár alebo disk) ručne a k nemu vytvoril objekt typu PersistentVolume
.
StatefulSet
Mapovanie medzi trvalým zväzkom a Podom zabezpečuje objekt typu PersistentVolumeClaim
. Tento objekt vyjadruje konkrétnu požiadavku aplikácie na úložný priestor. Ak ku nemu existuje PersistentVolume
ktorý vyhovuje požiadavke, tak sa vytvorí mapovanie.
Tento objekt môžeme vytvoriť samostatne, alebo využijeme špeciálny objekt typu StatefulSet
. Ten obsahuje pravidlá pre vytváranie a rušenie podov na ľubovoľnom uzle tak, aby sa zachoval prístup k ich stavu. Ak sa dáta aplikácie
nachádzajú na lokálnom disku, tak Kubernetes zabezpečí to, aby pod vykonával iba na tom uzle, kde sa nachádza zväzok. Vďaka tomu sú súbory v trvalom zväzku prístupné transparentne. Kontajner spravidla nemusí vedieť, kde a ako sú uložené súbory s ktorými pracuje.
Vyskúšajme si príklad na StatefulSet
a ukážme si nasadenie relačnej databázy.
Objekt StatefulSet
bude podobný ako objekt typu Deployment
,
ale bude obsahovať aj šablónu pre vytvorenie požiadavky
na trvalý zväzok typu PersistentVolumeClaim
:
Vytvorte si súbor postgres_ss.yaml
a zapíšte do neho:
# Použité API
apiVersion: apps/v1
# Druh objektu
kind: StatefulSet
# Meno objektu
metadata:
name: postgres
# Špecifikácia objektu
spec:
# prepojenie s podom podľa štítku podu
selector:
matchLabels:
app: postgres
# meno služby
serviceName: postgres
# Počet inštancií podov
replicas: 1
# Šablóna podu
template:
metadata:
# Štítok podu
labels:
app: postgres
spec:
# Kontajnery podu
containers:
# meno kontajnera
- name: postgres
# Meno obrazu
image: postgres:10.5
# otvorený port kontajnera
ports:
- name: postgres
containerPort: 5432
protocol: TCP
# Premenné prostredia pre konfiguráciu kontajnera
env:
# Meno používateľa databázy
- name: POSTGRES_USER
value: postgres
# Meno databázy
- name: POSTGRES_DB
# Heslo na pripojenie do databázy
value: postgres
- name: POSTGRES_PASSWORD
value: verysecret
# Požiadavky na trvalý zväzok
volumeMounts:
- mountPath: /var/lib/postgresql/data
# Meno požiadavky na zväzok
name: postgrespvc
volumeClaimTemplates:
- metadata:
# meno požiadavky na trvalý zväzok
# Musí byť rovnaké ako meno zväzku
# vo volumeMounts v Pode
name: postgrespvc
spec:
accessModes: ["ReadWriteOnce"]
# Automatické pridelenie trvalého zväzku
# Podľa toho vieme, ktorý zväzok prideliť
storageClassName: "local"
resources:
requests:
# Požiadavky na veľkosť trvalého zväzku
storage: 1Gi
V časti volumeClaimTemplates
zapisujeme šablóny pre požiadavky na trvalý zväzok typu PersistentVolumeClaim
(môže ich byť aj viac).
V tomto prípade sme deklarovali záujem o adresár s veľkosťou minimálne 1 GB (storage: 1Gi
) do ktorého sa dá zapisovať maximálne jedným procesom a čítať ľubovoľným počtom procesov
(accessMode: ["ReadWriteOnce"]
). Požiadali sme o automatické pridelenie trvalého zväzku (storageClassName: local
).
Vytvorme si objekt typu StatefulSet
kubectl apply -f postgres_ss.yaml -n cv7
Pri vytvorení objektu typu StatefulSet
sa automaticky vytvorí aj objekt typu PersistentVolumeClaim
ktorý reprezentuje požiadavku na vytvorenie trvalého zväzku. Overme si čo sa deje v našom klastri:
# Najdôležitejšie objekty, ale PersistentVolumeClaim nevidno
kubectl get all -n cv7
kubectl describe statefulset/postgres -n cv7
# PersistenVolume Claim musíme pozrieť samostatne
kubectl get pvc -n cv7
# Zistite meno požiadavky na trvalý zväzok
kubectl describe statefulsets/postgres -n cv7
kubectl describe pvc/postgrespvc-postgres-0 -n cv7
# Pozrieme v akom stave je trvalý zväzok
kubectl describe pv/desktoppv1
# Trvalé zväzky nemajú menný priestor
Objekt StatefulSet
, podobne ako Deployment
vytvorí objekty typu ReplicaSet
a Pod
.
Okrem toho vytvorí aj požiadavku na vytvorenie trvalého zväzku typu PersistentVolumeClaim
podľa zadanej šablóny.
Keď k objektu PersistentVolumeClaim
existuje vhodný objekt typu PersistentVolume
(trvalý zväzok), tak je možné vytvoriť mapovanie a spustiť nový pod manažovaný objektom typu StatefulSet
.
Databáza by mala bežať. Ak nie, tak pátrajte po príčine pomocou príkazov get
, describe
alebo logs
.
Zverejnenie služby
Ak je trvalý zväzok v poriadku, môžeme si vyskúšať funkčnosť
nového objektu typu StatefulSet
.
Prítomnosť novej služby v klastri vyjadríme pomocou objektu Service
. Tým povieme pod akým menom a portom bude služba dostupná.
Vytvorme si službu s databázou postgresql
aby ju iné objekty vedeli využívať.
Konfiguráciu služby si uložte napr. do súboru postgres-service.yaml
.
apiVersion: v1
kind: Service
metadata:
name: postgresservice
spec:
selector:
app: postgres
type: ClusterIP
ports:
- protocol: TCP
# Port služby
port: 5432
# Port kontajnera
targetPort: 5432
Táto služba s názvom postgresservice
bude dostupná iba v rámci klastra na porte 5432.
Grafické rozhranie k databáze
Vytvorme si rozhranie pomocou ktorého sa vieme napojiť na databázu.
Webové rozhranie "pgadmin" bude bežať ako samostatný objekt typu Deployment
so službou. Keď sa na ňu pripojíme pomocou webového prehliadača, budeme mať k dispozícii aj službu databázy. Databáza bude bežať pod DNS menom postgresservice
.
Rozhranie "pgadmin" bude prístupné z prehliadača na porte 30881.
V tomto príklade umiestnime službu aj deployment do jedného súboru, konfigurácie sú oddelené ---
.
Súbor pgadmin-deploymentservice.yaml
:
apiVersion: v1
kind: Service
metadata:
name: pgadmin
spec:
selector:
app: pgadmin
# Typ služby sa mení z ClusterIP na NodePort
type: NodePort
ports:
- protocol: TCP
port: 8800
targetPort: 80
# Port viditeľný na každom uzle
nodePort: 30881
---
# verziu API zistíte z dokumentácie
apiVersion: apps/v1
# Druh objektu
kind: Deployment
# O objekte
metadata:
# Meno objektu
name: pgadmin-deployment
# špecifikácia objektu
spec:
# Počet podov ktorý sa má vytvoriť
replicas: 1
# Selektor vytvára prepojenie Deploymentu a Podu
# Vyberá tie PODy ktoré majú štítok nginx
selector:
matchLabels:
app: pgadmin
# Šablóna PODu
template:
metadata:
# štítok PODu - na spojenie Deploymentu a Podu
labels:
app: pgadmin
spec:
# kontajnery PODu
containers:
# Len jeden kontajner s aplikáciou nginx
- name: pgadmin
# Meno a verzia obrazu
image: dpage/pgadmin4
ports:
# POD má otvorený port 80
- containerPort: 80
env:
- name: PGADMIN_DEFAULT_EMAIL
value: admin@admin.sk
- name: PGADMIN_DEFAULT_PASSWORD
value: verysecret
Aplikujeme konfiguráciu a po čase by v klastri mala bežať webová aplikácia pomocou ktorej sa vieme pripojiť na databázu a niečo do nej vložiť.
Pomocou premenných prostredia vieme určiť prihlasovacie meno a heslo.