Плъгини за обем за съхранение на Kubernetes: от Flexvolume до CSI

Плъгини за обем за съхранение на Kubernetes: от Flexvolume до CSI

Когато Kubernetes все още беше v1.0.0, имаше плъгини за обем. Те бяха необходими за свързване на системи към Kubernetes за съхраняване на постоянни (постоянни) контейнерни данни. Техният брой беше малък и сред първите бяха такива доставчици на съхранение като GCE PD, Ceph, AWS EBS и други.

Плъгините бяха доставени заедно с Kubernetes, поради което получиха името си - in-tree. За мнозина обаче съществуващият набор от такива добавки се оказа недостатъчен. Занаятчиите добавиха прости плъгини към ядрото на Kubernetes с помощта на кръпки, след което сглобиха свой собствен Kubernetes и го инсталираха на своите сървъри. Но с течение на времето разработчиците на Kubernetes осъзнаха това риба проблемът не може да бъде решен. Хората имат нужда от въдица. И в изданието на Kubernetes v1.2.0 се появи...

Плъгин Flexvolume: минимална въдица

Разработчиците на Kubernetes създадоха плъгина FlexVolume, който беше логическа рамка от променливи и методи за работа с драйвери Flexvolume, внедрени от разработчици на трети страни.

Нека спрем и да разгледаме по-отблизо какво представлява драйверът FlexVolume. Това е сигурно изпълним файл (двоичен файл, Python скрипт, Bash скрипт и т.н.), който, когато се изпълни, приема аргументи от командния ред като вход и връща съобщение с предварително известни полета във формат JSON. По конвенция първият аргумент на командния ред винаги е метод, а останалите аргументи са негови параметри.

Плъгини за обем за съхранение на Kubernetes: от Flexvolume до CSI
Диаграма на свързване за споделяния на CIFS в OpenShift. Драйвер Flexvolume - точно в центъра

Минимален набор от методи изглежда така:

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}
}

Използване на методи attach и detach ще определи сценария, в който kubelet ще действа в бъдеще, когато извиква драйвера. Има и специални методи expandvolume и expandfs, които са отговорни за динамичното преоразмеряване на силата на звука.

Като пример за промените, които методът добавя expandvolume, а с него и възможността за преоразмеряване на обеми в реално време, можете да се запознаете нашата заявка за изтегляне в Rook Ceph Operator.

И ето пример за внедряване на драйвера Flexvolume за работа с 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

Така че, след като подготвите действителния изпълним файл, трябва качете драйвера в клъстера Kubernetes. Драйверът трябва да се намира на всеки клъстерен възел според предварително определен път. По подразбиране е избрано:

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

... но когато използвате различни дистрибуции на Kubernetes (OpenShift, Rancher...), пътят може да е различен.

Проблеми с Flexvolume: как да замятате правилно въдица?

Качването на драйвера Flexvolume в клъстерни възли се оказа нетривиална задача. След като извършите операцията ръчно веднъж, лесно е да се сблъскате със ситуация, при която в клъстера се появяват нови възли: поради добавяне на нов възел, автоматично хоризонтално мащабиране или - което е по-лошо - подмяна на възел поради неизправност. В този случай трябва да се работи със съхранението на тези възли е невъзможно, докато не добавите ръчно драйвера Flexvolume към тях.

Решението на този проблем беше един от примитивите на Kubernetes - DaemonSet. Когато в клъстера се появи нов възел, той автоматично съдържа под от нашия DaemonSet, към който е прикрепен локален том по пътя за намиране на драйвери Flexvolume. При успешно създаване подът копира необходимите файлове за работа на драйвера на диск.

Ето пример за такъв DaemonSet за оформяне на плъгин 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>

... и пример за Bash скрипт за оформяне на драйвера 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

Важно е да не забравяме, че операцията за копиране не е атомно. Има голяма вероятност kubelet да започне да използва драйвера, преди процесът му на осигуряване да приключи, което да доведе до срив на системата. Правилният подход е първо да копирате файловете на драйвера под различно име и след това да използвате операция за атомно преименуване.

Плъгини за обем за съхранение на Kubernetes: от Flexvolume до CSI
Диаграма за работа с Ceph в оператора Rook: драйверът Flexvolume в диаграмата се намира в агента Rook

Следващият проблем при използване на драйвери Flexvolume е този за повечето хранилища на клъстерен възел необходимият софтуер за това трябва да бъде инсталиран (например общия пакет ceph за Ceph). Първоначално плъгинът Flexvolume не беше предназначен за внедряване на такива сложни системи.

Оригинално решение на този проблем може да се види в изпълнението на драйвера Flexvolume на оператора Rook:

Самият драйвер е проектиран като RPC клиент. IPC гнездото за комуникация се намира в същата директория като самия драйвер. Спомняме си, че за копиране на драйверни файлове би било добре да използвате DaemonSet, който свързва директорията с драйвера като обем. След копиране на необходимите файлове на драйвера на топа, този pod не умира, а се свързва към IPC сокета през прикачения том като пълноправен RPC сървър. Пакетът ceph-common вече е инсталиран в контейнера на pod. IPC сокетът гарантира, че kubelet ще комуникира точно с pod, който се намира на същия възел. Всичко гениално е просто!..

Сбогом, нашите привързани... плъгини в дърво!

Разработчиците на Kubernetes откриха, че броят на добавките за съхранение в ядрото е двадесет. И промяна във всяка от тях, по един или друг начин, преминава през пълния цикъл на издаване на Kubernetes.

Оказва се, че за да използвате новата версия на плъгина за съхранение, трябва да актуализирате целия клъстер. В допълнение към това може да се изненадате, че новата версия на Kubernetes внезапно ще стане несъвместима с Linux ядрото, което използвате... Така че избърсвате сълзите си и, скърцайки със зъби, координирате с вашето ръководство и потребители времето за актуализирайте ядрото на Linux и клъстера Kubernetes. С възможен престой в предоставянето на услугите.

Ситуацията е повече от комична, не мислите ли? За цялата общност стана ясно, че подходът не работи. С умишлено решение разработчиците на Kubernetes обявяват, че новите плъгини за работа със съхранение вече няма да се приемат в ядрото. Освен това, както вече знаем, бяха установени редица недостатъци при внедряването на плъгина Flexvolume...

Последният добавен плъгин за томове в Kubernetes, CSI, беше призован да затвори проблема с постоянното съхранение на данни веднъж завинаги. Неговата алфа версия, по-пълно наричана Out-of-Tree CSI Volume Plugins, беше обявена в изданието Kubernetes 1.9.

Интерфейс за съхранение на контейнери или въртяща се въдица CSI 3000!

Първо, бих искал да отбележа, че CSI не е просто плъгин за обем, а реален стандартен за създаване на персонализирани компоненти за работа със складове за данни. Системите за оркестриране на контейнери като Kubernetes и Mesos трябваше да се „научат“ как да работят с компоненти, внедрени съгласно този стандарт. И сега вече научих Kubernetes.

Каква е структурата на приставката CSI в Kubernetes? Добавката CSI работи със специални драйвери (CSI драйвери), написани от разработчици на трети страни. CSI драйверът в Kubernetes трябва да се състои минимум от два компонента (pods):

  • Регулатор — управлява външни постоянни хранилища. Той е реализиран като gRPC сървър, за който се използва примитива StatefulSet.
  • Възел — отговаря за монтирането на постоянно съхранение към клъстерни възли. Той също е реализиран като gRPC сървър, но използва примитива DaemonSet.

Плъгини за обем за съхранение на Kubernetes: от Flexvolume до CSI
Как работи приставката CSI в Kubernetes

Можете да научите за някои други подробности за работата на CSI, например от статията „Разбиране на C.S.I." превод на който публикувахме преди година.

Предимствата на такова изпълнение

  • За основни неща като регистриране на драйвер за възел, разработчиците на Kubernetes внедриха набор от контейнери. Вече не е необходимо сами да генерирате JSON отговор с възможности, както беше направено за приставката Flexvolume.
  • Вместо да „подхлъзваме“ изпълними файлове върху възли, сега качваме подове в клъстера. Това е, което първоначално очакваме от Kubernetes: всички процеси се случват в контейнери, разположени с помощта на примитиви на Kubernetes.
  • Вече не е необходимо да разработвате RPC сървър и RPC клиент за внедряване на сложни драйвери. Клиентът беше внедрен за нас от разработчици на Kubernetes.
  • Предаването на аргументи за работа през gRPC протокола е много по-удобно, гъвкаво и надеждно от предаването им през аргументи на командния ред. За да разберете как да добавите поддръжка за показатели за използване на обем към CSI чрез добавяне на стандартизиран gRPC метод, можете да прочетете: нашата заявка за изтегляне за vsphere-csi драйвер.
  • Комуникацията се осъществява чрез IPC сокети, за да не се бърка дали kubelet е изпратил заявката до правилния pod.

Този списък напомня ли ви за нещо? Предимствата на CSI са решаване на същите тези проблеми, които не са взети предвид при разработването на плъгина Flexvolume.

Данни

CSI като стандарт за внедряване на персонализирани добавки за взаимодействие със складове за данни беше много топло приет от общността. Освен това, поради своите предимства и гъвкавост, CSI драйверите се създават дори за системи за съхранение като Ceph или AWS EBS, плъгини за работа с които бяха добавени в първата версия на Kubernetes.

В началото на 2019 г. плъгини в дърво са обявени за остарели. Планираме да продължим да поддържаме приставката Flexvolume, но няма да разработваме нова функционалност за нея.

Ние самите вече имаме опит с използването на ceph-csi, vsphere-csi и сме готови да добавим към този списък! Засега CSI се справя с гръм и трясък с възложените му задачи, но ще почакаме и ще видим.

Не забравяйте, че всичко ново е добро преосмисляне на старото!

PS

Прочетете също в нашия блог:

Източник: www.habr.com

Добавяне на нов коментар