
V dobách, kdy Kubernetes byl ještě ve verzi v1.0.0, existovaly pluginy pro svazky (volume plugins). Ty byly potřeba pro propojení Kubernetes se systémy pro ukládání perzistentních (trvalých) dat kontejnerů. Jejich počet byl malý, a mezi prvními byli takoví poskytovatelé úložišť jako GCE PD, Ceph, AWS EBS a další.
Pluginy byly dodávány spolu s Kubernetes, za což dostaly své označení — in-tree. Nicméně pro mnohé se stávající soubor těchto pluginů ukázal jako nedostačující. Řemeslníci přidávali jednoduché pluginy do jádra Kubernetes pomocí patchů, po nichž vytvářeli vlastní Kubernetes a instalovali je na své servery. Ale časem vývojáři Kubernetes pochopili, že se problém nevyřeší. Lidem je potřeba rybaření. A v vydání Kubernetes v1.2.0 se to objevilo…
Plugin Flexvolume: nástroj pro začátečníky
Vývojáři Kubernetes vytvořili plugin FlexVolume, který byl logickým obalem z proměnných a metod pro práci s implementovanými externími Flexvolume ovladači.
Zastavme se a podívejme se podrobněji, co představuje ovladač FlexVolume. Je to jakýsi spustitelný soubor (binární soubor, Python skript, Bash skript atd.), který při provádění přijímá argumenty příkazového řádku a vrací zprávu s předem známými poli v JSON formátu. Prvním argumentem příkazového řádku je vždy podle dohody metoda a ostatní argumenty jsou jejích parametry.

Schéma připojení CIFS Shares v OpenShift. Ovladač Flexvolume — přímo uprostřed
Minimální soubor metod vypadá takto:
flexvolume_driver mount # zodpovídá za připojení svazku k podu
# Formát vrácené zprávy:
{
"status": "Success"/"Failure"/"Not supported",
"message": "Důvod, proč byl vrácen právě tento stav",
}
flexvolume_driver unmount # zodpovídá za odpojení svazku od podu
# Formát vrácené zprávy:
{
"status": "Success"/"Failure"/"Not supported",
"message": "Důvod, proč byl vrácen právě tento stav",
}
flexvolume_driver init # zodpovídá za inicializaci pluginu
# Formát vrácené zprávy:
{
"status": "Success"/"Failure"/"Not supported",
"message": "Důvod, proč byl vrácen právě tento stav",
// Určuje, zda ovladač používá metody attach/detach
"capabilities":{"attach": True/False}
} Použití metod attach a detach určí scénář, podle kterého se v budoucnu kubelet bude chovat při volání ovladače. Existují také speciální metody expandvolume a expandfs, které odpovídají za dynamickou změnu velikosti svazku.
Jako příklad změn, které tento metod přidává, expandvolume, a spolu s ním i možnost provádět změny velikosti svazků v reálném čase, si můžete prohlédnout v Rook Ceph Operator.
Tady je příklad implementace Flexvolume ovladače pro práci s NFS:
usage() {
err "Neplatné použití. Použití: "
err "t$0 init"
err "t$0 mount <mount dir> <json params>"
err "t$0 unmount <mount dir>"
exit 1
}
err() {
echo -ne $* 1>&2
}
log() {
echo -ne $* >&1
}
ismounted() {
MOUNT=`findmnt -n ${MNTPATH} 2>\/dev\/null | cut -d' ' -f1`
if [ "${MOUNT}" == "${MNTPATH}" ]; then
echo "1"
else
echo "0"
fi
}
domount() {
MNTPATH=$1
NFS_SERVER=$(echo $2 | jq -r '.server')
SHARE=$(echo $2 | jq -r '.share')
if [ $(ismounted) -eq 1 ] ; then
log '{"status": "Úspěch"}'
exit 0
fi
mkdir -p ${MNTPATH} &> \/dev\/null
mount -t nfs ${NFS_SERVER}:\/\${SHARE} ${MNTPATH} &> \/dev\/null
if [ $? -ne 0 ]; then
err "{ "status": "Selhání", "message": "Selhalo připojení ${NFS_SERVER}:${SHARE} na ${MNTPATH}"}"
exit 1
fi
log '{"status": "Úspěch"}'
exit 0
}
unmount() {
MNTPATH=$1
if [ $(ismounted) -eq 0 ] ; then
log '{"status": "Úspěch"}'
exit 0
fi
umount ${MNTPATH} &> \/dev\/null
if [ $? -ne 0 ]; then
err "{ "status": "Selhalo", "message": "Selhalo odpojení svazku na ${MNTPATH}"}"
exit 1
fi
log '{"status": "Úspěch"}'
exit 0
}
op=$1
if [ "$op" = "init" ]; then
log '{"status": "Úspěch", "capabilities": {"attach": false}}'
exit 0
fi
if [ $# -lt 2 ]; then
usage
fi
shift
case "$op" in
mount)
domount $*
;;
unmount)
unmount $*
;;
*)
log '{"status": "Nepodporováno"}'
exit 0
esac
exit 1Takže po přípravě vlastního spustitelného souboru je třeba nahrát ovladač do Kubernetes clusteru. Ovladač by měl být na každém uzlu clusteru podle předem dohodnuté cesty. Standardně byla zvolena:
/usr/libexec/kubernetes/kubelet-plugins/volume/exec/имя_поставщика_хранилища~имя_драйвера/
… ale při použití různých distribucí Kubernetes (OpenShift, Rancher…) může být cesta jiná.
Problémy Flexvolume: jak správně házet udici?
Nahrání Flexvolume ovladače na uzly clusteru se ukázalo jako netriviální úkol. Po provedení operace jednou ručně se snadno dostanete do situace, kdy v clusteru přibudou nové uzly: z důvodu přidání nového uzlu, automatického horizontálního škálování nebo — co je horší — výměny uzlu kvůli závadě. V tomto případě je práce se skladováním na těchto uzlech prováděna nemožné, dokud nebudete stále ručně přidávat Flexvolume ovladač na ně.
Řešením tohoto problému se stal jeden z primitivů Kubernetes — DaemonSetKdyž se v clusteru objeví nový uzel, automaticky se na něm umístí pod z našeho DaemonSetu, ke kterému se připojí lokální svazek podle cesty pro hledání ovladačů Flexvolume. Při úspěšném vytvoření podu se potřebné soubory pro funkčnost ovladače zkopírují na disk.
Zde je příklad takového DaemonSetu pro nasazení plovoucího plugu Flexvolume:
apiVersion: extensions/v1beta1
kind: DaemonSet
metadata:
name: flex-set
spec:
template:
metadata:
name: flex-deploy
labels:
app: flex-deploy
spec:
containers:
- image:
name: flex-deploy
securityContext:
privileged: true
volumeMounts:
- mountPath: /flexmnt
name: flexvolume-mount
volumes:
- name: flexvolume-mount
hostPath:
path:… a příklad Bash skriptu pro nasazení ovladače Flexvolume:
#!/bin/sh
set -o errexit
set -o pipefail
VENDOR=k8s.io
DRIVER=nfs
driver_dir=$VENDOR${VENDOR:+"~"}${DRIVER}
if [ ! -d "/flexmnt/$driver_dir" ]; then
mkdir "/flexmnt/$driver_dir"
fi
cp "/$DRIVER" "/flexmnt/$driver_dir/.$DRIVER"
mv -f "/flexmnt/$driver_dir/.$DRIVER" "/flexmnt/$driver_dir/$DRIVER"
while : ; do
sleep 3600
doneJe důležité nezapomenout, že operace kopírování není atomární.Je velká pravděpodobnost, že kubelet začne používat ovladač dříve, než bude proces jeho přípravy dokončen, což způsobí chybu v systému. Správný přístup by byl nejprve zkopírovat soubory ovladače pod jiným názvem a poté použít atomární operaci přejmenování.

Schéma práce s Ceph v operátoru Rook: ovladač Flexvolume je na schématu umístěn uvnitř agenta Rook.
Dalším problémem při použití ovladačů Flexvolume je, že pro většinu uložišť na uzlu clusteru musí být nainstalován potřebný software. (například balíček ceph-common pro Ceph). Původně nebyl plugin Flexvolume navržen pro implementaci tak složitých systémů.
Originální řešení tohoto problému lze vidět v implementaci ovladače Flexvolume operátora Rook:
Samotný ovladač je proveden jako RPC klient. IPC socket pro komunikaci se nachází ve stejném adresáři jako samotný ovladač. Pamatujeme si, že pro kopírování souborů ovladače by bylo dobré použít DaemonSet, který jako svazek připojuje adresář s ovladačem. Po zkopírování potřebných souborů ovladače rook tento pod nezmizí, ale připojí se k IPC socketu prostřednictvím připojeného svazku jako plnohodnotný RPC server. Balíček ceph-common je již nainstalován uvnitř kontejneru podu. IPC socket zaručuje, že kubelet bude komunikovat právě s tím pod, který se nachází na stejném uzlu. Vše geniální je jednoduché!..
Sbohem, naši milí... plugginům in-tree!
Vývojáři Kubernetes zjistili, že počet pluginů pro úložiště v jádře dosahuje dvaceti. A změna v každém z nich prochází úplným uvolňovacím cyklem Kubernetes.
Ukazuje se, že pro použití nové verze pluginu pro úložiště, je nutné aktualizovat celý klastr. K tomu se můžete divit, že nová verze Kubernetes se najednou stane nekompatibilní s používaným jádrem Linuxu... Takže si utíráte slzy a se skřípěním zubů domlouváte s nadřízenými a uživateli čas aktualizace jádra Linuxu a klastru Kubernetes. S možným prostoji v poskytovaných službách.
Situace je víc než komická, nemyslíte? Celému společenství bylo jasné, že tento přístup nefunguje. Z rozhodnutí vývojářů Kubernetes se noví pluginy pro práci s úložišti již nebudou přijímat do jádra. Kromě toho, jak již víme, byl u Flexvolume pluginu identifikován celá řada nedostatků...
Jednou provždy vyřešit problém s perzistentními úložišti dat měl poslední přidaný plugin pro svazky v Kubernetes — CSI. Jeho alfa verzi, plně nazvanou jako „Out-of-Tree CSI Volume Plugins“, ohlásili v uvolnění .
Container Storage Interface, neboli spinující CSI 3000!
Nejdříve bych chtěl zdůraznit, že CSI není jen volume plugin, ale skutečný pro vytváření uživatelských komponent pro práci s datovými úložišti.Předpokládalo se, že systémy pro orchestraci kontejnerů, jako Kubernetes a Mesos, by se měly naučit pracovat s komponentami implementovanými podle této normy. A teď se Kubernetes již naučil.
Jak vlastně funguje plugin CSI v Kubernetes? Plugin CSI pracuje se speciálními ovladači (CSI-ovladači), které napsali externí vývojáři. Ovladač CSI v Kubernetes musí minimálně sestávat ze dvou komponent (podů):
- Ovladač — spravuje externí perzistentní úložiště. Uvolňuje se jako gRPC server, pro který se používá primitiva
StatefulSet. - Node — odpovídá za připojení perzistentních úložišť k uzlům klastru. Také se realizuje jako gRPC server, ale pro něj se používá primitiva
DaemonSet.

Diagram fungování pluginu CSI v Kubernetes
O některých jiných podrobnostech fungování CSI se můžete dozvědět například z článku „», jsme publikovali před rokem.
Výhody takové realizace
- Pro základní věci — jako je registrace ovladače pro uzel — vývojáři Kubernetes realizovali sadu kontejnerů. Není již potřeba vytvářet JSON odpověď s capabilities, jako tomu bylo u pluginu Flexvolume.
- Místo „vkládání“ spustitelných souborů na uzly nyní nasazujeme pod’y do clustru. To jsme od Kubernetes původně očekávali: všechny procesy probíhají uvnitř kontejnerů, které jsou nasazeny pomocí primitiv Kubernetes.
- Pro realizaci složitějších ovladačů již není potřeba vyvíjet RPC server a RPC klienta. Klienta za nás vytvořili vývojáři Kubernetes.
- Předávání argumentů pro práci s protokolem gRPC je mnohem pohodlnější, flexibilnější a spolehlivější než předávání přes argumenty příkazového řádku. Pro pochopení, jak přidat v CSI podporu metrik pro využití objemu pomocí standardizované gRPC metody, se můžete podívat na pro ovladač vsphere-csi.
- Komunikace probíhá přes IPC sockety, abychom se neztráceli vtom, kterému pod'u kubelet poslal žádost.
Tento seznam vám něco nepřipomíná? Výhody CSI jsou řešením těchto problémů, které nebyly zohledněny při vývoji pluginu Flexvolume.
Závěry
CSI jako standard pro implementaci uživatelských pluginů pro interakci se storage systémy byl komunitou přijat velmi vřele. Navíc, díky svým výhodám a univerzálnosti, jsou CSI ovladače vytvářeny i pro takové úložiště jako Ceph nebo AWS EBS, pro které byly pluginy přidány již v první verzi Kubernetes.
Na začátku roku 2019 byly in-tree pluginy . Plánuje se pokračovat v podpoře pluginu Flexvolume, ale nové funkce pro něj vyvíjeny nebudou.
Sami již máme zkušenosti s využíváním ceph-csi, vsphere-csi a jsme připraveni tento seznam doplnit! Zatím si CSI skvěle poradí s úkoly, které byly na něj kladeny, a jak se to s vývojem ukáže, uvidíme.
Nezapomeňte, že vše nové je dobře přepracované staré!
P.S.
Přečtěte si také náš blog:
- «»;
- «»;
- «».
Zdroj: habr.com
