Comment nettoyer les anciennes tâches Kubernetes
Agence web » Actualités du digital » Que sont les StatefulSets Kubernetes ? Quand devriez-vous les utiliser ?

Que sont les StatefulSets Kubernetes ? Quand devriez-vous les utiliser ?

Les StatefulSets sont des objets Kubernetes utilisés pour déployer de manière cohérente des composants d’application avec état. Les pods créés dans le cadre d’un StatefulSet reçoivent des identifiants persistants qu’ils conservent même lorsqu’ils sont replanifiés.

Un StatefulSet peut déployer des applications qui doivent identifier de manière fiable des répliques spécifiques, déployer des mises à jour dans un ordre prédéfini ou accéder de manière stable à des volumes de stockage. Ils s’appliquent à de nombreux cas d’utilisation différents, mais sont le plus souvent utilisés pour les bases de données et d’autres types de stockage de données persistantes.

Dans cet article, vous apprendrez ce que sont les StatefulSets, comment ils fonctionnent et quand vous devez les utiliser. Nous couvrirons également leurs limites et les situations où d’autres objets Kubernetes constituent un meilleur choix.

Que sont les StatefulSets ?

Intégrer les pods à un StatefulSet indique à Kubernetes de les planifier et de les mettre à l’échelle de manière garantie. Chaque pod se voit attribuer une identité unique que tous les pods de remplacement conservent.

Le nom du pod est suffixé par un index ordinal qui définit son ordre lors des opérations de planification. Un StatefulSet appelé mysql contenant trois instances dupliquées créera les pods nommés suivants :

Les pods utilisent leurs noms comme nom d’hôte afin que les autres services qui doivent accéder de manière fiable au deuxième réplica du StatefulSet puissent se connecter à mysql-2. Même si le pod spécifique qui s’exécute mysql-2 est reprogrammée plus tard, son identité passera à son remplaçant.

Les StatefulSets imposent également que les pods soient supprimés dans l’ordre inverse de leur création. Si le StatefulSet est réduit à un réplica, mysql-3 est assuré de sortir en premier, suivi de mysql-2. Ce comportement ne s’applique pas lorsque l’ensemble du StatefulSet est supprimé et peut être désactivé en définissant un StatefulSet’s podManagementPolicy champ à Parallel.

Cas d’utilisation de StatefulSet

Les StatefulSets sont normalement utilisés pour exécuter des applications répliquées où les pods individuels ont des rôles différents. Par exemple, vous pourriez déployer une base de données MySQL avec une instance principale et deux répliques en lecture seule. Un ReplicaSet ou un déploiement régulier ne serait pas approprié car vous ne pourriez pas identifier de manière fiable le pod exécutant le réplica principal.

Les StatefulSets résolvent ce problème en garantissant que chaque pod du ReplicaSet conserve son identité. Vos autres services peuvent se connecter de manière fiable à mysql-1 pour interagir avec le réplica principal. Les ReplicaSets imposent également que les nouveaux pods ne démarrent que lorsque le pod précédent est en cours d’exécution. Cela garantit que les réplicas en lecture seule sont créés une fois que le principal est opérationnel et prêt à exposer ses données.

L’objectif de StatefulSets est d’héberger des répliques non interchangeables dans Kubernetes. Alors que les pods d’une application sans état sont équivalents les uns aux autres, les charges de travail avec état nécessitent une approche intentionnelle des déploiements, de la mise à l’échelle et de la résiliation.

Les StatefulSets s’intègrent aux volumes persistants locaux pour prendre en charge le stockage persistant qui reste attaché à chaque réplica. Chaque pod a accès à son propre volume qui sera automatiquement rattaché lorsque la réplique sera reprogrammée sur un autre nœud.

Créer un StatefulSet

Voici un exemple de manifeste YAML qui définit un ensemble avec état pour exécuter MySQL avec un nœud principal et deux répliques :

apiVersion: v1
kind: Service
metadata:
  name: mysql
  labels:
    app: mysql
spec:
  ports:
    - name: mysql
      port: 3306
  clusterIP: None
  selector:
    app: mysql
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: mysql
spec:
  selector:
    matchLabels:
      app: mysql
  serviceName: mysql
  replicas: 3
  template:
    metadata:
      labels:
        app: mysql
    spec:
      initContainers:
      - name: mysql-init
        image: mysql:8.0
        command:
        - bash
        - "-c"
        - |
          set -ex
          [[ `hostname` =~ -([0-9]+)$ ]] || exit 1
          ordinal=${BASH_REMATCH[1]}
          echo [mysqld] > /mnt/conf/server-id.cnf
          # MySQL doesn't allow "0" as a `server-id` so we have to add 1 to the Pod's index
          echo server-id=$((1 + $ordinal)) >> /mnt/conf/server-id.cnf
          if [[ $ordinal -eq 0 ]]; then
            printf "[mysqld]nlog-bin" > /mnt/conf/primary.cnf
          else
            printf "[mysqld]nsuper-read-only" /mnt/conf/replica.cnf
          fi          
        volumeMounts:
        - name: config
          mountPath: /mnt/conf
      containers:
      - name: mysql
        image: mysql:8.0
        env:
        - name: MYSQL_ALLOW_EMPTY_PASSWORD
          value: "1"
        ports:
        - name: mysql
          containerPort: 3306
        volumeMounts:
        - name: config
          mountPath: /etc/mysql/conf.d
        - name: data
          mountPath: /var/lib/mysql
          subPath: mysql
        livenessProbe:
          exec:
            command: ["mysqladmin", "ping"]
          initialDelaySeconds: 30
          periodSeconds: 5
          timeoutSeconds: 5
        readinessProbe:
          exec:
            command: ["mysql", "-h", "127.0.0.1", "-e", "SELECT 1"]
          initialDelaySeconds: 5
          periodSeconds: 5
          timeoutSeconds: 1
      volumes:
      - name: config
        emptyDir: {}
  volumeClaimTemplates:
  - metadata:
      name: data
    spec:
      accessModes: ["ReadWriteOnce"]
      resources:
        requests:
          storage: 1Gi

C’est un manifeste assez long, alors déballons ce qui se passe.

  • Un service sans tête est créé en définissant son clusterIP à None. Ceci est lié au StatefulSet et fournit les identités réseau de ses pods.
  • Un StatefulSet est créé pour contenir les pods MySQL. La replicas champ spécifie que trois pods seront exécutés. Le service sans tête est référencé par le serviceName champ.
  • Dans le StatefulSet, un conteneur init est créé qui pré-remplit un fichier dans un répertoire de configuration monté à l’aide d’un volume persistant. Le conteneur exécute un script Bash qui établit l’index ordinal du pod en cours d’exécution. Lorsque l’index est 0, le pod est le premier à être créé dans le StatefulSet, il devient donc le nœud principal MySQL. Les autres pods sont configurés en tant que répliques. Le fichier de configuration approprié est écrit dans le volume où il sera accessible ultérieurement au conteneur MySQL.
  • Le conteneur MySQL est créé avec le volume de configuration monté dans le répertoire MySQL correct. Cela garantit que l’instance MySQL est configurée en tant qu’instance principale ou réplica, selon qu’il s’agit du premier pod à démarrer dans le StatefulSet.
  • Les sondes d’activité et de préparation sont utilisées pour détecter quand l’instance MySQL est prête. Cela empêche les pods successifs du StatefulSet de démarrer tant que le précédent n’est pas en cours d’exécution, garantissant ainsi que les répliques MySQL n’existent pas avant que le nœud principal ne soit opérationnel.

Un déploiement ou un ReplicaSet ordinaire ne peut pas implémenter ce flux de travail. Une fois vos pods démarrés, vous pouvez augmenter ou réduire le StatefulSet sans risquer de détruire le nœud principal MySQL. Kubernetes fournit une garantie que l’ordre des pods établi sera respecté.

# Create the MySQL StatefulSet
$ kubectl apply -f mysql-statefulset.yaml

# Scale up to 5 Pods - a MySQL primary and 4 MySQL replicas
$ kubectl scale statefulset mysql --replicas=5

Mises à jour continues

Les StatefulSets implémentent des mises à jour progressives lorsque vous modifiez leur spécification. Le contrôleur StatefulSet remplacera chaque pod dans l’ordre inverse séquentiel, en utilisant les index ordinaux attribués de manière persistante. mysql-3 seront supprimés et remplacés en premier, suivis de mysql-2 et mysql-1. mysql-2 ne sera pas mis à jour avant le nouveau mysql-3 Le pod passe au Running Etat.

Le mécanisme de mise à jour progressive inclut également la prise en charge des déploiements par étapes. Réglage de la .spec.updateStrategy.rollingUpdate.partition dans le manifeste de votre StatefulSet indique à Kubernetes de ne mettre à jour les pods qu’avec un index ordinal supérieur ou égal à la partition donnée.

apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: mysql
spec:
  selector:
    matchLabels:
      app: mysql
  serviceName: mysql
  replicas: 3
  updateStrategy:
    rollingUpdate:
      partition: 1
  template:
    ...
  volumeClaimTemplates:
    ...

Dans cet exemple, seuls les pods indexés 1 ou supérieur seront ciblés par les opérations de mise à jour. Le premier pod du StatefulSet ne recevra pas de nouvelle spécification tant que la partition n’aura pas été réduite ou supprimée.

Limites

Les StatefulSets ont certaines limitations dont vous devez être conscient avant de les adopter. Ces pièges courants peuvent vous faire trébucher lorsque vous commencez à déployer des applications avec état.

  • La suppression d’un StatefulSet ne garantit pas que les pods seront résiliés dans l’ordre indiqué par leurs identités.
  • La suppression d’un StatefulSet ou la réduction de son nombre de répliques ne supprimera aucun volume associé. Cela protège contre la perte accidentelle de données.
  • L’utilisation de mises à jour propagées peut créer une situation dans laquelle un état cassé non valide se produit. Cela se produit lorsque vous fournissez une configuration qui ne passe jamais à l’état Running ou Ready en raison d’un problème avec votre application. Revenir à une bonne configuration ne résoudra pas le problème, car Kubernetes attend indéfiniment que le mauvais pod devienne prêt. Vous devez résoudre manuellement la situation en supprimant les pods en attente ou en échec.

Les StatefulSets omettent également un mécanisme de redimensionnement des volumes liés à chaque Pod. Vous devez modifier manuellement chaque volume persistant et sa demande de volume persistant correspondante, puis supprimer le StatefulSet et orphelin ses pods. La création d’un nouveau StatefulSet avec la spécification révisée permettra à Kubernetes de récupérer les pods orphelins et de redimensionner les volumes.

Quand ne pas utiliser un StatefulSet

Vous ne devez utiliser un StatefulSet que lorsque des réplicas individuels ont leur propre état. Un StatefulSet n’est pas nécessaire lorsque tous les réplicas partagent le même état, même s’il est persistant.

Dans ces situations, vous pouvez utiliser un ReplicaSet ou un déploiement standard pour lancer vos pods. Tous les volumes montés seront partagés entre tous les pods, ce qui est le comportement attendu pour les systèmes sans état.

Un StatefulSet n’ajoute pas de valeur, sauf si vous avez besoin d’un stockage persistant individuel ou d’identificateurs de réplicas persistants. L’utilisation incorrecte d’un StatefulSet peut prêter à confusion en suggérant que les pods sont avec état alors qu’ils exécutent en réalité une charge de travail sans état.

Sommaire

Les StatefulSets fournissent des identités persistantes pour les pods Kubernetes répliqués. Chaque pod est nommé avec un index ordinal alloué séquentiellement. Lorsque le Pod est reprogrammé, son remplaçant hérite de son identité. Le StatefulSet garantit également que les pods sont terminés dans l’ordre inverse dans lequel ils ont été créés.

Les StatefulSets permettent à Kubernetes de prendre en charge les applications qui nécessitent des déploiements progressifs gracieux, des identifiants réseau stables et un accès fiable au stockage persistant. Ils conviennent à toutes les situations où les répliques d’un ensemble de pods ont leur propre état qui doit être préservé.

Un StatefulSet n’a pas besoin d’être utilisé si vos réplicas sont sans état, même s’ils stockent des données persistantes. Les déploiements et les ReplicaSets sont plus adaptés lorsque les réplicas individuels n’ont pas besoin d’être identifiés ou mis à l’échelle dans un ordre cohérent.

★★★★★