Opérateur Tarantool Kubernetes



Kubernetes devient la norme de facto pour l'exécution d'applications sans état. Principalement parce qu'il peut réduire considérablement le délai de mise sur le marché pour la livraison de nouvelles fonctionnalités. Le lancement d'applications avec état - bases de données, microservices avec état - est toujours une tâche difficile, mais la nécessité de résister à la concurrence et de maintenir un taux de livraison élevé pousse les entreprises à expérimenter dans ce domaine et crée une demande pour de telles solutions.

Nous vous présentons notre solution pour le lancement de clusters avec état Cartouche Tarantool : Tarantool Kubernetes Operator , pour plus de détails je demande sous cat.

Table des matières:

  1. Au lieu de mille mots
  2. Que fait l'opérateur du tout
  3. Un peu sur les nuances
  4. Comment fonctionne l'opérateur
  5. Ce que l'opérateur étend
  6. Résumé


Tarantool est une base de données open source et un serveur d'applications dans un seul paquet. En tant que base de données, elle présente un certain nombre de caractéristiques uniques: une efficacité élevée d'utilisation du fer, un schéma de données flexible, la prise en charge du stockage en mémoire et sur disque et la possibilité d'extension grâce à l'utilisation du langage Lua. En tant que serveur d'applications, il vous permet de déplacer le code d'application aussi près que possible des données, tout en obtenant un temps de réponse minimal et un débit maximal. De plus, Tarantool dispose d' un écosystème étendu , fournissant des modules prêts à l'emploi pour résoudre les problèmes d'application: partitionnement , file d'attente , modules pour faciliter le développement ( cartouche , luatest ), solutions de fonctionnement ( métriques , ansible ) - ce ne sont que quelques exemples.

Pour tous ses avantages, les capacités d'une seule instance de Tarantool ne sont pas illimitées: pour stocker des téraoctets de données et traiter des millions de demandes, vous devez générer des dizaines et des centaines d'instances, et c'est un système distribué, avec tous ses problèmes inhérents. Pour les résoudre, nous avons Tarantool Cartridge , un framework dont la tâche principale est de cacher toutes sortes de difficultés dans l'écriture d'applications distribuées et de permettre aux développeurs de se concentrer sur la valeur commerciale de l'application. La cartouche fournit un ensemble puissant de composants pour l'orchestration automatique des clusters, la distribution automatique des données, les outils Web de fonctionnement et de développement.

Tarantool n'est pas seulement une technologie, mais aussi une équipe d'ingénieurs qui sont engagés dans le développement de systèmes d'entreprise clé en main, de solutions de boîtiers et de support pour les composants open source.

Globalement, nos tâches peuvent être divisées en deux domaines: le développement de nouveaux systèmes et l'augmentation des solutions existantes. Par exemple, il existe une grande base d'un fournisseur célèbre. Pour le mettre à l'échelle pour la lecture, ils ont mis un cache finalement cohérent sur Tarantool derrière lui. Ou vice versa: afin de mettre à l'échelle l'enregistrement, ils placent Tarantool dans la configuration chaud / froid, où au fur et à mesure qu'ils «refroidissent», les données sont transférées vers le stockage froid et en parallèle dans la file d'attente d'analyse. Ou pour sauvegarder un système existant, une version allégée de ce système (réserve fonctionnelle) est écrite, qui réserve le principal «à chaud» avec la réplication des données du système principal. Plus d'informations peuvent être trouvées dans les rapports de T + 2019 .

Tous ces systèmes ont une chose en commun: ils sont assez difficiles à utiliser. Déployez rapidement un cluster de plus de 100 instances avec redondance dans 3 centres de données, mettez à jour l'application qui stocke les données sans interruption de service et sans maintenance, effectuez une restauration de sauvegarde en cas de catastrophe ou d'erreurs d'origine humaine, assurez le basculement discret des composants, organisez la gestion de la configuration ... En général, une tonne intéressant.

Et ce serait formidable que tout cela soit toujours aussi simple à développer. Kubernetes permet d'atteindre le résultat souhaité, mais l'utilisation d'un opérateur spécialisé rend la vie encore plus facile.

Au lieu de mille mots


Nous avons préparé un petit exemple basé sur la cartouche Tarantool, et nous travaillerons avec. Une application simple comme «stockage de valeur de clé distribué avec interface HTTP». Après le lancement, nous obtenons cette image:



OĂą:

  • Routeurs - la partie du cluster qui est responsable de l'acceptation et du traitement des requĂŞtes HTTP entrantes;
  • Le stockage est la partie du cluster qui est responsable du stockage et du traitement des donnĂ©es, 3 Ă©clats sortent de la boĂ®te, dans chaque maĂ®tre et rĂ©plique.

Pour équilibrer le trafic HTTP entrant sur les routeurs, l'entrée Kubernetian est utilisée. Les données sont distribuées en stockage au niveau de Tarantool lui-même à l' aide du composant vshard .

Nous avons besoin de kubernetes 1.14+, minikube fonctionnera . De plus, la disponibilité de kubectl ne fera pas de mal. Pour démarrer l'opérateur, vous devez créer un ServiceAccount, Role et RoleBinding pour celui-ci:

$ kubectl create -f https://raw.githubusercontent.com/tarantool/tarantool-operator/0.0.1/deploy/service_account.yaml $ kubectl create -f https://raw.githubusercontent.com/tarantool/tarantool-operator/0.0.1/deploy/role.yaml $ kubectl create -f https://raw.githubusercontent.com/tarantool/tarantool-operator/0.0.1/deploy/role_binding.yaml 

Tarantool Operator étend l'API Kubernetes avec ses définitions de ressources, nous allons les créer:

 $ kubectl create -f https://raw.githubusercontent.com/tarantool/tarantool-operator/0.0.1/deploy/crds/tarantool_v1alpha1_cluster_crd.yaml $ kubectl create -f https://raw.githubusercontent.com/tarantool/tarantool-operator/0.0.1/deploy/crds/tarantool_v1alpha1_role_crd.yaml $ kubectl create -f https://raw.githubusercontent.com/tarantool/tarantool-operator/0.0.1/deploy/crds/tarantool_v1alpha1_replicasettemplate_crd.yaml 

Tout est prêt pour lancer l'opérateur, c'est parti:

 $ kubectl create -f https://raw.githubusercontent.com/tarantool/tarantool-operator/0.0.1/deploy/operator.yaml 

Nous attendons le démarrage de l'opérateur, et nous pouvons procéder au lancement de l'application:

 $ kubectl create -f https://raw.githubusercontent.com/tarantool/tarantool-operator/0.0.1/examples/kv/deployment.yaml 

Dans le fichier yaml avec l'exemple, Ingress est déclaré sur l'interface utilisateur Web; il est disponible sur cluster_ip/admin/cluster . Lorsqu'au moins un pod d'Ingress est en place, vous pouvez vous y rendre et voir comment de nouvelles instances sont ajoutées au cluster et comment sa topologie change.

Nous attendons que le cluster soit utilisé:

 $ kubectl describe clusters.tarantool.io examples-kv-cluster 

Nous prévoyons que dans l'état du cluster, il y aura les éléments suivants:

 … Status: State: Ready … 

Tout, l'application est prĂŞte Ă  l'emploi!

Besoin de plus d'espace de stockage? Ajouter des fragments:

 $ kubectl scale roles.tarantool.io storage --replicas=3 

Les éclats ne peuvent pas faire face à la charge? Augmentez le nombre d'instances dans le fragment en modifiant le modèle de jeu de réplicas:

 $ kubectl edit replicasettemplates.tarantool.io storage-template 

Définissez .spec.replicas , par exemple 2, pour augmenter le nombre d'instances dans chaque jeu de réplicas à deux.

Un cluster n'est plus nécessaire? Nous le supprimons avec toutes les ressources:

 $ kubectl delete clusters.tarantool.io examples-kv-cluster 

Quelque chose a mal tourné? Marquez le ticket , nous allons rapidement le démonter. :)

Que fait l'opérateur du tout


Le lancement et le fonctionnement du cluster Tarantool Cartridge est l'histoire de l'exécution de certaines actions, dans un ordre spécifique, à un certain moment.

Le cluster lui-même est géré principalement via l'API d'administration: GraphQL sur HTTP. Vous pouvez bien sûr descendre à un niveau inférieur et exécuter des commandes directement dans la console, mais cela se produit rarement. Par exemple, voici comment le cluster démarre:

  1. Nous augmentons le nombre requis d'instances de Tarantool, par exemple, sous systemd.
  2. Fusionner des instances en appartenance:

     mutation { probe_instance: probe_server(uri: "storage:3301") } 

  3. Attribuez des rôles aux instances, prescrivez des identificateurs d'instance et de jeu de réplicas. L'API GraphQL est également utilisée pour cela:

     mutation { join_server( uri:"storage:3301", instance_uuid: "cccccccc-cccc-4000-b000-000000000001", replicaset_uuid: "cccccccc-0000-4000-b000-000000000000", roles: ["storage"], timeout: 5 ) } 

  4. Nous effectuons le bootstrap du composant responsable du sharding. Aussi via l'API:

     mutation { bootstrap_vshard cluster { failover(enabled:true) } } 


Facile, non?

Tout devient plus intéressant lorsqu'il s'agit d'étendre un cluster. Le rôle des routeurs de l'exemple varie simplement: augmentez le nombre d'instances, connectez-les à un cluster existant - vous avez terminé! Le rôle des stockages est quelque peu plus délicat. Le stockage est fragmenté, donc lors de l'ajout / suppression d'instances, il est nécessaire de rééquilibrer les données pour les déplacer vers de nouvelles instances / pour passer des instances supprimées. Si cela n'est pas fait, dans un cas, nous obtenons des instances sous-chargées, dans le second - nous perdons des données. Et si ce n'est pas un, mais une douzaine de tels clusters avec des topologies différentes sont en fonctionnement?

En général, Tarantool Operator est occupé par tout cela. L'utilisateur décrit l'état souhaité du cluster de cartouches Tarantool, et l'opérateur le traduit en un ensemble d'actions sur les ressources k8s et en certains appels à l'API d'administration du cluster Tarantool dans un ordre spécifique, à un certain moment, et essaie généralement de cacher toutes les nuances à l'utilisateur.

Un peu sur les nuances


Lorsque vous travaillez avec l'API du cluster d'administration Tarantool Cartridge, Ă  la fois l'ordre des appels et leur provenance est important. Pourquoi

Tarantool Cartridge transporte son référentiel de topologie, son composant de découverte de service et son composant de configuration. Chaque instance du cluster stocke une copie de la topologie et de la configuration dans un fichier yaml.

 servers: d8a9ce19-a880-5757-9ae0-6a0959525842: uri: storage-2-0.examples-kv-cluster:3301 replicaset_uuid: 8cf044f2-cae0-519b-8d08-00a2f1173fcb 497762e2-02a1-583e-8f51-5610375ebae9: uri: storage-0-0.examples-kv-cluster:3301 replicaset_uuid: 05e42b64-fa81-59e6-beb2-95d84c22a435 … vshard: bucket_count: 30000 ... 

La mise à jour se produit de concert à l'aide du mécanisme de validation en deux phases . Une mise à niveau réussie nécessite un quorum de 100%: chaque instance doit répondre, sinon annulation. Qu'est-ce que cela signifie en termes de fonctionnement? Toutes les demandes adressées à l'API d'administration modifiant l'état du cluster sont les plus fiables à envoyer à une instance, au leader, sinon nous courons le risque d'obtenir différentes configurations sur différentes instances. Tarantool Cartridge ne sait pas comment faire une élection de leader (mais ne sait pas comment), mais Tarantool Operator peut - et vous ne pouvez le savoir que comme un fait amusant, car l'opérateur va tout gâcher.

De plus, chaque instance doit avoir une identité fixe, c'est-à-dire un ensemble d' instance_uuid et replicaset_uuid , ainsi que advertise_uri . Si le stockage redémarre soudainement et que l'un de ces paramètres change, vous courez le risque de casser le quorum - l'opérateur le fait également.

Comment fonctionne l'opérateur


La tâche de l'opérateur est d'amener le système dans l'état défini par l'utilisateur et de maintenir le système dans cet état jusqu'à ce que de nouvelles directions soient reçues. Pour que l'opérateur puisse effectuer son travail, il a besoin:

  1. Description de l'état du système.
  2. Le code qui amène le système à cet état.
  3. Un mécanisme pour intégrer ce code dans les k8 (par exemple, pour recevoir des notifications de changements d'état).

Le cluster de cartouches Tarantool est décrit en termes de k8 à travers une définition de ressource personnalisée (CRD) ; l'opérateur a besoin de 3 ressources personnalisées de ce type, réunies sous le groupe tarantool.io/v1alpha:

  • Le cluster est une ressource de niveau supĂ©rieur qui correspond Ă  un cluster de cartouches Tarantool.
  • RĂ´le - en termes de cartouche Tarantool, il s'agit d'un rĂ´le utilisateur .
  • ReplicasetTemplate - un modèle par lequel des StatefulSets seront créés (pourquoi stateful - je vous le dirai un peu plus tard; Ă  ne pas confondre avec k8s ReplicaSet).

Toutes ces ressources reflètent directement le modèle de description du cluster de cartouches Tarantool. Ayant un dictionnaire commun, il est plus facile pour un opérateur de communiquer avec les développeurs et de comprendre ce qu'ils veulent voir dans le prod.

Le code qui amène le système à l'état donné - en termes de k8, c'est Controller. Dans le cas de l'opérateur Tarantool, il existe plusieurs contrôleurs:

  • ClusterController - est responsable de l'interaction avec le cluster Tarantool Cartridge, connecte les instances au cluster, dĂ©connecte les instances du cluster.
  • RoleController est un contrĂ´leur de rĂ´le utilisateur, il est responsable du dĂ©ploiement des StatefulSets Ă  partir d'un modèle et du maintien de leur numĂ©ro dans un numĂ©ro donnĂ©.

À quoi ressemble un contrôleur? Un ensemble de code qui ramène progressivement le monde autour de vous. ClusterController peut être schématiquement représenté comme ceci:



Un point d'entrée est une vérification pour voir si une ressource de cluster existe par rapport à laquelle l'événement s'est produit. N'existe pas? Nous partons. Y a-t-il? Nous passons au bloc suivant: saisir la propriété sur les rôles d'utilisateur. Capturé un - à gauche, sur le deuxième cercle, nous capturons le second. Et ainsi de suite, jusqu'à ce que nous capturions tout. Tous les rôles sont-ils capturés? Passez donc au bloc d'opérations suivant. Et ainsi, jusqu'à ce que nous arrivions au dernier; on peut alors supposer que le système contrôlé est dans un état donné.

En général, tout est simple. Il est important de déterminer les critères de réussite pour réussir chaque étape. Par exemple, nous considérons comme réussie l'opération de rejoindre un cluster non pas quand il a renvoyé conditionnel success = true, mais quand il a renvoyé une erreur comme "déjà joint".

Et la dernière partie de ce mécanisme est l'intégration du contrôleur avec les k8. Vue aérienne, l'ensemble des k8 se compose d'un ensemble de contrôleurs qui génèrent des événements et y répondent. Les événements passent par des files d'attente auxquelles nous pouvons nous abonner. Schématiquement, cela peut être représenté comme suit:



L'utilisateur appelle kubectl create -f tarantool_cluster.yaml , la ressource de cluster correspondante est créée. ClusterController est informé de la création d'une ressource de cluster. Et la première chose qu'il essaie de faire est de trouver toutes les ressources de rôle qui devraient faire partie de ce cluster. S'il le trouve, affecte alors le cluster comme propriétaire du rôle et met à jour la ressource de rôle. Le RoleController reçoit une notification de mise à jour de rôle, voit que la ressource a un propriétaire et commence à créer des StatefulSets. Et ainsi de suite en cercle: le premier strigger du second, le second strigger du troisième - et ainsi de suite jusqu'à ce que quelqu'un s'arrête. Et vous pouvez également déclencher à temps, par exemple, toutes les 5 secondes, ce qui est parfois utile.

C'est tout l'opérateur: créer une ressource personnalisée et écrire du code qui répond aux événements sur les ressources.

Ce que l'opérateur étend


Les actions des opérateurs conduisent finalement les k8 à créer des pods et des conteneurs. Dans le cluster Tarantool Cartridge déployé sur les k8, tous les pods sont fusionnés en StatefulSets.

Pourquoi StatefulSet? Comme je l'ai écrit plus tôt, chaque instance de Tarantool Cluster conserve une copie de la topologie et de la configuration du cluster, et souvent sur le serveur d'applications, non, non, et ils utilisent une sorte d'espace, par exemple, à leur tour ou des données de référence, et c'est déjà un état complet . Et StatefulSet garantit également la préservation des pods d'identité, ce qui est important lors du clustering d'instances dans un cluster: l'identité des instances doit être corrigée, sinon nous risquons de perdre le quorum lors du redémarrage.

Lorsque toutes les ressources de cluster sont créées et portées à l'état souhaité, elles forment la hiérarchie suivante:



Les flèches indiquent la relation propriétaire-dépendante entre les ressources. Il est nécessaire que le Garbage Collector nettoie après nous dans le cas, par exemple, de la suppression de Cluster.

En plus des StatefulSets, l'opérateur Tarantool crée le service sans tête, qui est nécessaire pour l'élection du chef, et à travers lui, les instances communiquent entre elles.

Sous le capot de l'opérateur Tarantool se trouve le cadre opérateur , le code opérateur lui-même est en golang, rien d'extraordinaire ici.

Résumé


C’est tout, en général! Nous attendons vos commentaires et billets - où sans eux, la version alpha est tout de même. Et ensuite? Et puis, il y a beaucoup de travail à faire pour que tout cela soit présent:

  • UnitĂ©, test E2E;
  • Test du Chaos Monkey
  • tests de rĂ©sistance;
  • sauvegarde / restauration;
  • fournisseur de topologie externe.

Chacun de ces sujets est vaste en soi et mérite un matériel séparé, attendez les mises à jour!

Source: https://habr.com/ru/post/fr465823/


All Articles