22
ao

k8s + Galera : gestion de la persistance des données dans Kubernetes

 

Par Jacques Roussel, Consultant Cloud @Objectif Libre

 

Kubernetes (k8s) est devenu un incontournable dans l’orchestration de conteneurs. Beaucoup aimeraient conteneuriser tout leur SI ; peu se risquent cependant à y mettre des bases de données critiques à cause de la nature-même d’un conteneur.

Comment gérer la persistance des données dans un environnement hautement éphémère ?

 

Cet article présente dans le détail les statefulsets qui sont la réponse qu’apporte k8s à cette question.

 

Les objectifs derrière un portage de base de données dans un cluster k8s sont multiples :

  • Profiter de la simplicité des déploiements qu’apporte k8s
  • Profiter de la scalabilité offerte par k8s
  • Unifier la manière de gérer l’ensemble des technologies qui forment une application

 

Dans cet article / tutoriel, nous montrons une manière de déployer un cluster Galera dans k8s en utilisant les statefulsets, prévus pour déployer des applications stateful dans k8s. Pour rappel, Galera est la solution permettant de faire un cluster MySQL multi-masters.

 

La plus-value apportée ici par rapport à la documentation déjà publiée sur Internet :

  • Utilisation de percona (et de la suite associée)
  • Déploiement d’un galera multi-master

 

Nota bene :

  • Nous simplifions volontairement certaines choses afin de rester le plus pédagogique possible. Aussi les exemples fournis ne sont pas prévus pour être utilisés tels quels dans des environnements critiques
  • Nous supposons aussi une connaissance minimale de k8s : les objets comme les pods / namespaces ne seront pas expliqués dans les détails
  • Tous les fichiers présentés sont disponibles sur le GitHub d’Objectif Libre

 

La procédure décrite ci-dessous a été validée sur une distribution Ubuntu 16.04.

 

Définition

Un statefulset apporte :

  • Un identifiant réseau unique
  • Un espace de stockage persistant
  • Un ordre de déploiement et de scaling des pods défini
  • Un ordre de suppression des pods défini
  • Un mécanisme de rolling update

Préparation de l’environnement

Pour nos tests, nous utiliserons minikube (environnement de test k8s).

curl -Lo kubectl https://storage.googleapis.com/kubernetes-release/release/v1.6.1/bin/linux/amd64/kubectl && chmod +x kubectl && sudo mv kubectl /usr/local/bin
sudo apt-get update && sudo apt-get install -y virtualbox
curl -Lo minikube https://storage.googleapis.com/minikube/releases/v0.21.0/minikube-linux-amd64 && chmod +x minikube && sudo mv minikube /usr/local/bin/
minikube start
kubectl get no

ou bien :

curl https://raw.githubusercontent.com/ObjectifLibre/k8s-galera-demo/master/install.sh | bash

À ce stade, nous avons un k8s prêt.

 

Déploiement de Galera

Pour déployer galera, nous allons devoir créer plusieurs objets dans k8s.

Le namespace galera

On crée un namespace dédié :

kubectl create namespace galera
kubectl get namespace
kubectl config set-context $(kubectl config current-context) --namespace=galera # pour éviter des "-n galera" par la suite

ou simplement :

curl https://raw.githubusercontent.com/ObjectifLibre/k8s-galera-demo/master/create-namespace.sh |bash

Le headless service

apiVersion: v1
kind: Service
metadata:
  name: percona
  namespace: galera
  labels:
    app: percona
spec:
  ports:
  - name: percona
    port: 3306
  clusterIP: None
  selector:
    app: percona
$ kubectl create -f https://raw.githubusercontent.com/ObjectifLibre/k8s-galera-demo/master/svc.yaml

La création de ce service est un prérequis au statefulset. C’est le nom de ce service qu’il faudra renseigner par la suite dans la variable serviceName.

Le configMap percona

Rappel : les configmaps servent à stocker la configuration que l’on souhaite fournir aux pods.

 

apiVersion: v1
kind: ConfigMap
metadata:
  name: percona
  namespace: galera
  labels:
    app: percona
data:
  client.cnf: |
              [client]
              port            = 3306
              socket          = /var/run/mysqld/mysqld.sock
  mysqld.cnf: |
              # Template my.cnf for PXC
              # Edit to your requirements.
              [mysqld]
              bind-address = 0.0.0.0
              skip-host-cache
              skip-name-resolve
              server-id=1
              datadir=/var/lib/mysql
              socket=/var/run/mysqld/mysqld.sock
              #log-error=/var/log/mysqld.log
              pid-file=/var/run/mysqld/mysqld.pid
              #log-bin
              #log_slave_updates
              expire_logs_days=7

              # Disabling symbolic-links is recommended to prevent assorted security risks
              symbolic-links=0
              innodb_locks_unsafe_for_binlog = 1
              innodb_autoinc_lock_mode = 2
              default_storage_engine = InnoDB
              innodb_file_per_table
              max_connections = 300
  mysqld_safe.cnf: |
                   #
                   # The Percona XtraDB Cluster 5.7 configuration file.
                   #
                   # One can use all long options that the program supports.
                   # Run program with --help to get a list of available options and with
                   # --print-defaults to see which it would actually understand and use.
                   #
                   # For explanations see
                   # http://dev.mysql.com/doc/mysql/en/server-system-variables.html

                   [mysqld_safe]
                   pid-file = /var/run/mysqld/mysqld.pid
                   socket   = /var/run/mysqld/mysqld.sock
                   nice     = 0
  wsrep.cnf: |
             [mysqld]
             # Path to Galera library
             wsrep_provider=/usr/lib/galera3/libgalera_smm.so

             # Cluster connection URL contains IPs of nodes
             #If no IP is found, this implies that a new cluster needs to be created,
             #in order to do that you need to bootstrap this node
             wsrep_cluster_address = gcomm://percona-0.percona,percona-1.percona,percona-2.percona

             # In order for Galera to work correctly binlog format should be ROW
             binlog_format=ROW

             # MyISAM storage engine has only experimental support
             default_storage_engine=InnoDB

             # Slave thread to use
             wsrep_slave_threads= 8

             wsrep_log_conflicts

             # This changes how InnoDB autoincrement locks are managed and is a requirement for Galera
             innodb_autoinc_lock_mode=2

             # Node IP address
             #wsrep_node_address=192.168.70.63
             # Cluster name
             wsrep_cluster_name=PERCONA-CLUSTER

             #If wsrep_node_name is not specified,  then system hostname will be used
             #wsrep_node_name=pxc-cluster-node-1

             #pxc_strict_mode allowed values: DISABLED,PERMISSIVE,ENFORCING,MASTER
             pxc_strict_mode=ENFORCING

             # SST method
             wsrep_sst_method=xtrabackup-v2

             #Authentication for SST method
             wsrep_sst_auth="root:"
             wsrep_retry_autocommit = 4
kubectl create -f  https://raw.githubusercontent.com/ObjectifLibre/k8s-galera-demo/master/configmap.yaml
kubectl get configmap

 

Nous venons de créer 4 fichiers de configuration :

  1. client.cnf qui contient les informations de configuration du client mysql
  2. mysqld.cnf qui contient la configuration de mysqld
  3. mysqld_safe.cnf qui contient la configuration pour mysqld_safe
  4. wsrep.cnf qui contient la configuration pour la replication galera

 

Pour cette démonstration, peu de modifications ont été apportées aux fichiers de base. Deux changements sont à retenir :

  1. wsrep_cluster_address qui est fixé à gcomm://percona-0.percona,percona-1.percona,percona-2.percona.
  2. wsrep_sst_auth qui est mis à root et sans mot de passe pour éviter d’avoir à gérer la création d’un utilisateur spécifique.

 

Pour la variable wsrep_cluster_address on s’appuie sur l’ordre de démarrage des pods défini dans les statefulsets. En effet, le nom des pods d’un statefulset est connu à l’avance et leur ordre d’apparition aussi. Dans notre cas, le premier pod sera percona-0 puis percona-1 et ainsi de suite.

Le statefulset

Entrons à présent dans le vif du sujet avec le statefulset.

 

apiVersion: apps/v1beta1
kind: StatefulSet
metadata:
  name: percona
  namespace: galera
spec:
  serviceName: "percona"
  replicas: 3
  template:
    metadata:
      labels:
        app: percona
    spec:
      terminationGracePeriodSeconds: 10
      containers:
      - name: percona
        image: objectiflibre/percona-galera:5.7
        imagePullPolicy: Always
        args: ['--ignore-db-dir=lost+found']
        env:
        - name: MYSQL_ALLOW_EMPTY_PASSWORD
          value: "1"
        ports:
        - containerPort: 3306
          name: mysql
        volumeMounts:
        - name: percona
          mountPath: /var/lib/mysql
        - name: percona-conf
          mountPath: /etc/mysql/percona-xtradb-cluster.conf.d/
        readinessProbe:
          exec:
            command: ["mysql", "-h", "127.0.0.1", "-e", "SELECT 1"]
          initialDelaySeconds: 5
          timeoutSeconds: 1
      - name: xtrabackup
        image: objectiflibre/percona-galera:5.7
        imagePullPolicy: Always
        ports:
        - containerPort: 3307
          name: mysql
        volumeMounts:
        - name: percona
          mountPath: /var/lib/mysql
        - name: percona-conf
          mountPath: /etc/mysql/percona-xtradb-cluster.conf.d/
        command:
          - "/bin/bash"
          - "-c"
          - |
            echo "Waiting for mysqld to be ready (accepting connections)"
            until mysql -h 127.0.0.1 -e "SELECT 1"; do sleep 10; done
            exec nc -l -p 3307 -c 'xtrabackup --backup --galera-info --stream=xbstream --host=127.0.0.1 --user=root'
      initContainers:
      - name: percona-init
        image: objectiflibre/percona-galera:5.7
        imagePullPolicy: Always
        command:
          - "/bin/bash"
          - "-c"
          - |
            [[ `hostname` =~ -([0-9]+)$ ]] || exit 1
            ordinal=${BASH_REMATCH[1]}
            echo [mysqld] > /etc/mysql/percona-xtradb-cluster.conf.d/server-id.cnf
            echo server-id=$((100 + $ordinal)) >> /etc/mysql/percona-xtradb-cluster.conf.d/server-id.cnf
            echo wsrep_node_address=`hostname --ip-address` >> /etc/mysql/percona-xtradb-cluster.conf.d/server-id.cnf
            cp /tmp/config/* /etc/mysql/percona-xtradb-cluster.conf.d/
            [[ -d /var/lib/mysql/mysql ]] && exit 0
            [[ `hostname` =~ -([0-9]+)$ ]] || exit 1
            ordinal=${BASH_REMATCH[1]}
            [[ $ordinal -eq 0 ]] && sed -i 's#wsrep_cluster_address = gcomm.*#wsrep_cluster_address = gcomm://#g' /etc/mysql/percona-xtradb-cluster.conf.d/wsrep.cnf
            [[ $ordinal -eq 0 ]] && exit 0
            #while ! timeout 1 bash -c 'cat < /dev/null > /dev/tcp/percona-'$(($ordinal-1))'/3306'; do sleep 20; done
            nc percona-$(($ordinal-1)).percona 3307 | xbstream -x -C /var/lib/mysql
            xtrabackup --prepare --target-dir=/var/lib/mysql
            cat <<EOF > /var/lib/mysql/grastate.dat
            version: 2.1
            uuid: $(cut -d: -f1 /var/lib/mysql/xtrabackup_galera_info)
            seqno: $(cut -d: -f2 /var/lib/mysql/xtrabackup_galera_info)
            cert_index:
            EOF
            chown -R mysql: /var/lib/mysql
        volumeMounts:
        - name: percona-conf
          mountPath: /etc/mysql/percona-xtradb-cluster.conf.d/
        - name: percona
          mountPath: /var/lib/mysql
        - name: config-map
          mountPath: /tmp/config
      volumes:
      - name: percona-conf
        emptyDir: {}
      - name: config-map
        configMap:
          name: percona
  volumeClaimTemplates:
  - metadata:
      name: percona
      annotations:
        volume.beta.kubernetes.io/storage-class: standard
    spec:
      accessModes: [ "ReadWriteOnce" ]
      resources:
        requests:
          storage: 1Gi
kubectl create -f https://raw.githubusercontent.com/ObjectifLibre/k8s-galera-demo/master/statefulset.yaml

Pour bien comprendre la logique de ce fichier, rappelons d’abord comment on déploie un cluster galera et comment on ajoute des noeuds à ce cluster.

Bootstrap d’un galera

Lorsqu’on crée un cluster galera, il faut d’abord installer les paquets nécessaires sur l’ensemble des serveurs puis choisir le noeud qui démarre en mode bootstrap. Il faut ensuite démarrer un à un les autres nœuds qui, grâce à la variable wsrep_cluster_address , trouvent le nœud en mode bootstrap et/ou tous les nœuds qui forment déjà un cluster. Dans le cadre d’un bootstrap, étant donné qu’il n’y a pas de données, il n’est pas nécessaire de partir d’un dump. Cependant, lorsqu’on ajoute un nœud à un cluster qui possède beaucoup de données, il est souvent préférable de repartir d’un backup. Dans ce cas, il faut créer un backup, l’importer sur le nouveau noeud et démarrer le service MySQL. Le nœud récupère alors seulement le delta et rejoint le cluster.

En résumé, lorsqu’un nœud galera démarre :

  • s’il est le premier il faut le démarrer en mode bootstrap
  • sinon, il faut importer un backup et le démarrer en mode nominal

 

Commentaire détaillé du statefulset

Notre fichier statefulset.yaml se décompose en plusieurs parties que nous commentons ci-dessous :

apiVersion: apps/v1beta1
kind: StatefulSet
metadata:
  name: percona
  namespace: galera

Ici on définit le type d’objet, son nom et son namespace. Ce qui vient ensuite correspond à ce que déploiera concrètement notre statefulset.

spec:
  serviceName: "percona"
  replicas: 3

Le nombre de replicas est transparent. En revanche, il est important de comprendre serviceName qui permet de définir comment les pods pourront se résoudre entre eux. Il doit porter le même nom que le headless service créé précédemment. Sans entrer dans les détails, retenez que la règle est : ${nom-du-pod}.${serviceName}. On utilisera cette propriété des statefulsets par la suite dans les fichiers de configuration.

  template:
    metadata:
      labels:
        app: percona

Cette section template introduit la configuration et la logique de déploiement de nos pods.

Avant d’aller plus loin, remarquez que nous avons aux mêmes niveaux :

  volumeClaimTemplates:
  - metadata:
      name: percona
      annotations:
        volume.beta.kubernetes.io/storage-class: standard
    spec:
      accessModes: [ "ReadWriteOnce" ]
      resources:
        requests:
          storage: 1Gi

Ce bloc demande à k8s de créer un volume de 1G par pod. Pour cela, on doit préciser le storageClass utilisé. Étant donné que le volume est destiné à /var/lib/mysql, on configure l’accesMode à ReadWriteOnce. Il est possible de lister les storage-class disponibles avec la commande suivante :

kubectl get storageclass

Un storageClass est un objet k8s qui gère des volumes. Ils sont mis à disposition par les administrateurs du k8s.

Pour la suite du fichier, on remarque deux entrées de même niveau initContainers et containers. Nous les décrirons dans leur ordre de démarrage lorsqu’on déploie le statefulset.

Les PersistentVolumes et les PersistentVolumesClaim générés par un statefulset ne sont jamais supprimés automatiquement par k8s. Cela permet d’éviter la perte des données lors d’un crash majeur.

 

Les initcontainers

Les initContainers sont des conteneurs qui vont démarrer avant que les conteneurs utiles démarrent. Cela permet d’effectuer des actions de bootstrap avec l’avantage d’éviter d’avoir à écrire des dockerfiles qui embarquent la logique de déploiement. La tâche de construction des conteneurs est donc plus aisée.

      initContainers:
      - name: percona-init
        image: objectiflibre/percona-galera:5.7
        imagePullPolicy: Always
        command:
          - "/bin/bash"
          - "-c"
          - |
            [[ `hostname` =~ -([0-9]+)$ ]] || exit 1
            ordinal=${BASH_REMATCH[1]}
            echo [mysqld] > /etc/mysql/percona-xtradb-cluster.conf.d/server-id.cnf
            echo server-id=$((100 + $ordinal)) >> /etc/mysql/percona-xtradb-cluster.conf.d/server-id.cnf
            echo wsrep_node_address=`hostname --ip-address` >> /etc/mysql/percona-xtradb-cluster.conf.d/server-id.cnf
            cp /tmp/config/* /etc/mysql/percona-xtradb-cluster.conf.d/
            [[ -d /var/lib/mysql/mysql ]] && exit 0
            [[ `hostname` =~ -([0-9]+)$ ]] || exit 1
            ordinal=${BASH_REMATCH[1]}
            [[ $ordinal -eq 0 ]] && sed -i 's#wsrep_cluster_address = gcomm.*#wsrep_cluster_address = gcomm://#g' /etc/mysql/percona-xtradb-cluster.conf.d/wsrep.cnf
            [[ $ordinal -eq 0 ]] && exit 0
            #while ! timeout 1 bash -c 'cat < /dev/null > /dev/tcp/percona-'$(($ordinal-1))'/3306'; do sleep 20; done
            nc percona-$(($ordinal-1)).percona 3307 | xbstream -x -C /var/lib/mysql
            xtrabackup --prepare --target-dir=/var/lib/mysql
            cat <<EOF > /var/lib/mysql/grastate.dat
            version: 2.1
            uuid: $(cut -d: -f1 /var/lib/mysql/xtrabackup_galera_info)
            seqno: $(cut -d: -f2 /var/lib/mysql/xtrabackup_galera_info)
            cert_index:
            EOF
            chown -R mysql: /var/lib/mysql
        volumeMounts:
        - name: percona-conf
          mountPath: /etc/mysql/percona-xtradb-cluster.conf.d/
        - name: percona
          mountPath: /var/lib/mysql
        - name: config-map
          mountPath: /tmp/config
      volumes:
      - name: percona-conf
        emptyDir: {}
      - name: config-map
        configMap:
          name: percona

Ici, on note d’abord l’image utilisée objectiflibre/percona-galera:5.7. Pour le détail de l’image, le Dockerfile est consultable sur le GitHub d’Objectif Libre. C’est l’image officielle légèrement modifiée pour embarquer galera.

      volumes:
      - name: percona-conf
        emptyDir: {}
      - name: config-map
        configMap:
          name: percona

On remarque aussi l’utilisation de notre configmap comme volume. Le volume emptyDir a la particularité d’être un volume qui existe le temps qu’un pod existe. C’est utile lorsque l’on veut partager des fichiers entre différents conteneurs au sein d’un pod.

        volumeMounts:
        - name: percona-conf
          mountPath: /etc/mysql/percona-xtradb-cluster.conf.d/
        - name: percona
          mountPath: /var/lib/mysql
        - name: config-map
          mountPath: /tmp/config

On note qu’on monte le config-map dans /tmp/config. En fait, nous nous servons des fichiers du config-map comme templates.

        command:
          - "/bin/bash"
          - "-c"
          - |
            [[ `hostname` =~ -([0-9]+)$ ]] || exit 1
            ordinal=${BASH_REMATCH[1]}
            echo [mysqld] > /etc/mysql/percona-xtradb-cluster.conf.d/server-id.cnf
            echo server-id=$((100 + $ordinal)) >> /etc/mysql/percona-xtradb-cluster.conf.d/server-id.cnf
            echo wsrep_node_address=`hostname --ip-address` >> /etc/mysql/percona-xtradb-cluster.conf.d/server-id.cnf
            cp /tmp/config/* /etc/mysql/percona-xtradb-cluster.conf.d/
            [[ -d /var/lib/mysql/mysql ]] && exit 0
            [[ `hostname` =~ -([0-9]+)$ ]] || exit 1
            ordinal=${BASH_REMATCH[1]}
            [[ $ordinal -eq 0 ]] && sed -i 's#wsrep_cluster_address = gcomm.*#wsrep_cluster_address = gcomm://#g' /etc/mysql/percona-xtradb-cluster.conf.d/wsrep.cnf
            [[ $ordinal -eq 0 ]] && exit 0
            #while ! timeout 1 bash -c 'cat < /dev/null > /dev/tcp/percona-'$(($ordinal-1))'/3306'; do sleep 20; done
            nc percona-$(($ordinal-1)).percona 3307 | xbstream -x -C /var/lib/mysql
            xtrabackup --prepare --target-dir=/var/lib/mysql
            cat <<EOF > /var/lib/mysql/grastate.dat
            version: 2.1
            uuid: $(cut -d: -f1 /var/lib/mysql/xtrabackup_galera_info)
            seqno: $(cut -d: -f2 /var/lib/mysql/xtrabackup_galera_info)
            cert_index:
            EOF
            chown -R mysql: /var/lib/mysql

ATTENTION : le mot clé command peut porter à confusion : dans l’univers k8s, command correspond à l’instruction entrypoint des conteneurs tandis que args (non utilisé) correspond à l’instruction cmd.
Nous avons ici un simple script bash qui vérifie qu’on est bien dans un statefulset grâce au hostname qui est connu à l’avance. Il prépare ensuite la configuration du mysql. L’instruction [[ -d /var/lib/mysql/mysql ]] vérifie que /var/lib/mysql/mysql est présent. Si c’est le cas nous sommes en présence d’un mysql déjà initialisé et donc on ne fait rien. Sinon, soit on est le premier nœud du cluster et dans ce cas on modifie la variable  wsrep_cluster_address à gcomm:// pour signifier au mysql de démarrer en mode bootstrap, soit on n’est pas le premier nœud du cluster et on demande un backup au pod précédent avec l’instruction nc percona-$(($ordinal-1)).percona 3307 | xbstream -x -C /var/lib/mysql. Cette instruction est possible grâce au caractère prédictif des statefulsets.

 

Nous venons de voir la logique de bootstrap de nos pods. Voyons à présent ce qui se passe une fois que les initContainers sont terminés.

 

Les containers

      containers:
      - name: percona
        image: objectiflibre/percona-galera:5.7
        imagePullPolicy: Always
        args: ['--ignore-db-dir=lost+found']
        env:
        - name: MYSQL_ALLOW_EMPTY_PASSWORD
          value: "1"
        ports:
        - containerPort: 3306
          name: mysql
        volumeMounts:
        - name: percona
          mountPath: /var/lib/mysql
        - name: percona-conf
          mountPath: /etc/mysql/percona-xtradb-cluster.conf.d/
        readinessProbe:
          exec:
            command: ["mysql", "-h", "127.0.0.1", "-e", "SELECT 1"]
          initialDelaySeconds: 5
          timeoutSeconds: 1
      - name: xtrabackup
        image: objectiflibre/percona-galera:5.7
        imagePullPolicy: Always
        ports:
        - containerPort: 3307
          name: mysql
        volumeMounts:
        - name: percona
          mountPath: /var/lib/mysql
        - name: percona-conf
          mountPath: /etc/mysql/percona-xtradb-cluster.conf.d/
        command:
          - "/bin/bash"
          - "-c"
          - |
            echo "Waiting for mysqld to be ready (accepting connections)"
            until mysql -h 127.0.0.1 -e "SELECT 1"; do sleep 10; done
            exec nc -l -p 3307 -c 'xtrabackup --backup --galera-info --stream=xbstream --host=127.0.0.1 --user=root'

Le fonctionnement des volumes est le même que pour l’initContainers. Le seul point notable est l’utilisation de percona-conf que l’initContainer aura rempli. La partie la plus intéressante est l’utilisation de deux conteneurs percona et xtrabackup.

Le premier conteneur lance notre processus mysql.

        readinessProbe:
          exec:
            command: ["mysql", "-h", "127.0.0.1", "-e", "SELECT 1"]
          initialDelaySeconds: 5
          timeoutSeconds: 1

L’instruction readinessProbe permet à k8s de vérifier quand le mysql à l’intérieur du pod est complètement démarré et fonctionnel. Cela permet d’ordonner le déploiement. En effet, k8s ne démarrera pas de nouveau pod tant que le readinessProbe du pod précédent n’est pas bon. On s’assure ainsi que percona-1 ne démarrera qu’une fois que percona-0 sera totalement fonctionnel.

 

Le second conteneur est un peu spécial.

        command:
          - "/bin/bash"
          - "-c"
          - |
            echo "Waiting for mysqld to be ready (accepting connections)"
            until mysql -h 127.0.0.1 -e "SELECT 1"; do sleep 10; done
            exec nc -l -p 3307 -c 'xtrabackup --backup --galera-info --stream=xbstream --host=127.0.0.1 --user=root'

Il sert à envoyer un backup, sur demande, sur le port 3307. C’est lui qui fournira le backup à partir duquel le pod n+1 s’initialisera, grâce à l’instruction nc percona-$(($ordinal-1)).percona 3307 | xbstream -x -C /var/lib/mysql vue précédemment.

Vous pouvez vérifier la bonne initialisation du cluster comme suit :

kubectl exec -it percona-0 -c percona mysql
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 6675
Server version: 5.7.18-15-57 Percona XtraDB Cluster (GPL), Release rel15, Revision 7693d6e, WSREP version 29.20, wsrep_29.20

Copyright (c) 2009-2017 Percona LLC and/or its affiliates
Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> show status like "wsrep_cluster_size";
+--------------------+-------+
   | Variable_name      | Value |
   +--------------------+-------+
   | wsrep_cluster_size | 3     |
   +--------------------+-------+
1 row in set (0.01 sec)

La variable wsrep_cluster_size correspond au nombre de nœuds de votre cluster et doit être identique au nombre de replicas du replicaset.

Conclusion

Les statefulsets fournis par k8s permettent clairement d’adresser le problème des applications stateful.

Leur caractère prédictif, couplé au concept de pod et aux initContainers nous donne un framework puissant pour déployer ce type de cluster et la question du déploiement de ce type d’application semble ainsi résolue.

Toutefois, certaines questions demeurent : quid de l’administration au quotidien ? Est-ce viable pour de la production ? La gestion des bases de données à travers k8s est-elle réalisable simplement ?