Volume pluginy pro úložiště Kubernetes: od Flexvolume po CSI

Volume pluginy pro úložiště Kubernetes: od Flexvolume po CSI

Když byl Kubernetes ještě v1.0.0, existovaly moduly pro objem. Byly potřeba k připojení systémů ke Kubernetes pro ukládání trvalých (trvalých) dat kontejnerů. Jejich počet byl malý a mezi prvními byli poskytovatelé úložiště jako GCE PD, Ceph, AWS EBS a další.

Pluginy byly dodány spolu s Kubernetes, a proto dostaly svůj název - in-tree. Pro mnohé se však stávající sada takových pluginů ukázala jako nedostatečná. Řemeslníci přidali jednoduché pluginy do jádra Kubernetes pomocí patchů, poté sestavili vlastní Kubernetes a nainstalovali je na své servery. Ale postupem času si to vývojáři Kubernetes uvědomili ryby problém nelze vyřešit. Lidé potřebují rybářský prut. A ve vydání Kubernetes v1.2.0 se objevilo...

Flexvolume plugin: minimální rybářský prut

Vývojáři Kubernetes vytvořili plugin FlexVolume, což byl logický rámec proměnných a metod pro práci s ovladači Flexvolume implementovaný vývojáři třetích stran.

Zastavme se a podívejme se blíže na to, co je ovladač FlexVolume. To je jisté spustitelný soubor (binární soubor, skript Python, skript Bash atd.), který po spuštění přebírá argumenty příkazového řádku jako vstup a vrací zprávu s předem známými poli ve formátu JSON. Podle konvence je prvním argumentem příkazového řádku vždy metoda a zbývající argumenty jsou její parametry.

Volume pluginy pro úložiště Kubernetes: od Flexvolume po CSI
Schéma připojení pro CIFS Shares v OpenShift. Flexvolume Driver – přímo v centru

Minimální soubor metod Vypadá to takhle:

flexvolume_driver mount # отвечает за присоединение тома к pod'у
# Формат возвращаемого сообщения:
{
  "status": "Success"/"Failure"/"Not supported",
  "message": "По какой причине был возвращен именно такой статус",
}

flexvolume_driver unmount # отвечает за отсоединение тома от pod'а
# Формат возвращаемого сообщения:
{
  "status": "Success"/"Failure"/"Not supported",
  "message": "По какой причине был возвращен именно такой статус",
}

flexvolume_driver init # отвечает за инициализацию плагина
# Формат возвращаемого сообщения:
{
  "status": "Success"/"Failure"/"Not supported",
  "message": "По какой причине был возвращен именно такой статус",
  // Определяет, использует ли драйвер методы attach/deatach
  "capabilities":{"attach": True/False}
}

Použití metod attach и detach bude definovat scénář, ve kterém bude kubelet v budoucnu jednat při volání řidiče. Existují i ​​speciální metody expandvolume и expandfs, které jsou zodpovědné za dynamickou změnu velikosti svazku.

Jako příklad změn, které metoda přidává expandvolumea díky možnosti měnit velikost svazků v reálném čase se můžete seznámit náš požadavek na stažení v operátorovi Rook Ceph.

A zde je příklad implementace ovladače Flexvolume pro práci s NFS:

usage() {
    err "Invalid usage. Usage: "
    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": "Success"}'
        exit 0
    fi

    mkdir -p ${MNTPATH} &> /dev/null

    mount -t nfs ${NFS_SERVER}:/${SHARE} ${MNTPATH} &> /dev/null
    if [ $? -ne 0 ]; then
        err "{ "status": "Failure", "message": "Failed to mount ${NFS_SERVER}:${SHARE} at ${MNTPATH}"}"
        exit 1
    fi
    log '{"status": "Success"}'
    exit 0
}

unmount() {
    MNTPATH=$1
    if [ $(ismounted) -eq 0 ] ; then
        log '{"status": "Success"}'
        exit 0
    fi

    umount ${MNTPATH} &> /dev/null
    if [ $? -ne 0 ]; then
        err "{ "status": "Failed", "message": "Failed to unmount volume at ${MNTPATH}"}"
        exit 1
    fi

    log '{"status": "Success"}'
    exit 0
}

op=$1

if [ "$op" = "init" ]; then
    log '{"status": "Success", "capabilities": {"attach": false}}'
    exit 0
fi

if [ $# -lt 2 ]; then
    usage
fi

shift

case "$op" in
    mount)
        domount $*
        ;;
    unmount)
        unmount $*
        ;;
    *)
        log '{"status": "Not supported"}'
        exit 0
esac

exit 1

Takže po přípravě skutečného spustitelného souboru musíte nahrajte ovladač do clusteru Kubernetes. Ovladač musí být umístěn na každém uzlu clusteru podle předem určené cesty. Ve výchozím nastavení bylo vybráno:

/usr/libexec/kubernetes/kubelet-plugins/volume/exec/имя_поставщика_хранилища~имя_драйвера/

... ale při použití různých distribucí Kubernetes (OpenShift, Rancher...) může být cesta odlišná.

Problémy s Flexvolume: jak správně nahodit rybářský prut?

Nahrání ovladače Flexvolume do uzlů clusteru se ukázalo jako netriviální úkol. Po ručním provedení operace se snadno může stát, že se v clusteru objeví nové uzly: přidáním nového uzlu, automatickým horizontálním měřítkem nebo - co je horší - nahrazením uzlu z důvodu poruchy. V tomto případě by měla být provedena práce s úložištěm na těchto uzlech je nemožné, dokud k nim stále ručně nepřidáte ovladač Flexvolume.

Řešením tohoto problému bylo jedno z primitiv Kubernetes - DaemonSet. Když se v clusteru objeví nový uzel, automaticky obsahuje modul z naší DaemonSet, ke kterému je podél cesty připojen místní svazek za účelem nalezení ovladačů Flexvolume. Po úspěšném vytvoření modul zkopíruje soubory potřebné pro práci ovladače na disk.

Zde je příklad takového DaemonSet pro rozložení pluginu Flexvolume:

apiVersion: extensions/v1beta1
kind: DaemonSet
metadata:
  name: flex-set
spec:
  template:
    metadata:
      name: flex-deploy
      labels:
        app: flex-deploy
    spec:
      containers:
        - image: <deployment_image>
          name: flex-deploy
          securityContext:
              privileged: true
          volumeMounts:
            - mountPath: /flexmnt
              name: flexvolume-mount
      volumes:
        - name: flexvolume-mount
          hostPath:
            path: <host_driver_directory>

... a příklad skriptu Bash pro rozložení 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
done

Je důležité nezapomenout, že operace kopírování není atomový. Existuje vysoká pravděpodobnost, že kubelet začne používat ovladač před dokončením procesu poskytování, což způsobí zhroucení systému. Správný přístup je nejprve zkopírovat soubory ovladače pod jiným názvem a poté použít operaci atomického přejmenování.

Volume pluginy pro úložiště Kubernetes: od Flexvolume po CSI
Schéma práce s Ceph v operátoru Rook: ovladač Flexvolume v diagramu je umístěn uvnitř agenta Rook

Dalším problémem při použití ovladačů Flexvolume je to, že pro většinu úložiště v uzlu clusteru k tomu musí být nainstalován potřebný software (například balíček ceph-common pro Ceph). Zpočátku nebyl zásuvný modul 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 navržen jako RPC klient. IPC socket pro komunikaci je umístěn 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ý spojuje adresář s ovladačem jako svazek. Po zkopírování potřebných souborů ovladače věže tento modul nezemře, ale připojí se k IPC socketu přes připojený svazek jako plnohodnotný RPC server. Balíček ceph-common je již nainstalován uvnitř kontejneru pod. IPC zásuvka zajišťuje, že kubelet bude komunikovat přesně s podem, který je umístěn na stejném uzlu. Všechno důmyslné je jednoduché!...

Sbohem, naše milé... pluginy ve stromě!

Vývojáři Kubernetes zjistili, že počet pluginů pro úložiště v jádru je dvacet. A změna v každém z nich, tak či onak, prochází celým cyklem vydání Kubernetes.

Ukazuje se, že chcete-li použít novou verzi pluginu úložiště, musíte aktualizovat celý cluster. Kromě toho vás možná překvapí, že se nová verze Kubernetes náhle stane nekompatibilní s linuxovým jádrem, které používáte... Takže si utřete slzy a se skřípěním zubů koordinujete se svým vedením a uživateli čas aktualizujte jádro Linuxu a cluster Kubernetes. S možnými výpadky v poskytování služeb.

Situace je více než komická, nemyslíte? Celé komunitě bylo jasné, že tento přístup nefunguje. Záměrným rozhodnutím vývojáři Kubernetes oznamují, že nové pluginy pro práci s úložištěm již nebudou do jádra přijímány. Navíc, jak již víme, byla při implementaci pluginu Flexvolume zjištěna řada nedostatků...

Nejnovější přidaný plugin pro svazky v Kubernetes, CSI, byl vyzván, aby problém s trvalým ukládáním dat jednou provždy uzavřel. Jeho alfa verze, plněji označovaná jako Out-of-Tree CSI Volume Plugins, byla oznámena ve vydání Kubernetes 1.9.

Container Storage Interface nebo přívlač CSI 3000!

Nejprve bych rád poznamenal, že CSI není jen objemový plugin, ale skutečný standardní o vytváření vlastních komponent pro práci s datovými sklady. Systémy pro orchestraci kontejnerů jako Kubernetes a Mesos se měly „naučit“ pracovat s komponentami implementovanými podle tohoto standardu. A teď už jsem se naučil Kubernetes.

Jaká je struktura pluginu CSI v Kubernetes? CSI plugin pracuje se speciálními ovladači (CSI ovladače) napsané vývojáři třetích stran. Ovladač CSI v Kubernetes by se měl skládat minimálně ze dvou komponent (podů):

  • kontrolor — spravuje externí trvalá úložiště. Je implementován jako gRPC server, pro který se používá primitiv StatefulSet.
  • Uzel — odpovídá za připojení trvalého úložiště do uzlů clusteru. Je také implementován jako gRPC server, ale používá se pro něj primitiv DaemonSet.

Volume pluginy pro úložiště Kubernetes: od Flexvolume po CSI
Jak funguje plugin CSI v Kubernetes

O některých dalších detailech práce CSI se můžete dozvědět například z článku „Pochopení C.S.I." jehož překlad jsme vydali před rokem.

Výhody takové implementace

  • Pro základní věci, jako je registrace ovladače pro uzel, vývojáři Kubernetes implementovali sadu kontejnerů. Již nemusíte sami generovat odpověď JSON s funkcemi, jak tomu bylo u pluginu Flexvolume.
  • Namísto „podsouvání“ spustitelných souborů na uzly nyní nahráváme pody do clusteru. To je to, co zpočátku očekáváme od Kubernetes: všechny procesy probíhají uvnitř kontejnerů nasazených pomocí primitiv Kubernetes.
  • K implementaci složitých ovladačů již nemusíte vyvíjet server RPC a klienta RPC. Klienta pro nás implementovali vývojáři Kubernetes.
  • Předávání argumentů pro práci přes protokol gRPC je mnohem pohodlnější, flexibilnější a spolehlivější než předávání argumentů příkazového řádku. Chcete-li pochopit, jak přidat podporu pro metriky využití objemu do CSI přidáním standardizované metody gRPC, můžete si přečíst: náš požadavek na stažení pro ovladač vsphere-csi.
  • Komunikace probíhá přes IPC zásuvky, aby nedošlo k záměně, zda kubelet odeslal požadavek na správný modul.

Připomíná vám tento seznam něco? Výhody CSI jsou řešení stejných problémů, které nebyly zohledněny při vývoji pluginu Flexvolume.

Závěry

CSI jako standard pro implementaci vlastních pluginů pro interakci s datovými sklady byl komunitou velmi vřele přijat. Navíc díky svým výhodám a všestrannosti jsou CSI ovladače vytvořeny i pro úložné systémy jako Ceph nebo AWS EBS, pluginy pro práci s nimi byly přidány v úplně první verzi Kubernetes.

Na začátku roku 2019 in-tree pluginy byly prohlášeny za zastaralé. Plánujeme pokračovat v podpoře zásuvného modulu Flexvolume, ale nebudeme pro něj vyvíjet nové funkce.

Sami již máme zkušenosti s používáním ceph-csi, vsphere-csi a jsme připraveni tento seznam přidat! CSI se zatím vyrovnává s úkoly, které mu byly přiděleny, s třeskem, ale počkáme a uvidíme.

Nezapomeňte, že všechno nové je dobré přehodnocení starého!

PS

Přečtěte si také na našem blogu:

Zdroj: www.habr.com

Přidat komentář