Déployer une charge de travail avec état avec Filestore

Ce tutoriel explique comment déployer une charge de travail avec état avec accès en lecture/écriture simple à l'aide d'un Volume persistant (PV) et d'une Revendication de volume persistant (PVC) sur Google Kubernetes Engine (GKE). Suivez ce tutoriel pour apprendre à concevoir une solution évolutive à l'aide de Filestore, le système de fichiers réseau géré de Google Cloud.

Contexte

Par nature, les pods sont éphémères. Cela signifie que GKE détruit l'état et la valeur stockés dans un pod lorsque celui-ci est supprimé, évincé ou reprogrammé.

En tant qu'opérateur d'application, vous souhaitez peut-être conserver des charges de travail avec état. Les applications traitant des articles WordPress, les applications de messagerie et les applications de traitement des opérations de machine learning en sont des exemples.

En utilisant Filestore sur GKE, vous pouvez effectuer les opérations suivantes:

  • Déployer des charges de travail avec état évolutives.
  • Activez plusieurs pods afin que leur champ ReadWriteMany soit défini sur accessMode, afin que plusieurs pods puissent lire et écrire en même temps sur le même espace de stockage.
  • Configurer GKE pour installer des volumes dans plusieurs pods simultanément.
  • Conservez l'espace de stockage lorsque les pods sont supprimés.
  • Autorisez les pods à partager des données et à évoluer facilement.

Configurer le stockage de fichiers géré avec Filestore à l'aide de CSI

GKE fournit un moyen de déployer et de gérer automatiquement le pilote CSI Kubernetes pour Filestore dans vos clusters. L'utilisation de CSI Filestore vous permet de créer ou de supprimer dynamiquement des instances Filestore et de les utiliser dans des charges de travail Kubernetes avec un StorageClass ou un Deployment.

Vous pouvez créer une instance Filestore en créant une PVC qui provisionne dynamiquement une instance Filestore et le PV, ou accéder aux instances Filestore préprovisionnées dans les charges de travail Kubernetes.

Nouvelle instance

Créer la ressource StorageClass

apiVersion: storage.k8s.io/v1 kind: StorageClass metadata:   name: filestore-sc provisioner: filestore.csi.storage.gke.io volumeBindingMode: Immediate allowVolumeExpansion: true parameters:   tier: standard   network: default
  • volumeBindingMode est défini sur Immediate, ce qui permet de commencer immédiatement le provisionnement du volume.
  • tier est défini sur standard pour accélérer la création de l'instance Filestore. Si vous avez besoin d'un espace de stockage NFS supérieur, d'instantanés pour la sauvegarde de données, de la réplication de données sur plusieurs zones et d'autres fonctionnalités de niveau entreprise, définissez tier sur enterprise. Remarque: La règle de récupération pour le PV créé dynamiquement est définie par défaut sur Delete si le reclaimPolicy du StorageClass n'est pas défini.
  1. Créez la ressource StorageClass :

    kubectl create -f filestore-storageclass.yaml 
  2. Vérifiez que la classe de stockage est créée:

    kubectl get sc 

    Le résultat ressemble à ce qui suit :

    NAME                     PROVISIONER                    RECLAIMPOLICY   VOLUMEBINDINGMODE      ALLOWVOLUMEEXPANSION   AGE filestore-sc             filestore.csi.storage.gke.io   Delete          Immediate              true                   94m 

Instance préprovisionnée

Créer la ressource StorageClass

apiVersion: storage.k8s.io/v1 kind: StorageClass metadata:   name: filestore-sc provisioner: filestore.csi.storage.gke.io volumeBindingMode: Immediate allowVolumeExpansion: true

Lorsque volumeBindingMode est défini sur Immediate, il permet le démarrage immédiat du provisionnement du volume.

  1. Créez la ressource StorageClass :

      kubectl create -f preprov-storageclass.yaml 
  2. Vérifiez que la classe de stockage est créée:

      kubectl get sc 

    Le résultat ressemble à ce qui suit :

      NAME                     PROVISIONER                    RECLAIMPOLICY   VOLUMEBINDINGMODE      ALLOWVOLUMEEXPANSION   AGE   filestore-sc             filestore.csi.storage.gke.io   Delete          Immediate              true                   94m 

Créer un volume persistant pour l'instance Filestore

apiVersion: v1 kind: PersistentVolume metadata:   name: fileserver   annotations:     pv.kubernetes.io/provisioned-by: filestore.csi.storage.gke.io spec:   storageClassName: filestore-sc   capacity:     storage: 1Ti   accessModes:     - ReadWriteMany   persistentVolumeReclaimPolicy: Delete   volumeMode: Filesystem   csi:     driver: filestore.csi.storage.gke.io     # Modify this to use the zone, filestore instance and share name.     volumeHandle: "modeInstance/<LOCATION>/<INSTANCE_NAME>/<FILE_SHARE_NAME>"     volumeAttributes:       ip: <IP_ADDRESS> # Modify this to Pre-provisioned Filestore instance IP       volume: <FILE_SHARE_NAME> # Modify this to Pre-provisioned Filestore instance share name
  1. Vérifiez que l'instance Filestore préexistante est prête:

      gcloud filestore instances list 

    Le résultat ressemble à ce qui suit, où la valeur STATE est READY:

      INSTANCE_NAME: stateful-filestore   LOCATION: us-central1-a   TIER: ENTERPRISE   CAPACITY_GB: 1024   FILE_SHARE_NAME: statefulpath   IP_ADDRESS: 10.109.38.98   STATE: READY   CREATE_TIME: 2022-04-05T18:58:28 

    Notez les valeurs INSTANCE_NAME, LOCATION, FILE_SHARE_NAME et IP_ADDRESS de l'instance Filestore.

  2. Renseignez les variables de la console d'instance Filestore:

      INSTANCE_NAME=INSTANCE_NAME   LOCATION=LOCATION   FILE_SHARE_NAME=FILE_SHARE_NAME   IP_ADDRESS=IP_ADDRESS 
  3. Remplacez les variables d'espace réservé par les variables de console obtenues ci-dessus dans le fichier preprov-pv.yaml:

      sed "s/<INSTANCE_NAME>/$INSTANCE_NAME/" preprov-pv.yaml > changed.yaml && mv changed.yaml preprov-pv.yaml   sed "s/<LOCATION>/$LOCATION/" preprov-pv.yaml > changed.yaml && mv changed.yaml preprov-pv.yaml   sed "s/<FILE_SHARE_NAME>/$FILE_SHARE_NAME/" preprov-pv.yaml > changed.yaml && mv changed.yaml preprov-pv.yaml   sed "s/<IP_ADDRESS>/$IP_ADDRESS/" preprov-pv.yaml > changed.yaml && mv changed.yaml preprov-pv.yaml 
  4. Créer le PV :

      kubectl apply -f preprov-pv.yaml 
  5. Vérifiez que le champ STATUS du PV est défini sur Bound:

      kubectl get pv 

    Le résultat ressemble à ce qui suit :

      NAME        CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM                STORAGECLASS    REASON   AGE   fileserver  1Ti        RWX            Delete           Bound    default/fileserver   filestore-sc             46m 

Utiliser un objet PersistentVolumeClaim pour accéder au volume

Le fichier manifeste pvc.yaml suivant fait référence à la StorageClass du pilote CSI Filestore nommée filestore-sc.

Pour que plusieurs pods lisent et écrivent dans le volume, accessMode est défini sur ReadWriteMany.

kind: PersistentVolumeClaim apiVersion: v1 metadata:   name: fileserver spec:   accessModes:   - ReadWriteMany   storageClassName: filestore-sc   resources:     requests:       storage: 1Ti
  1. Déployez la PVC:

    kubectl create -f pvc.yaml 
  2. Vérifiez que la PVC est créée:

    kubectl get pvc 

    Le résultat ressemble à ce qui suit :

    NAME         STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS        AGE fileserver   Bound    pvc-aadc7546-78dd-4f12-a909-7f02aaedf0c3   1Ti        RWX            filestore-sc        92m 
  3. Vérifiez que l'instance Filestore que vous venez de créer est prête:

    gcloud filestore instances list 

    Le résultat ressemble à ce qui suit :

    INSTANCE_NAME: pvc-5bc55493-9e58-4ca5-8cd2-0739e0a7b68c LOCATION: northamerica-northeast2-a TIER: STANDARD CAPACITY_GB: 1024 FILE_SHARE_NAME: vol1 IP_ADDRESS: 10.29.174.90 STATE: READY CREATE_TIME: 2022-06-24T18:29:19 

Créer un pod lecteur et rédacteur

Dans cette section, vous allez créer un pod lecteur et un pod rédacteur. Ce tutoriel utilise des déploiements Kubernetes pour créer les pods. Un déploiement est un objet de l'API Kubernetes qui vous permet d'exécuter plusieurs instances dupliquées de pods répartis entre les nœuds d'un cluster.

Créer le pod lecteur

Le pod de lecture lit le fichier en cours d'écriture par les pods redacteurs. Les pods de lecture verront l'heure et l'instance dupliquée du pod rédacteur écrite dans le fichier.

apiVersion: apps/v1 kind: Deployment metadata:   name: reader spec:   replicas: 1   selector:     matchLabels:       app: reader   template:     metadata:       labels:         app: reader     spec:       containers:       - name: nginx         image: nginx:stable-alpine         ports:         - containerPort: 80         volumeMounts:         - name: fileserver           mountPath: /usr/share/nginx/html # the shared directory            readOnly: true       volumes:       - name: fileserver         persistentVolumeClaim:           claimName: fileserver

Le pod de lecture lit à partir du chemin /usr/share/nginx/html, partagé entre tous les pods.

  1. Déployez le pod du lecteur:

    kubectl apply -f reader-fs.yaml 
  2. Vérifiez que les instances dupliquées du lecteur sont en cours d'exécution en interrogeant la liste des pods:

    kubectl get pods 

    Le résultat ressemble à ce qui suit :

    NAME                      READY   STATUS    RESTARTS   AGE reader-66b8fff8fd-jb9p4   1/1     Running   0          3m30s 

Créer le pod rédacteur

Le pod rédacteur écrit régulièrement dans un fichier partagé auquel d'autres pods rédacteur et lecteur peuvent accéder. Le pod du rédacteur enregistre sa présence en écrivant son nom d'hôte dans le fichier partagé.

L'image utilisée pour le pod rédacteur est une image personnalisée d'Alpine Linux, utilisée pour les utilitaires et les applications de production. Elle inclut un script indexInfo.html qui obtient les métadonnées du rédacteur le plus récent, et comptabilise l'ensemble des rédacteurs uniques et le nombre total d'écritures.

apiVersion: apps/v1 kind: Deployment metadata:   name: writer spec:   replicas: 2 # start with 2 replicas   selector:     matchLabels:       app: writer   template:     metadata:       labels:         app: writer     spec:       containers:       - name: content         image: us-docker.pkg.dev/google-samples/containers/gke/stateful-workload:latest         volumeMounts:         - name: fileserver           mountPath: /html # the shared directory         command: ["/bin/sh", "-c"]         args:         - cp /htmlTemp/indexInfo.html /html/index.html;           while true; do           echo "<b> Date :</b> <text>$(date)</text> <b> Writer :</b> <text2> ${HOSTNAME} </text2> <br>  " >> /html/indexData.html;           sleep 30;             done       volumes:       - name: fileserver         persistentVolumeClaim:           claimName: fileserver

Pour ce tutoriel, le pod de rédacteur écrit toutes les 30 secondes dans le chemin /html/index.html. Modifiez la valeur du numéro de sleep pour obtenir une fréquence d'écriture différente.

  1. Déployez le pod rédacteur :

    kubectl apply -f writer-fs.yaml 
  2. Vérifiez que les pods du rédacteur sont en cours d'exécution en interrogeant la liste des pods:

    kubectl get pods 

    Le résultat ressemble à ce qui suit :

    NAME                      READY   STATUS    RESTARTS   AGE reader-66b8fff8fd-jb9p4   1/1     Running   0          3m30s writer-855565fbc6-8gh2k   1/1     Running   0          2m31s writer-855565fbc6-lls4r   1/1     Running   0          2m31s 

Exposer la charge de travail de lecture à un équilibreur de charge de service et y accéder.

Pour exposer une charge de travail en dehors du cluster, créez un service de type LoadBalancer. Ce type de service crée un équilibreur de charge externe avec une adresse IP accessible via Internet.

  1. Créez un service de type LoadBalancer nommé reader-lb:

    kubectl create -f loadbalancer.yaml 
  2. Regardez le déploiement afin de constater que GKE attribue une EXTERNAL-IP au service reader-lb:

    kubectl get svc --watch 

    Lorsque Service est prêt, la colonne EXTERNAL-IP affiche l'adresse IP publique de l'équilibreur de charge:

      NAME         TYPE           CLUSTER-IP    EXTERNAL-IP     PORT(S)        AGE   kubernetes   ClusterIP      10.8.128.1    <none>          443/TCP        2d21h   reader-lb    LoadBalancer   10.8.131.79   34.71.232.122   80:32672/TCP   2d20h 
  3. Appuyez sur Ctrl+C pour mettre fin au processus de contrôle.

  4. Utilisez un navigateur Web pour accéder à l'EXTERNAL-IP attribuée à l'équilibreur de charge. La page est actualisée toutes les 30 secondes. Plus nombreux sont les pods de rédacteurs et plus la fréquence d'écriture est courte, plus le nombre d'entrées affichées est élevé.

Pour en savoir plus sur le service d'équilibrage de charge, consultez la page sur loadbalancer.yaml.

Effectuer le scaling à la hausse du rédacteur

Étant donné que le PV accessMode a été défini sur ReadWriteMany, GKE peut augmenter le nombre de pods afin que davantage de pods rédacteurs puissent écrire sur ce volume partagé (ou qu'un plus grand nombre de lecteurs puissent les lire).

  1. Effectuez un scaling à la hausse de writer à cinq instances dupliquées:

    kubectl scale deployment writer --replicas=5 

    Le résultat ressemble à ce qui suit :

    deployment.extensions/writer scaled 
  2. Vérifiez le nombre d'instances dupliquées en cours d'exécution:

    kubectl get pods 

    Le résultat ressemble à ce qui suit :

    NAME                      READY   STATUS    RESTARTS   AGE reader-66b8fff8fd-jb9p4   1/1     Running   0          11m writer-855565fbc6-8dfkj   1/1     Running   0          4m writer-855565fbc6-8gh2k   1/1     Running   0          10m writer-855565fbc6-gv5rs   1/1     Running   0          4m writer-855565fbc6-lls4r   1/1     Running   0          10m writer-855565fbc6-tqwxc   1/1     Running   0          4m 
  3. Utilisez un navigateur Web pour accéder de nouveau à l'EXTERNAL-IP attribuée à l'équilibreur de charge.

À ce stade, vous avez configuré et mis à l'échelle votre cluster pour qu'il soit compatible avec cinq pods de rédacteur avec état. Où plusieurs pods d'écriture écrivent simultanément sur le même fichier. Vous pouvez également faire évoluer facilement les pods de lecteur.

Facultatif: Accéder aux données à partir du pod du rédacteur

Cette section explique comment utiliser une interface de ligne de commande pour accéder à un pod lecteur ou rédacteur. Vous pouvez voir le composant partagé dans lequel le rédacteur écrit et le lecteur lit.

  1. Obtenez le nom du pod du rédacteur:

    kubectl get pods 

    Le résultat ressemble à ce qui suit :

    NAME                      READY   STATUS    RESTARTS   AGE writer-5465d65b46-7hxv4   1/1     Running   0          20d 

    Notez le nom d'hôte d'un pod rédacteur (exemple: writer-5465d65b46-7hxv4).

  2. Exécutez la commande suivante pour accéder au pod rédacteur:

    kubectl exec -it WRITER_HOSTNAME -- /bin/sh 
  3. Consultez le composant partagé dans le fichier indexData.html:

    cd /html cat indexData.html 
  4. Effacez le fichier indexData.html:

    echo '' > indexData.html 

    Actualisez le navigateur Web hébergeant l'adresse EXTERNAL-IP pour afficher la modification.

  5. Quittez l'environnement:

    exit