Pluginuri de volum pentru stocarea Kubernetes: de la Flexvolume la CSI

Pluginuri de volum pentru stocarea Kubernetes: de la Flexvolume la CSI

Pe vremea când Kubernetes era încă v1.0.0, existau pluginuri de volum. Erau necesare pentru a conecta sistemele la Kubernetes pentru stocarea datelor persistente (permanente) ale containerelor. Numărul lor a fost mic, iar printre primii s-au numărat furnizori de stocare precum GCE PD, Ceph, AWS EBS și alții.

Pluginurile au fost livrate împreună cu Kubernetes, motiv pentru care și-au primit numele - în arbore. Cu toate acestea, pentru mulți, setul existent de astfel de plugin-uri s-a dovedit a fi insuficient. Artizanii au adăugat pluginuri simple la nucleul Kubernetes folosind patch-uri, după care și-au asamblat propriile Kubernetes și l-au instalat pe serverele lor. Dar, de-a lungul timpului, dezvoltatorii Kubernetes și-au dat seama de asta pește problema nu poate fi rezolvata. Oamenii au nevoie toiag de pescuit. Și în lansarea Kubernetes v1.2.0 a apărut...

Plugin Flexvolume: undiță minimă

Dezvoltatorii Kubernetes au creat pluginul FlexVolume, care era un cadru logic de variabile și metode de lucru cu driverele Flexvolume implementate de dezvoltatori terți.

Să ne oprim și să aruncăm o privire mai atentă la ce este driverul FlexVolume. Acesta este un cert fisier executabil (fișier binar, script Python, script Bash etc.), care, atunci când este executat, ia argumente de linie de comandă ca intrare și returnează un mesaj cu câmpuri precunoscute în format JSON. Prin convenție, primul argument din linia de comandă este întotdeauna o metodă, iar argumentele rămase sunt parametrii săi.

Pluginuri de volum pentru stocarea Kubernetes: de la Flexvolume la CSI
Diagrama de conectare pentru CIFS Shares în OpenShift. Flexvolume Driver - chiar în centru

Set minim de metode arată astfel:

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

Utilizarea Metodelor attach и detach va defini scenariul în care kubelet-ul va acționa în viitor la apelarea șoferului. Există și metode speciale expandvolume и expandfs, care sunt responsabile pentru redimensionarea dinamică a volumului.

Ca exemplu al modificărilor pe care le adaugă metoda expandvolume, și cu acesta capacitatea de a redimensiona volume în timp real, vă puteți familiariza cu cererea noastră de tragere în Rook Ceph Operator.

Și iată un exemplu de implementare a driverului Flexvolume pentru lucrul cu 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

Deci, după pregătirea fișierului executabil propriu-zis, trebuie încărcați driverul în clusterul Kubernetes. Driverul trebuie să fie localizat pe fiecare nod de cluster în conformitate cu o cale predeterminată. Implicit a fost selectat:

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

... dar atunci când utilizați diferite distribuții Kubernetes (OpenShift, Rancher...) calea poate fi diferită.

Probleme de flexibilitate: cum să aruncați corect o undiță?

Încărcarea driverului Flexvolume în nodurile cluster s-a dovedit a fi o sarcină netrivială. După ce ați făcut operația manual o singură dată, este ușor să întâlniți o situație în care apar noi noduri în cluster: datorită adăugării unui nou nod, scalare orizontală automată sau - ceea ce este mai rău - înlocuirea unui nod din cauza unei defecțiuni. În acest caz, ar trebui să se lucreze cu stocarea pe aceste noduri este imposibil, până când le adăugați manual driverul Flexvolume.

Soluția la această problemă a fost una dintre primitivele Kubernetes - DaemonSet. Când apare un nou nod în cluster, acesta conține automat un pod din DaemonSet, la care este atașat un volum local de-a lungul căii pentru a găsi drivere Flexvolume. După crearea cu succes, podul copiază fișierele necesare pentru ca driverul să funcționeze pe disc.

Iată un exemplu de astfel de DaemonSet pentru amenajarea unui plugin 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 un exemplu de script Bash pentru aranjarea driverului 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

Este important să nu uităm că operația de copiere nu este atomic. Există o șansă mare ca kubelet să înceapă să folosească driverul înainte ca procesul de furnizare să fie finalizat, provocând blocarea sistemului. Abordarea corectă este să copiați mai întâi fișierele driverului sub un alt nume și apoi să utilizați o operație de redenumire atomică.

Pluginuri de volum pentru stocarea Kubernetes: de la Flexvolume la CSI
Diagrama de lucru cu Ceph în operatorul Rook: driverul Flexvolume din diagramă este situat în interiorul agentului Rook

Următoarea problemă atunci când utilizați driverele Flexvolume este cea pentru majoritatea stocării pe un nod de cluster software-ul necesar pentru aceasta trebuie instalat (de exemplu, pachetul ceph-common pentru Ceph). Inițial, pluginul Flexvolume nu a fost conceput pentru a implementa astfel de sisteme complexe.

O soluție originală la această problemă poate fi văzută în implementarea driverului Flexvolume a operatorului Rook:

Driverul în sine este proiectat ca un client RPC. Soclul IPC pentru comunicare se află în același director cu driverul însuși. Ne amintim că pentru a copia fișierele driverului ar fi bine să folosiți DaemonSet, care conectează directorul cu driverul ca volum. După copierea fișierelor de driver rook necesare, acest pod nu moare, ci se conectează la soclul IPC prin volumul atașat ca un server RPC cu drepturi depline. Pachetul ceph-common este deja instalat în interiorul containerului pod. Priza IPC asigură că kubelet-ul va comunica exact cu podul care se află pe același nod. Totul ingenios este simplu!...

La revedere, pluginurile noastre afectuoase... în arbore!

Dezvoltatorii Kubernetes au descoperit că numărul de pluginuri pentru stocare în nucleu este de douăzeci. Și o schimbare în fiecare dintre ele, într-un fel sau altul, trece prin ciclul complet de lansare Kubernetes.

Se pare că pentru a utiliza noua versiune a pluginului de stocare, trebuie să actualizați întregul cluster. În plus, s-ar putea să fii surprins că noua versiune de Kubernetes va deveni brusc incompatibilă cu kernel-ul Linux pe care îl folosești... Așa că îți ștergi lacrimile și, strângând din dinți, coordonezi cu managementul și utilizatorii timpul necesar. actualizați nucleul Linux și clusterul Kubernetes. Cu posibile perioade de nefuncţionare în prestarea serviciilor.

Situația este mai mult decât comică, nu crezi? A devenit clar pentru întreaga comunitate că abordarea nu funcționează. Printr-o decizie intenționată, dezvoltatorii Kubernetes anunță că noile plugin-uri pentru lucrul cu stocarea nu vor mai fi acceptate în kernel. În plus, după cum știm deja, au fost identificate o serie de deficiențe în implementarea pluginului Flexvolume...

Cel mai recent plugin adăugat pentru volume în Kubernetes, CSI, a fost solicitat să închidă problema cu stocarea persistentă a datelor o dată pentru totdeauna. Versiunea sa alfa, denumită mai detaliat Out-of-Tree CSI Volume Plugins, a fost anunțată în lansare. Kubernetes 1.9.

Container Storage Interface sau lansetă de filare CSI 3000!

În primul rând, aș dori să observ că CSI nu este doar un plugin de volum, ci un real стандарт privind crearea de componente personalizate pentru lucrul cu depozitele de date. Sistemele de orchestrare a containerelor, cum ar fi Kubernetes și Mesos, trebuiau să „învețe” cum să lucreze cu componentele implementate conform acestui standard. Și acum am învățat deja Kubernetes.

Care este structura pluginului CSI în Kubernetes? Pluginul CSI funcționează cu drivere speciale (Drivere CSI) scris de dezvoltatori terți. Un driver CSI în Kubernetes ar trebui să fie alcătuit minim din două componente (pod-uri):

  • operator de date cu caracter personal, — gestionează stocările externe persistente. Este implementat ca server gRPC, pentru care se folosește primitivul StatefulSet.
  • Nod — este responsabil pentru montarea stocării persistente pe nodurile clusterului. De asemenea, este implementat ca server gRPC, dar folosește primitivul DaemonSet.

Pluginuri de volum pentru stocarea Kubernetes: de la Flexvolume la CSI
Cum funcționează pluginul CSI în Kubernetes

Puteți afla despre alte detalii despre activitatea CSI, de exemplu, din articolul „Înțelegerea C.S.I." traducere a căruia am publicat acum un an.

Avantajele unei astfel de implementări

  • Pentru lucruri de bază, cum ar fi înregistrarea unui driver pentru un nod, dezvoltatorii Kubernetes au implementat un set de containere. Nu mai trebuie să generați singur un răspuns JSON cu capabilități, așa cum sa făcut pentru pluginul Flexvolume.
  • În loc să „alunecăm” fișierele executabile pe noduri, acum încărcăm pod-uri în cluster. Aceasta este ceea ce ne așteptăm inițial de la Kubernetes: toate procesele au loc în interiorul containerelor implementate folosind primitive Kubernetes.
  • Nu mai trebuie să dezvoltați un server RPC și un client RPC pentru a implementa drivere complexe. Clientul a fost implementat pentru noi de către dezvoltatorii Kubernetes.
  • Transmiterea de argumente pentru a funcționa prin protocolul gRPC este mult mai convenabilă, flexibilă și de încredere decât trecerea lor prin argumente din linia de comandă. Pentru a înțelege cum să adăugați suport pentru valorile de utilizare a volumului la CSI prin adăugarea unei metode standardizate gRPC, puteți citi: cererea noastră de tragere pentru driverul vsphere-csi.
  • Comunicarea are loc prin prize IPC, pentru a nu fi confundat dacă kubelet-ul a trimis cererea la podul corect.

Aceasta lista iti aminteste de ceva? Avantajele CSI sunt rezolvarea acelorași probleme, care nu au fost luate în considerare la dezvoltarea pluginului Flexvolume.

Constatări

CSI ca standard pentru implementarea plugin-urilor personalizate pentru interacțiunea cu depozitele de date a fost primit foarte călduros de către comunitate. Mai mult, datorită avantajelor și versatilității lor, driverele CSI sunt create chiar și pentru sisteme de stocare precum Ceph sau AWS EBS, plugin-uri pentru lucru cu care au fost adăugate chiar în prima versiune de Kubernetes.

La începutul anului 2019, pluginuri în arbore au fost declarate învechite. Intenționăm să continuăm să sprijinim pluginul Flexvolume, dar nu vom dezvolta noi funcționalități pentru acesta.

Noi înșine avem deja experiență în utilizarea ceph-csi, vsphere-csi și suntem gata să adăugăm la această listă! Până acum, CSI se descurcă cu sarcinile care i-au fost atribuite, dar vom aștepta și vom vedea.

Nu uitați că tot ce este nou este un vechi bine regândit!

PS

Citește și pe blogul nostru:

Sursa: www.habr.com

Adauga un comentariu