Déployer un cluster Cassandra hautement disponible dans AWS à l’aide de Kubernetes.

Lors de la mission Chez G.E Aviation , nous utilisons Cassandra base de données NoSQL pour certaines de nos solutions cloud hautement disponibles. Cassandra est une base de données NoSQL évolutive hautement disponible, hautement performante et véritablement horizontale. Cependant, le déploiement de Cassandra dans le cloud de manière hautement disponible est une tâche non triviale et nécessite une configuration appropriée. Heureusement, en raison de l’émergence de nouvelles technologies, le déploiement d’un cluster Cassandra dans AWS est plus facile de nos jours.

Cet article vous montrera comment déployer un cluster Cassandra dans AWS, à l’aide de kops (Kubernetes Operations). Il montrera également que la configuration est hautement disponible en testant certains scénarios de défaillance.

Cet article suppose des connaissances de base d’AWS, Kubernetes et Apache Cassandra.

Déploiement

L’image ci-dessous montre à quoi ressemble le déploiement final de Cassandra dans AWS :

Décrivons le déploiement en détail :

  •       Le déploiement utilise une région géographique : Europe (Paris) eu-west-3
  •       Dans cette région, trois zones de disponibilité sont utilisées. Une zone de disponibilité est une zone isolée dans une région, c’est-à-dire qu’une défaillance dans une zone de disponibilité n’a pas d’impact sur les opérations dans une autre zone de disponibilité. Par conséquent, la haute disponibilité est obtenue en répartissant le traitement et le stockage sur les zones de disponibilité.
  •       Il existe trois masters appelés maîtres Kubernetes, un dans chaque zone de disponibilité. Un maître Kubernete planifie les pods (conteneurs), c’est-à-dire qu’il détermine quel noeud Kubernetes exécute quel pod (conteneur). En ayant un maître dans chaque zone de disponibilité, les maîtres Kubernetes peuvent continuer à planifier des pods, même si une zone de disponibilité est en panne. Les machines principales sont déployées dans un groupe à mise à l’échelle automatique. Par conséquent, si une instance EC2 de ce groupe se termine, une nouvelle instance EC2 (et le maître Kubernetes) est démarrée automatiquement.
  •       Il existe six nœuds Kubernetes, deux dans chaque zone de disponibilité. Un nœud Kubernetes exécute vos modules d’application. Dans cette configuration, chaque nœud Kubernetes exécutera un module Cassandra. Si un pod échoue, un nouveau sera planifié par le maître Kubernetes. Les nœuds Kubernetes sont également déployés dans un groupe à mise à l’échelle automatique.
  •       Un état Kubernetes avec des volumes persistants est utilisé pour déployer Cassandra: chaque pod Cassandra a une identité connue (par exemple cassandra-0) et un volume connu (par exemple cassandra-storage-cassandra-0). L’identité du pod et l’identité du volume sont étroitement liées. Cela permet à un pod Cassandra de redémarrer sur un autre nœud et de transférer son état. Lorsqu’un pod Cassandra démarre, il attache le même volume EBS que précédemment et a donc le même état qu’auparavant. Les volumes EBS sont automatiquement créés au premier démarrage d’un pod Cassandra.

Voyons maintenant comment Cassandra doit être configuré pour répliquer les données dans plusieurs zones de disponibilité. Pour ce faire, définissez les propriétés suivantes :

  • ·     Snitch. Il détermine à quel datacenter et rack appartient un nœud. Cassandra utilise les termes « datacenter » et «rack» pour identifier la topologie du réseau. EC2Snitch est utilisé. Lorsqu’un nœud Cassandra démarre, EC2Snitch récupère les informations de région et de zone de disponibilité à partir du point de terminaison de métadonnées EC2 : le datacenter est défini sur la région et le rack est défini sur la zone de disponibilité.
  • ·     Facteur de réplication. Ceci détermine le nombre de copies de données. Un facteur de réplication de trois est utilisé, c’est-à-dire que trois copies sont stockées sur des nœuds différents.
  • ·     Stratégie de réplication Cette propriété détermine quels nœuds stockent les répliques. La NetworkTopologyStrategy est utilisée. Avec cette stratégie, une réplique est stockée dans chaque zone de disponibilité. Comment cela est fait précisément, est discuté ensuite.

Configuration étape par étape

Ensuite, nous allons installer le déploiement décrit à partir de zéro. Pour suivre ces étapes, vous n’avez besoin que d’un compte AWS et d’une machine Linux pour exécuter les commandes. Nous utilisons les versions suivantes pour les différents composants :

  •       MacOs Pro Catalina 10.15.2
  •       Kops 1.15.0
  •       Kubernetes 1.7.16
  •       Cassandra 3.11.5

NB : Vous pouvez utiliser la même démarche en utilisant le système linux comme ubuntu.

Si vous voulez installer ubuntu sur virtualbox ou vmware ou encore récupérer une image déjà prête, vous avez les ressources ci-dessous :

Installation de Ubuntu sur VirtualBox: https://dmnbigdata.com/fr/installation-de-ubuntu-18-04-3-lts-sur-oracle-virtualbox-pour-installer-apache-cassandra Installation de Ubuntu sur VMWare ou VMWare Fusion: https://dmnbigdata.com/fr/installation-de-ubuntu-18-04-3-lts-sur-vmware-fusion-et-conditions-prealables-pour-linstallation-de-cassandra

Image VMware : https://drive.google.com/open?id=1MZ1ilbZk-Sy7uNpSPSisrkswOiAiBUZd

Image VirtualBox : https://drive.google.com/open?id=1kaNJRYfwn2Xh4ktKr0mpl6zrjb9rsNx0

Configuration de Kubernetes

Premièrement, vous avez besoin de la commande kops, qui est utilisée pour configurer l’infrastructure dans AWS :

Commandes pour macOS :

· Téléchargez la version récente de kops avec la commande :

curl -LO https://github.com/kubernetes/kops/releases/download/$(curl -s https://api.github.com/repos/kubernetes/kops/releases/latest | grep tag_name | cut -d '"' -f 4)/kops-darwin-amd64

· Mettre les binaires de kops en mode exécutable.

chmod +x kops-darwin-amd64

· Déplacez les binaires de kops dans le répertoire /usr/local/bin/kops.

sudo mv kops-darwin-amd64 /usr/local/bin/kops

Linux:

· Téléchargez la version récente avec la commande :

curl -LO  https://github.com/kubernetes/kops/releases/download/1.15.0/kops-linux-amd64

· Mettre les binaires de kops en mode exécutable

sudo mv kops-linux-amd64 /usr/local/bin/kops && sudo chmod a+x /usr/local/bin/kops

Voir la version récente sur :

https://kubernetes.io/docs/setup/production-environment/tools/kops/

Vous avez besoin de la commande kubectl pour interagir avec le cluster Kubernetes dans AWS :

curl -LO https://storage.googleapis.com/kubernetes-release/release/v1.7.16/bin/linux/amd64/kubectl
chmod +x ./kubectl ;sudo mv kubectl /usr/local/bin/kubectl ;sudo chmod a+x /usr/local/bin/kubectl

Kops utilise la commande awscli pour interagir avec AWS. Sur Ubuntu, vous pouvez installer cet outil via :

apt-get install awscli

Commandes pour Linux :

curl "https://d1vvhvl2y92vvt.cloudfront.net/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip"
unzip awscliv2.zip
sudo  ./aws/install

Commandes pour macOS:

curl "https://d1vvhvl2y92vvt.cloudfront.net/awscli-exe-macos.zip" -o "awscliv2.zip"
unzip awscliv2.zip
sudo ./aws/install

D’autres moyens d’installer awscli peuvent être trouvés ici :

https://docs.aws.amazon.com/fr_fr/cli/latest/userguide/aws-cli.pdf

https://docs.aws.amazon.com/cli/latest/userguide/installing.html

https://docs.aws.amazon.com/cli/latest/userguide/install-cliv2-linux-mac.html

Vous devez maintenant vous assurer qu’il existe un utilisateur IAM que kops peut utiliser pour installer les composants requis dans AWS. L’utilisateur IAM a besoin d’un accès par programmation (c’est-à-dire utiliser une clé d’accès (access-key) et une clé d’accès secrète (secret-access-key) pour se connecter). En outre, l’utilisateur IAM requiert les autorisations suivantes :

AmazonEC2FullAccess

AmazonRoute53FullAccess

AmazonS3FullAccess

IAMFullAccess

AmazonVPCFullAccess

Voici comment créer cet utilisateur. Pour notre cas, nous allons l’appeler dmnbigdata

aws iam
aws iam

Cliquez sur Utilisateurs et ensuite sur Ajouter un utilisateur

Ensuite cliquez sur Suivant : Autorisations après avoir rempli les points 1 et 2 :

Cliquez sur groupe pour créer un groupe et lui attribué les autorisations notées ci-dessous :

Une fois le groupe crée avec les bonnes autorisations, cliquez sur Créer un groupe et vous aurez l’image ci-dessous :

Cliquez sur Suivant : Balises

Cliquez sur Suivant : Vérification

Cliquez sur Créer un utilisateur

Surtout ne pas oublier de cliquer sur Télécharger.csv et le sauvegarder dans un endroit sécurisé sinon, vous ne pouvez plus le régénérer.

Maintenant, configurons AWS2 (aws2 parce que j’ai installé la version 2 de aws-cli) :

aws2 configure

Entrez les informations d’identification de l’utilisateur IAM créées à l’étape précédente. Nous utilisons Europe (Paris) eu-west-3 comme région. Acceptez le format de sortie par défaut. Vous devez ensuite créer un bucket S3. Kops stocke la configuration du déploiement dans ce bucket

aws2  s3api create-bucket --bucket kops-cassandra-dmnbigdata --region eu-west-3 --create-bucket-configuration LocationConstraint=eu-west-3

Pour voir les buckets crées dans s3, lancez la commande ci-dessous :

$ aws2  s3api list-buckets

Générez maintenant une paire de clés publique / privée :

ssh-keygen -f kops-cassandra-dmnbigdata

Cette paire de clés est utilisée pour accéder aux machines EC2. La commande suivante crée la définition de cluster :

kops create cluster \
--cloud=aws \
--name=kops-cassandra-dmnbigdata.k8s.local \
--zones=eu-west-3a,eu-west-3b,eu-west-3c \
--master-size="t2.small" \
--master-zones=eu-west-3a,eu-west-3b,eu-west-3c \
--node-size="t2.small" \
--ssh-public-key="kops-cassandra-dmnbigdata.pub" \
--state=s3://kops-cassandra-dmnbigdata \
--node-count=6

Appliquez maintenant la définition de cluster, c’est-à-dire créez les ressources actuelles dans AWS :

kops update cluster --name=kops-cassandra-dmnbigdata.k8s.local --state=s3://kops-cassandra-dmnbigdata --yes

Après quelques minutes, nous aurons un cluster Kubernetes hautement disponible dans AWS. Kops configure automatiquement kubectl. Utilisez la commande suivante pour vérifier les nœuds principaux de Kubernetes (l’argument -L affiche les étiquettes (labels), tandis que l’argument -l filtre sur les étiquettes (labels)):

kubectl get no -L failure-domain.beta.kubernetes.io/zone -l kubernetes.io/role=master

La sortie suivante est visible :

NAME             STATUS   ROLES    AGE    VERSION   ZONE
ip-172-20-117-22 Ready   master 104s v1.15.7 eu-west-3c
ip-172-20-43-100 Ready   master 98s v1.15.7 eu-west-3a
ip-172-20-81-84  Ready   master 103s v1.15.7 eu-west-3b

En se connectant dans aws et en cliquant sur le Tableau de bord EC2, vous allez voir toutes les instances créées :

Comme on peut le voir, les trois maîtres Kubernetes résident chacun dans une zone de disponibilité distincte. Exécutez maintenant la même commande pour les nœuds Kubernetes :

$ kubectl get no -L failure-domain.beta.kubernetes.io/zone -l kubernetes.io/role=node

Comme on peut le voir dans la sortie, chaque zone de disponibilité a deux nœuds Kubernetes :

NAME             STATUS    ROLES   AGE     VERSION   ZONE
ip-172-20-100-27      Ready     node 9m23s v1.15.7 eu-west-3c
ip-172-20-108-191     Ready     node 9m23s v1.15.7 eu-west-3c
ip-172-20-51-2        Ready     node 9m22s v1.15.7 eu-west-3a
ip-172-20-59-252      Ready     node 9m23s v1.15.7 eu-west-3a
ip-172-20-71-148      Ready     node 9m20s v1.15.7 eu-west-3b
ip-172-20-73-128      Ready     node 6m2s v1.15.7 eu-west-3b

Vous pouvez détruire l’environnement à tout moment en exécutant la commande suivante :

$ kops delete cluster --name=kops-cassandra-dmnbigdata.k8s.local --state=s3://kops-cassandra-dmnbigdata --yes

Configuration et Installation de Cassandra

Nous allons voir la classe de storage appelée storage class pour Cassandra :

$ kubectl get sc
NAME              PROVISIONER              AGE
default           kubernetes.io/aws-ebs    4h37m
gp2 (default)     kubernetes.io/aws-ebs    4h37m

Déploiement de Cassandra StatefulSet sur AWS :

StatefulSet dans kubernates nécessite un service pour fournir une identité réseau aux pods qu’il crée. La commande suivante et la spécification vous aideront à créer un service pour votre installation Cassandra.

cat > px-cassandra-svc.yaml << EOF

apiVersion: v1
kind: Service
metadata:
  labels:
    app: cassandra
  name: cassandra
spec:
  clusterIP: None
  ports:
  - port: 9042
  selector:
    app: Cassandra

EOF

$ kubectl create -f px-cassandra-svc.yaml
 
$ service "cassandra" created

 

Maintenant, nous allons créer un cluster Cassandra avec statefulset en cours d’exécution basé sur les spécifications ci-dessous :

cat > px-cassandra-app.yaml << EOF

apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: cassandra
  labels:
    app: cassandra
spec:
  serviceName: cassandra
  replicas: 6
  selector:
    matchLabels:
      app: cassandra
  template:
    metadata:
      labels:
        app: cassandra
    spec:
      containers:
      - name: cassandra
        image: cassandra:3
        ports:
        - containerPort: 7000
          name: intra-node
        - containerPort: 7001
          name: tls-intra-node
        - containerPort: 7199
          name: jmx
        - containerPort: 9042
          name: cql
        resources:
          limits:
            cpu: "500m"
            memory: 1Gi
          requests:
            cpu: "500m"
            memory: 1Gi
        securityContext:
          capabilities:
            add:
              - IPC_LOCK
        lifecycle:
          preStop:
            exec:
              command: 
              - /bin/sh
              - -c
              - nodetool drain
        env:
          - name: MAX_HEAP_SIZE
            value: 512M
          - name: HEAP_NEWSIZE
            value: 100M
          - name: CASSANDRA_SEEDS
            value: "cassandra-0.cassandra.default.svc.cluster.local"
          - name: CASSANDRA_CLUSTER_NAME
            value: "Cassandra"
          - name: CASSANDRA_DC
            value: "DC1"
          - name: CASSANDRA_RACK
            value: "Rack1"
          - name: POD_IP
            valueFrom:
              fieldRef:
                fieldPath: status.podIP
        readinessProbe:
          exec:
            command:
            - /bin/bash
            - -c
            - /ready-probe.sh
          initialDelaySeconds: 15
          timeoutSeconds: 5
# Ces disques volumes montes sont persistants.        
        volumeMounts:
        - name: cassandra-data
          mountPath: /var/lib/cassandra
  # Ceux-ci en été convertis en volume par le contrôleur contrôleur
  # et montes aux chemins mentionnes ci-dessus.
  # Ne pas les utiliser en production mais plutôt choisir les disques ssd 
  volumeClaimTemplates:
  - metadata:
      name: cassandra-data
    spec:
      accessModes: [ "ReadWriteOnce" ]
      storageClassName: fast
      resources:
        requests:
          storage: 1Gi

# kind: StorageClass
# apiVersion: storage.k8s.io/v1
# metadata:
#  name: fast
# provisioner: k8s.io/minikube-hostpath
# parameters:
#  type: pd-ssd

EOF
$ kubectl apply -f px-cassandra-app.yaml
$ statefulset.apps "cassandra" created

Vérifiez que tous les pods sont en cours d’exécution avant de poursuivre :

$ kubectl     get   statefulset

NAME            READY         AGE
cassandra       6/6           63m
$ kubectl get pods

NAME        READY STATUS  RESTARTS  AGE
cassandra-0 1/1   Running 0         64m
cassandra-1 1/1   Running 0         63m
cassandra-2 1/1   Running 1         63m
cassandra-3 1/1   Running 1         62m
cassandra-4 1/1   Running 1         62m
cassandra-5 1/1   Running 2         61m

Vérifions également les volumes :

$ kubectl get pvc
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
cassandra-data-cassandra-0 Bound pvc-132ebdf7-3855-4492-9cdd-4a3ac9141e89 1Gi RWO gp2 24m
cassandra-data-cassandra-1 Bound pvc-73a14efd-f29b-4da6-b08a-6db462bd475a 1Gi RWO gp2 23m
cassandra-data-cassandra-2 Bound pvc-fdff8d71-e6ae-444f-abf0-230231696710 1Gi RWO gp2 22m
cassandra-data-cassandra-3 Bound pvc-2df3f2e5-4a5b-451c-93c0-89c04a5b8927 1Gi RWO gp2 18m
cassandra-data-cassandra-4 Bound pvc-7cbaa701-ee67-4f61-bc07-7cfc9d163227 1Gi RWO gp2 17m
cassandra-data-cassandra-5 Bound pvc-f21cbf71-394d-424d-8b5c-0afa87927474 1Gi RWO gp2 17m 

Obtenez les pods et la connaissance des hôtes sur lesquels ils sont programmés :

$ kubectl get pods -l app=cassandra -o json

Nous pouvons également utiliser l’outil nodetool de Cassandra pour vérifier l’état du cluster :

$ kubectl exec cassandra-0 -- nodetool status
Datacenter: DC1
===============
Status=Up/Down
|/ State=Normal/Leaving/Joining/Moving
-- Address          Load    Tokens   Owns (effective) Host ID Rack
UN 100.96.6.2 80.27 KiB 256 50.2% af410846-5bcc-4434-8bfe-51c851d71956  Rack1  
UN 100.96.8.2 91.85 KiB 256 52.6% 6c5f672a-56b6-45b5-826a-5b8fa31a7402 Rack1
UN 100.96.4.2 95.67 KiB 256 46.1% eb3a1c8c-c87b-4a5b-8955-c4d6a762b0de Rack1
UN 100.96.5.2 186.41 KiB 256 48.2% 4de4fe7e-880f-42b7-856e-76c40cd86102 Rack1
UN 100.96.7.3 186.67 KiB 256 48.7%  05e700a1-0343-45ad-b571-5c61be743e55 Rack1
UN 100.96.3.4 136.42 KiB 256 54.2%  1912d775-c8e7-4ca7-899d-3d38c48b2798 Rack1

Afin de se connecter au cluster Cassandra, nous utilisons la commande cqlsh qui est disponible sur chaque nœud :

$ kubectl exec -ti cassandra-0 cqlsh cassandra-0

Cela ouvre une invite de commande CQL et vous permet d’interagir avec le cluster à l’aide de CQL. La commande « cqlsh cassandra-0 » se connecte en fait au serveur répertorié dans le premier argument (cassandra-0). Donc, dans ce cas, il se connecte à lui-même.

Nous allons maintenant créer un keyspace, une table et 5 lignes. Définissez d’abord le niveau de cohérence :

CONSISTENCY QUORUM ;

Quorum signifie qu’une majorité des réplicas (2 dans notre cas) doivent être lues ou écrites pour que la commande de lecture ou d’écriture réussisse. Créez maintenant le keyspace:

CREATE KEYSPACE killrvideo WITH REPLICATION = {'class': 'NetworkTopologyStrategy', 'DC1': 3 };

Passer au keyspace de killrvideo:

USE killrvideo;

Créer une table videos:

CREATE TABLE videos 
(video_id timeuuid PRIMARY KEY,
added_date timestamp,title text) ;

 

Exécutez maintenant les commandes suivantes pour insérer 5 lignes.

INSERT INTO videos (video_id ,added_date ,title ) 
VALUES (1645ea59-14bd-11e5-a993-8138354b7e31,'2014-01-29',
'Cassandra History');
INSERT INTO videos (video_id ,added_date ,title ) 
VALUES (245e8024-14bd-11e5-9743-8238356b7e32,'2012-04-03',
' Cassandra & SSDs ');
INSERT INTO videos (video_id ,added_date ,title ) 
VALUES (3452f7de-14bd-11e5-855e-8738355b7e3a,'2013-03-17',
' Cassandra Intro ');
INSERT INTO videos (video_id ,added_date ,title ) 
VALUES (4845ed97-14bd-11e5-8a40-8338255b7e33,'2013-10-16',
' DataStax DevCenter ');
INSERT INTO videos (video_id ,added_date ,title ) 
VALUES (5645f8bd-14bd-11e5-af1a-8638355b8e3a,'2013-04-16',
' What is DataStax Enterprise?’);

Exécutez maintenant la commande suivante et assurez-vous que 5 lignes sont retournées :

SELECT * FROM videos;
cqlsh:killrvideo> SELECT * FROM videos;
video_id | added_date | title
--------------------------------------+-----------------------
245e8024-14bd-11e5-9743-8238356b7e32 | 2012-04-03 00:00:00.000000+0000 |  Cassandra & SSDs
3452f7de-14bd-11e5-855e-8738355b7e3a | 2013-03-17 00:00:00.000000+0000 | Cassandra Intro
5645f8bd-14bd-11e5-af1a-8638355b8e3a|2013-04-16 00:00:00.000000+0000|What is DataStax Enterprise?
1645ea59-14bd-11e5-a993-8138354b7e31 | 2014-01-29 00:00:00.000000+0000 | Cassandra History
4845ed97-14bd-11e5-8a40-8338255b7e33 | 2013-10-16 00:00:00.000000+0000 |  DataStax DevCenter
(5 rows)

Test de la haute disponibilité

Maintenant que nous avons un cluster Cassandra dans AWS avec des données à l’intérieur, nous pouvons tester la haute disponibilité. Notez que cette configuration n’est résiliente qu’aux défaillances dans une zone de disponibilité. Afin d’être résilient face à plusieurs défaillances simultanées de zone de disponibilité, il convient d’envisager d’utiliser un site de reprise après sinistre dans une autre région. Lors de l’exécution des scénarios d’échec dans les sections suivantes, la requête de sélection présentée plus haut doit toujours renvoyer 5 enregistrements, c’est-à-dire que Cassandra doit être en haute disponibilité (toutes les données doivent être disponibles) à tout moment.

Échec de l’instance EC2

Notez que nous ne testerons que la défaillance du nœud Kubernetes (pas la défaillance du maître Kubernetes). Terminons une instance EC2 via la console AWS. Nous ne devons pas terminer une instance EC2 exécutant le pod cassandra-0. Sinon, notre invite CQL se termine. Via les commandes suivantes :

$ kubectl get no -L failure-domain.beta.kubernetes.io/zone
NAME              STATUS ROLES  AGE   VERSION   ZONE
ip-172-20-107-251 Ready  master 36m   v1.15.7   eu-west-3c
ip-172-20-115-221 Ready  node   35m   v1.15.7   eu-west-3c
ip-172-20-38-248  Ready  node   35m   v1.15.7   eu-west-3a
ip-172-20-45-107  Ready  master 36m   v1.15.7   eu-west-3a
ip-172-20-79-12   Ready  node   35m   v1.15.7   eu-west-3b
ip-172-20-92-62   Ready  node   35m   v1.15.7   eu-west-3b
ip-172-20-93-178  Ready  master 36m   v1.15.7   eu-west-3b
ip-172-20-99-226  Ready  node   35m   v1.15.7   eu-west-3c
$ kubectl get po -o wide
NAME READY       STATUS RESTARTS AGE  IP NODE    NOMINATED NODE READINESS GATES
cassandra-0 1/1    Running  0   30m 100.96.6.2 ip-172-20-79-12
cassandra-1 1/1    Running  0   30m 100.96.8.2 ip-172-20-115-221
cassandra-2 1/1    Running  0   29m 100.96.4.2 ip-172-20-45-107
cassandra-3 1/1    Running  1   24m 100.96.3.4 ip-172-20-92-62
cassandra-4 1/1    Running  2   24m 100.96.7.3 ip-172-20-99-226
cassandra-5 1/1    Running  2   23m 100.96.5.2 ip-172-20-38-248

Nous pouvons construire le tableau suivant :

Cassandra-node                EC2 instance                Availability-zone —————————————————————————- cassandra-0                       ip-172-20-79-12                  eu-west-3b cassandra-1                        ip-172-20-115-221              eu-west-3c cassandra-2                       ip-172-20-45-107                eu-west-3a cassandra-3                       ip-172-20-92-62                  eu-west-3b cassandra-4                      ip-172-20-99-226                eu-west-3c cassandra-5                      ip-172-20-38-248                eu-west-3a

Pour ce test, nous terminerons l’instance ip-172-20-115-221 qui terminera cassandra-1. AWS tentera de lancer une nouvelle instance EC2 dans la zone de disponibilité avec le moins d’instances. Dans notre cas, le groupe de mise à l’échelle automatique appelé « nœuds » contient une instance pour la zone eu-west-3c, tandis qu’il en contient deux pour les autres zones. Par conséquent, la nouvelle instance est lancée dans eu-west-3c. Notez que c’est le meilleur effort ; si une zone de disponibilité entière est en panne pendant une période prolongée, une intervention manuelle est nécessaire pour récupérer. Cela sera discuté plus tard. Lors de la demande des pods, la sortie suivante est visible :

NAME          READY   STATUS    RESTARTS   AGE
cassandra-0   1/1     Running     0        118m
cassandra-1   1/1     Running     0        117m
cassandra-2   1/1     Running     1        116m
cassandra-3   1/1     Running     1        116m
cassandra-4   1/1     Running     1        115m
cassandra-5   1/1     Running     2        115m

Pendant le démarrage de l’instance EC2, l’état du pod est en attente. Comme prévu, la requête en lecture renvoie toujours 5 lignes. En effet, nous utilisons le niveau de consistance des lectures en quorum: nous avons besoin de deux des trois réplicas et puisque toutes les zones contiennent un réplica , la lecture réussit. Le pod cassandra-1 sera replanifié vers la nouvelle instance EC2. Les politiques suivantes s’appliquent lors de la reprogrammation :

Lorsqu’un nœud Kubernetes est démarré, il obtient automatiquement une étiquette avec des informations de zone de disponibilité. Lorsque Kubernetes planifie les pods d’un ensemble avec un état stateful, il essaie de les répartir sur les zones de disponibilité. Les volumes persistants (le volume EBS) d’un pod sont également situés dans une zone de disponibilité particulière. Lorsqu’un volume persistant est créé, il obtient également une étiquette contenant des informations sur la zone de disponibilité. Désormais, lorsqu’un pod est planifié et revendique un volume, Kubernetes s’assure que le pod est planifié sur un nœud dans la même zone de disponibilité que le volume. Dans notre cas, cassandra-1 doit être reprogrammé. Ce pod revendique (veut lier) le volume cassandra-stockage-cassandra-1. Étant donné que ce volume est situé dans la zone eu-west-3c, cassandra-1 sera programmé sur un nœud s’exécutant dans eu-west-3c.

Nous utilisons l’anti-pod-affinity pour nous assurer qu’un nœud Kubernetes exécute au maximum un pod Cassandra. Bien qu’il soit parfaitement viable de fonctionner sans cette stratégie, il présente deux avantages : Pendant le démarrage de la nouvelle instance EC2, le pod Cassandra n’est pas démarré sur les nœuds restants. Par conséquent, aucune replanification manuelle n’est requise par la suite (afin d’équilibrer les pods). Le deuxième avantage est que toutes les ressources du nœud sont disponibles pour le nœud Cassandra. Notez que la même chose peut être obtenue en utilisant d’autres moyens (par exemple en utilisant des quotas de ressources)

Échec de la zone de disponibilité

Afin de tester ce scénario, nous allons terminer les nœuds Cassandra fonctionnant dans la zone eu-west-3a: cassandra-2 (instance EC2 ip-172-20-45-107) cassandra-2 et cassandra-5 (instance EC2 ip-172-20-38-248) .La commande «get pods» n’affiche désormais que cinq nœuds, dont l’un est en attente:

$ kubectl get po -o wide
cassandra-0 1/1 Running 0 60m 100.96.6.2 ip-172-20-79-12 
cassandra-1 1/1 Running 0 60m 100.96.8.2 ip-172-20-115-221 
cassandra-2 0/1  Pending 0 43s 
cassandra-3 1/1 Running 1 55m 100.96.3.4 ip-172-20-92-62 
cassandra-4 1/1 Running 2 54m 100.96.7.3 ip-172-20-99-226

Étant donné que Cassandra réplique les données dans toutes les zones, toutes les données sont toujours disponibles. Cela peut être confirmé en exécutant la requête de lecture qui renvoie toujours 5 enregistrements.

Le processus de récupération pour ce scénario est fondamentalement le même que le scénario de défaillance d’une seule instance EC2 décrit dans le scénario précédent. Bien que très rare, une zone de disponibilité peut échouer de telle manière que les instances ne peuvent pas être redémarrées dans la zone défaillante, mais sont démarrées à la place dans une autre zone. Plus d’informations peuvent être trouvées ici:https://docs.aws.amazon.com/autoscaling/ec2/userguide/as-add-availability-zone.html

Le scénario précédent décrivait la façon dont les modules pods contenant des revendications de volume sont planifiés. Parce qu’il y aura une incompatibilité entre les nouvelles informations de zone d’instance EC2 et les informations de zone de volume, les pods ne peuvent pas replanifier. Une intervention manuelle est requise. Lorsque la zone de disponibilité défaillante est à nouveau active, arrêtez toutes les machines qui ne pouvaient auparavant pas démarrer dans la zone de disponibilité défaillante et toutes devraient se rétablir automatiquement.

Destruction de l’environnement :

Une fois que vous avez fini de travailler afin d’éviter les coûts financiers en exécutant la commande suivante :
$ kops delete cluster --name=kops-cassandra-dmnbigdata.k8s.local --state=s3://kops-cassandra-dmnbigdata --yes
A la fin de l’exécution de la commande, vous devez avoir le message ci-dessous si tout s’est bien terminé :
Deleted kubectl config for kops-cassandra-dmnbigdata.k8s.local
Deleted cluster: "kops-cassandra-dmnbigdata.k8s.local"
Au niveau du tableau de bord EC2, toutes les instances seront en Etat de l’instance terminated, comme ci-dessous : La dernière étape sera de supprimer le bucket crée dans s3, en utilisant la commande ci-dessous :
$ aws2 s3api delete-bucket --bucket kops-cassandra-dmnbigdata

Conclusion

Dans cet article, nous avons montré comment déployer un cluster Cassandra à haute disponibilité dans AWS. Nous avons également montré que le déploiement récupère automatiquement des défaillances de nœuds dans la même zone de disponibilité. Dans un prochain article, nous discuterons de la mise de l’évolutivité du cluster. Un autre sujet, non abordé ici, est la performance, qui pourrait également faire l’objet d’un futur article.

Laisser un commentaire

Fermer le menu
×
×

Panier