Plugins de volume pour le stockage Kubernetes : de Flexvolume à CSI

Plugins de volume pour le stockage Kubernetes : de Flexvolume à CSI

À l'époque où Kubernetes était encore v1.0.0, il existait des plugins de volume. Ils étaient nécessaires pour connecter les systèmes à Kubernetes afin de stocker les données de conteneur persistantes (permanentes). Leur nombre était faible et parmi les premiers figuraient des fournisseurs de stockage tels que GCE PD, Ceph, AWS EBS et autres.

Les plugins ont été livrés avec Kubernetes, c'est pourquoi ils tirent leur nom - in-tree. Cependant, pour beaucoup, l’ensemble existant de ces plugins s’est avéré insuffisant. Les artisans ont ajouté des plugins simples au cœur de Kubernetes à l'aide de correctifs, après quoi ils ont assemblé leur propre Kubernetes et l'ont installé sur leurs serveurs. Mais au fil du temps, les développeurs de Kubernetes ont réalisé que poisson le problème ne peut pas être résolu. Les gens ont besoin tige. Et dans la version de Kubernetes v1.2.0, il est apparu...

Plugin Flexvolume : canne à pêche minimale

Les développeurs Kubernetes ont créé le plugin FlexVolume, qui était un cadre logique de variables et de méthodes permettant de travailler avec les pilotes Flexvolume implémentés par des développeurs tiers.

Arrêtons-nous et examinons de plus près ce qu'est le pilote FlexVolume. C'est une certaine fichier exécutable (fichier binaire, script Python, script Bash, etc.), qui, une fois exécuté, prend les arguments de ligne de commande en entrée et renvoie un message avec des champs pré-connus au format JSON. Par convention, le premier argument de la ligne de commande est toujours une méthode et les arguments restants sont ses paramètres.

Plugins de volume pour le stockage Kubernetes : de Flexvolume à CSI
Schéma de connexion pour les partages CIFS dans OpenShift. Pilote Flexvolume - En plein centre

Ensemble minimum de méthodes Il ressemble à ceci:

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

Utiliser des méthodes attach и detach définira le scénario dans lequel le kubelet agira à l'avenir lors de l'appel du pilote. Il existe également des méthodes spéciales expandvolume и expandfs, qui sont responsables du redimensionnement dynamique du volume.

À titre d'exemple des changements ajoutés par la méthode expandvolume, et avec la possibilité de redimensionner les volumes en temps réel, vous pourrez vous familiariser avec notre demande de tirage dans l'opérateur Rook Ceph.

Et voici un exemple d'implémentation du pilote Flexvolume pour travailler avec 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

Ainsi, après avoir préparé le fichier exécutable proprement dit, vous devez télécharger le pilote sur le cluster Kubernetes. Le pilote doit être localisé sur chaque nœud du cluster selon un chemin prédéterminé. Par défaut, il a été sélectionné :

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

... mais lors de l'utilisation de différentes distributions Kubernetes (OpenShift, Rancher...) le chemin peut être différent.

Problèmes de Flexvolume : comment lancer correctement une canne à pêche ?

Le téléchargement du pilote Flexvolume sur les nœuds du cluster s'est avéré être une tâche non triviale. Après avoir effectué l'opération manuellement une fois, il est facile de rencontrer une situation où de nouveaux nœuds apparaissent dans le cluster : en raison de l'ajout d'un nouveau nœud, d'une mise à l'échelle horizontale automatique ou, pire encore, du remplacement d'un nœud en raison d'un dysfonctionnement. Dans ce cas, le travail avec le stockage sur ces nœuds doit être effectué impossible, jusqu'à ce que vous leur ajoutiez toujours manuellement le pilote Flexvolume.

La solution à ce problème était l'une des primitives Kubernetes - DaemonSet. Lorsqu'un nouveau nœud apparaît dans le cluster, il contient automatiquement un pod de notre DaemonSet, auquel un volume local est attaché le long du chemin pour trouver les pilotes Flexvolume. Une fois la création réussie, le pod copie les fichiers nécessaires au fonctionnement du pilote sur le disque.

Voici un exemple d'un tel DaemonSet pour la création d'un 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>

... et un exemple de script Bash pour la présentation du pilote 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

Il est important de ne pas oublier que l'opération de copie n'est pas atomique. Il y a de fortes chances que le kubelet commence à utiliser le pilote avant la fin de son processus de provisionnement, provoquant un crash du système. L'approche correcte consiste à copier d'abord les fichiers du pilote sous un nom différent, puis à utiliser une opération de renommage atomique.

Plugins de volume pour le stockage Kubernetes : de Flexvolume à CSI
Schéma de travail avec Ceph dans l'opérateur Rook : le pilote Flexvolume dans le diagramme est situé à l'intérieur de l'agent Rook

Le problème suivant lors de l'utilisation des pilotes Flexvolume est celui de la plupart des stockages sur un nœud de cluster. le logiciel nécessaire pour cela doit être installé (par exemple, le package ceph-common pour Ceph). Initialement, le plugin Flexvolume n'était pas conçu pour implémenter des systèmes aussi complexes.

Une solution originale à ce problème peut être vue dans l'implémentation du pilote Flexvolume de l'opérateur Rook :

Le pilote lui-même est conçu comme un client RPC. Le socket IPC pour la communication se trouve dans le même répertoire que le pilote lui-même. Nous rappelons que pour copier les fichiers du pilote, il serait bon d'utiliser DaemonSet, qui connecte le répertoire au pilote sous forme de volume. Après avoir copié les fichiers du pilote Rook nécessaires, ce pod ne meurt pas, mais se connecte au socket IPC via le volume connecté en tant que serveur RPC à part entière. Le package ceph-common est déjà installé dans le conteneur pod. Le socket IPC garantit que le kubelet communiquera exactement avec le pod situé sur le même nœud. Tout ce qui est ingénieux est simple !..

Adieu, nos affectueux... plugins in-tree !

Les développeurs de Kubernetes ont découvert que le nombre de plugins de stockage dans le noyau est de vingt. Et un changement dans chacun d’eux, d’une manière ou d’une autre, passe par le cycle complet de publication de Kubernetes.

Il s'avère que pour utiliser la nouvelle version du plugin de stockage, vous devez mettre à jour l'ensemble du cluster. En plus de cela, vous pourriez être surpris que la nouvelle version de Kubernetes devienne soudainement incompatible avec le noyau Linux que vous utilisez... Alors vous essuyez vos larmes et, en serrant les dents, vous coordonnez avec votre direction et les utilisateurs le temps de mettre à jour le noyau Linux et le cluster Kubernetes. Avec des temps d'arrêt possibles dans la fourniture de services.

La situation est plus que comique, vous ne trouvez pas ? Il est devenu clair pour l’ensemble de la communauté que cette approche ne fonctionnait pas. Par une décision délibérée, les développeurs de Kubernetes annoncent que les nouveaux plugins permettant de travailler avec le stockage ne seront plus acceptés dans le noyau. De plus, comme nous le savons déjà, un certain nombre de lacunes ont été identifiées dans l'implémentation du plugin Flexvolume...

Le dernier plugin ajouté pour les volumes dans Kubernetes, CSI, a été utilisé pour résoudre une fois pour toutes le problème du stockage de données persistant. Sa version alpha, plus largement appelée Out-of-Tree CSI Volume Plugins, a été annoncée dans le communiqué. Kubernetes 1.9.

Container Storage Interface, ou canne spinning CSI 3000 !

Tout d'abord, je tiens à préciser que CSI n'est pas qu'un simple plugin de volume, mais un véritable стандарт sur la création de composants personnalisés pour travailler avec des entrepôts de données. Les systèmes d'orchestration de conteneurs tels que Kubernetes et Mesos étaient censés « apprendre » à travailler avec des composants implémentés selon cette norme. Et maintenant, j'ai déjà appris Kubernetes.

Quelle est la structure du plugin CSI dans Kubernetes ? Le plugin CSI fonctionne avec des pilotes spéciaux (Pilotes CSI) écrit par des développeurs tiers. Un pilote CSI dans Kubernetes doit au minimum être composé de deux composants (pods) :

  • — gère les stockages persistants externes. Il est implémenté en tant que serveur gRPC, pour lequel la primitive est utilisée StatefulSet.
  • Nœud - est responsable du montage du stockage persistant sur les nœuds du cluster. Il est également implémenté en tant que serveur gRPC, mais il utilise la primitive DaemonSet.

Plugins de volume pour le stockage Kubernetes : de Flexvolume à CSI
Comment fonctionne le plugin CSI dans Kubernetes

Vous pouvez en apprendre davantage sur d’autres détails du travail de CSI, par exemple dans l’article «Comprendre le C.S.I." traduction dont nous avons publié il y a un an.

Les avantages d'une telle mise en œuvre

  • Pour des choses de base comme l'enregistrement d'un pilote pour un nœud, les développeurs Kubernetes ont implémenté un ensemble de conteneurs. Vous n'avez plus besoin de générer vous-même une réponse JSON avec des fonctionnalités, comme cela a été fait pour le plugin Flexvolume.
  • Au lieu de « glisser » des fichiers exécutables sur des nœuds, nous téléchargeons désormais des pods sur le cluster. C'est ce que nous attendons initialement de Kubernetes : tous les processus se déroulent dans des conteneurs déployés à l'aide de primitives Kubernetes.
  • Vous n'avez plus besoin de développer un serveur RPC et un client RPC pour implémenter des pilotes complexes. Le client a été implémenté pour nous par les développeurs Kubernetes.
  • Passer des arguments pour fonctionner via le protocole gRPC est beaucoup plus pratique, flexible et fiable que de les transmettre via des arguments de ligne de commande. Pour comprendre comment ajouter la prise en charge des métriques d'utilisation du volume à CSI en ajoutant une méthode gRPC standardisée, vous pouvez lire : notre demande de tirage pour le pilote vsphere-csi.
  • La communication s'effectue via les sockets IPC, afin de ne pas savoir si le kubelet a envoyé la requête au bon pod.

Cette liste ne vous rappelle rien ? Les avantages de CSI sont résoudre ces mêmes problèmes, qui n'ont pas été pris en compte lors du développement du plugin Flexvolume.

résultats

CSI en tant que standard pour la mise en œuvre de plugins personnalisés pour interagir avec les entrepôts de données a été très chaleureusement accueilli par la communauté. De plus, en raison de leurs avantages et de leur polyvalence, les pilotes CSI sont créés même pour les systèmes de stockage tels que Ceph ou AWS EBS, des plugins avec lesquels travailler ont été ajoutés dans la toute première version de Kubernetes.

Début 2019, les plugins in-tree ont été déclarés obsolètes. Nous prévoyons de continuer à prendre en charge le plugin Flexvolume, mais ne développerons pas de nouvelles fonctionnalités pour celui-ci.

Nous avons nous-mêmes déjà de l'expérience avec ceph-csi, vsphere-csi et sommes prêts à les ajouter à cette liste ! Jusqu’à présent, CSI s’acquitte avec brio des tâches qui lui sont assignées, mais nous attendrons de voir.

N'oubliez pas que tout ce qui est nouveau est une bonne refonte de l'ancien !

PS

A lire aussi sur notre blog :

Source: habr.com

Ajouter un commentaire