Wtyczki woluminów do pamięci masowej Kubernetes: od Flexvolume do CSI

Wtyczki woluminów do pamięci masowej Kubernetes: od Flexvolume do CSI

Kiedy Kubernetes był jeszcze w wersji 1.0.0, istniały wtyczki woluminów. Były potrzebne do połączenia systemów z Kubernetesem w celu przechowywania trwałych (stałych) danych kontenerowych. Ich liczba była niewielka, a wśród pierwszych byli tacy dostawcy pamięci masowej, jak GCE PD, Ceph, AWS EBS i inni.

Wtyczki zostały dostarczone wraz z Kubernetesem i stąd wzięła się ich nazwa – in-tree. Jednak dla wielu istniejący zestaw takich wtyczek okazał się niewystarczający. Rzemieślnicy dodali proste wtyczki do rdzenia Kubernetesa za pomocą łatek, po czym zmontowali własne Kubernetes i zainstalowali je na swoich serwerach. Jednak z biegiem czasu programiści Kubernetes zdali sobie z tego sprawę ryby problemu nie da się rozwiązać. Ludzie potrzebują wędka. A w wydaniu Kubernetes v1.2.0 pojawiło się...

Wtyczka Flexvolume: minimalna wędka

Programiści Kubernetes stworzyli wtyczkę FlexVolume, która stanowiła logiczną strukturę zmiennych i metod pracy ze sterownikami Flexvolume zaimplementowanymi przez zewnętrznych programistów.

Zatrzymajmy się i przyjrzyjmy się bliżej, czym jest sterownik FlexVolume. To jest pewne Plik wykonywalny (plik binarny, skrypt Pythona, skrypt Bash itp.), który po uruchomieniu pobiera argumenty wiersza poleceń jako dane wejściowe i zwraca komunikat ze znanymi polami w formacie JSON. Zgodnie z konwencją pierwszy argument wiersza poleceń jest zawsze metodą, a pozostałe argumenty są jej parametrami.

Wtyczki woluminów do pamięci masowej Kubernetes: od Flexvolume do CSI
Schemat połączeń udziałów CIFS w OpenShift. Sterownik Flexvolume — w samym centrum

Minimalny zestaw metod Wygląda to tak:

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

Używanie metod attach и detach zdefiniuje scenariusz, w którym kubelet będzie się zachowywał w przyszłości podczas wywoływania sterownika. Istnieją również metody specjalne expandvolume и expandfs, które odpowiadają za dynamiczną zmianę rozmiaru głośności.

Jako przykład zmian, które dodaje metoda expandvolume, a wraz z nim możliwość zmiany rozmiaru woluminów w czasie rzeczywistym, z którą możesz się zapoznać nasza prośba o ściągnięcie w Rook Ceph Operator.

A oto przykład implementacji sterownika Flexvolume do pracy z 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

Zatem po przygotowaniu rzeczywistego pliku wykonywalnego musisz to zrobić prześlij sterownik do klastra Kubernetes. Sterownik musi znajdować się w każdym węźle klastra zgodnie z ustaloną wcześniej ścieżką. Domyślnie wybrano:

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

... ale przy korzystaniu z różnych dystrybucji Kubernetes (OpenShift, Rancher...) ścieżka może być inna.

Problemy z Flexvolume: jak prawidłowo rzucić wędkę?

Wgranie sterownika Flexvolume do węzłów klastra okazało się zadaniem nietrywialnym. Wykonując raz tę operację ręcznie, łatwo spotkać się z sytuacją, w której w klastrze pojawią się nowe węzły: na skutek dodania nowego węzła, automatycznego skalowania w poziomie lub – co gorsza – wymiany węzła z powodu awarii. W takim przypadku należy wykonać pracę z pamięcią masową w tych węzłach jest niemożliwe, dopóki nie dodasz do nich ręcznie sterownika Flexvolume.

Rozwiązaniem tego problemu był jeden z prymitywów Kubernetesa - DaemonSet. Kiedy w klastrze pojawia się nowy węzeł, automatycznie zawiera on pod z naszego DaemonSet, do którego dołączany jest wolumin lokalny wzdłuż ścieżki w celu znalezienia sterowników Flexvolume. Po pomyślnym utworzeniu moduł kopiuje na dysk pliki niezbędne do działania sterownika.

Oto przykład takiego zestawu DaemonSet do układania wtyczki 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>

... i przykład skryptu Bash do układania sterownika 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

Ważne jest, aby nie zapomnieć o operacji kopiowania nie jest atomowy. Istnieje duże prawdopodobieństwo, że kubelet zacznie korzystać ze sterownika przed zakończeniem procesu udostępniania, co spowoduje awarię systemu. Prawidłowe podejście polega na skopiowaniu najpierw plików sterownika pod inną nazwą, a następnie zastosowaniu operacji atomowej zmiany nazwy.

Wtyczki woluminów do pamięci masowej Kubernetes: od Flexvolume do CSI
Schemat pracy z Cephem w operatorze Rook: sterownik Flexvolume na schemacie znajduje się wewnątrz agenta Rook

Następny problem podczas korzystania ze sterowników Flexvolume dotyczy większości pamięci w węźle klastra należy zainstalować niezbędne do tego oprogramowanie (na przykład pakiet ceph-common dla Ceph). Początkowo wtyczka Flexvolume nie była przeznaczona do wdrażania tak skomplikowanych systemów.

Oryginalne rozwiązanie tego problemu można zobaczyć w implementacji sterownika Flexvolume operatora Rook:

Sam sterownik został zaprojektowany jako klient RPC. Gniazdo IPC do komunikacji znajduje się w tym samym katalogu co sam sterownik. Pamiętamy, że do kopiowania plików sterownika dobrze byłoby skorzystać z DaemonSet, który łączy katalog ze sterownikiem jako wolumen. Po skopiowaniu niezbędnych plików sterownika rook, ten pod nie umiera, ale łączy się z gniazdem IPC poprzez dołączony wolumen jako pełnoprawny serwer RPC. Pakiet ceph-common jest już zainstalowany w kontenerze pod. Gniazdo IPC gwarantuje, że kubelet będzie komunikował się dokładnie z kapsułą, która znajduje się w tym samym węźle. Wszystko genialne jest proste!..

Żegnajcie, nasze kochane... wtyczki w drzewie!

Programiści Kubernetes odkryli, że liczba wtyczek do przechowywania w rdzeniu wynosi dwadzieścia. A zmiana w każdym z nich w ten czy inny sposób przechodzi przez pełny cykl wydawniczy Kubernetesa.

Okazuje się, że aby skorzystać z nowej wersji wtyczki do przechowywania danych, musisz zaktualizować cały klaster. Poza tym możesz być zaskoczony, że nowa wersja Kubernetesa nagle stanie się niekompatybilna z jądrem Linuksa, którego używasz... Więc ocierasz łzy i zaciskając zęby, uzgadniasz z zarządem i użytkownikami czas na zaktualizuj jądro Linuksa i klaster Kubernetes. Z możliwymi przestojami w świadczeniu usług.

Sytuacja jest bardziej niż komiczna, nie sądzisz? Dla całej społeczności stało się jasne, że to podejście nie działa. Świadomą decyzją programiści Kubernetes ogłaszają, że nowe wtyczki do pracy z pamięcią masową nie będą już akceptowane w jądrze. Poza tym jak już wiemy, zidentyfikowano szereg niedociągnięć we wdrażaniu wtyczki Flexvolume...

Ostatnio dodana wtyczka do woluminów w Kubernetesie, CSI, została wezwana, aby raz na zawsze zamknąć problem z trwałym przechowywaniem danych. W wydaniu ogłoszono jego wersję alfa, bardziej szczegółowo nazywaną wtyczkami wolumenowymi CSI Out-of-Tree Kubernetes 1.9.

Container Storage Interface, czyli wędka spinningowa CSI 3000!

Przede wszystkim chciałbym zauważyć, że CSI to nie tylko wtyczka głośności, ale prawdziwa стандарт na temat tworzenia niestandardowych komponentów do pracy z hurtowniami danych. Systemy orkiestracji kontenerów takie jak Kubernetes i Mesos miały „uczyć się” pracy z komponentami zaimplementowanymi według tego standardu. A teraz nauczyłem się już Kubernetesa.

Jaka jest struktura wtyczki CSI w Kubernetesie? Wtyczka CSI współpracuje ze specjalnymi sterownikami (Kierowcy CSI) napisane przez zewnętrznych programistów. Sterownik CSI w Kubernetes powinien składać się minimalnie z dwóch komponentów (podów):

  • kontroler — zarządza zewnętrznymi magazynami trwałymi. Jest zaimplementowany jako serwer gRPC, dla którego używany jest prymityw StatefulSet.
  • Node — odpowiada za montowanie pamięci trwałej w węzłach klastra. Jest również zaimplementowany jako serwer gRPC, ale używa prymitywu DaemonSet.

Wtyczki woluminów do pamięci masowej Kubernetes: od Flexvolume do CSI
Jak działa wtyczka CSI w Kubernetesie

O innych szczegółach pracy CSI możesz dowiedzieć się na przykład z artykułu „Zrozumienie C.S.I." tłumaczenie którego opublikowaliśmy rok temu.

Zalety takiego wdrożenia

  • Do podstawowych rzeczy, takich jak rejestracja sterownika dla węzła, programiści Kubernetes zaimplementowali zestaw kontenerów. Nie musisz już samodzielnie generować odpowiedzi JSON z możliwościami, jak miało to miejsce w przypadku wtyczki Flexvolume.
  • Zamiast „wrzucać” pliki wykonywalne na węzły, przesyłamy teraz pody do klastra. Tego właśnie początkowo oczekujemy od Kubernetesa: wszystkie procesy zachodzą w kontenerach wdrożonych przy użyciu prymitywów Kubernetes.
  • Nie musisz już tworzyć serwera RPC i klienta RPC, aby wdrożyć złożone sterowniki. Klient został dla nas wdrożony przez programistów Kubernetes.
  • Przekazywanie argumentów do pracy za pośrednictwem protokołu gRPC jest znacznie wygodniejsze, elastyczne i niezawodne niż przekazywanie ich za pomocą argumentów wiersza poleceń. Aby zrozumieć, jak dodać obsługę wskaźników wykorzystania wolumenu do CSI poprzez dodanie standardowej metody gRPC, możesz przeczytać: nasza prośba o ściągnięcie dla sterownika vsphere-csi.
  • Komunikacja odbywa się poprzez gniazda IPC, aby nie było wątpliwości, czy kubelet wysłał żądanie do odpowiedniego zasobnika.

Czy ta lista coś Ci przypomina? Zaletami CSI są rozwiązując te same problemy, które nie zostały wzięte pod uwagę przy opracowywaniu wtyczki Flexvolume.

odkrycia

CSI jako standard wdrażania niestandardowych wtyczek do interakcji z hurtowniami danych został bardzo ciepło przyjęty przez społeczność. Co więcej, sterowniki CSI ze względu na swoje zalety i wszechstronność są tworzone nawet dla systemów pamięci masowej takich jak Ceph czy AWS EBS, z którymi wtyczki do pracy zostały dodane już w pierwszej wersji Kubernetesa.

Na początku 2019 r. wtyczki w drzewie zostały uznane za przestarzałe. Planujemy nadal wspierać wtyczkę Flexvolume, ale nie będziemy opracowywać dla niej nowych funkcjonalności.

Sami mamy już doświadczenie w używaniu ceph-csi, vsphere-csi i jesteśmy gotowi dodać do tej listy! Na razie CSI radzi sobie z powierzonymi mu zadaniami z przytupem, ale poczekamy, zobaczymy.

Nie zapominaj, że wszystko, co nowe, jest dobrym przemyśleniem starego!

PS

Przeczytaj także na naszym blogu:

Źródło: www.habr.com

Dodaj komentarz