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'unVolume 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.

Objectifs

Ce tutoriel s'adresse aux opérateurs d'application et aux autres utilisateurs qui souhaitent configurer une charge de travail avec état évolutive sur GKE à l'aide de PVC et de NFS.

Schéma GKE sur les charges de travail avec état

Ce tutoriel couvre les étapes suivantes :

  1. créer un cluster GKE ;
  2. Configurez le stockage de fichiers géré avec Filestore à l'aide de CSI.
  3. Créer un pod lecteur et rédacteur
  4. Exposer le pod lecteur à un équilibreur de charge de service et y accéder.
  5. Effectuez le scaling à la hausse du rédacteur.
  6. Accéder aux données du pod du rédacteur.

Coûts

Ce tutoriel utilise les composants facturables Google Cloud suivants :

Utilisez le simulateur de coût pour générer une estimation des coûts en fonction de votre utilisation prévue.

Une fois que vous avez terminé ce tutoriel, évitez de continuer à payer des frais en supprimant les ressources que vous avez créées. Pour en savoir plus, consultez la section Effectuer un nettoyage.


Pour obtenir des instructions détaillées sur cette tâche directement dans la console Google Cloud, cliquez sur Visite guidée :

Visite guidée


Avant de commencer

Configurer votre projet

  1. Sign in to your Google Cloud account. If you're new to Google Cloud, create an account to evaluate how our products perform in real-world scenarios. New customers also get $300 in free credits to run, test, and deploy workloads.
  2. In the Google Cloud console, on the project selector page, click Create project to begin creating a new Google Cloud project.

    Go to project selector

  3. Make sure that billing is enabled for your Google Cloud project.

  4. Enable the Compute Engine, GKE, and Filestore APIs.

    Enable the APIs

  5. In the Google Cloud console, on the project selector page, click Create project to begin creating a new Google Cloud project.

    Go to project selector

  6. Make sure that billing is enabled for your Google Cloud project.

  7. Enable the Compute Engine, GKE, and Filestore APIs.

    Enable the APIs

Définir des valeurs par défaut pour Google Cloud CLI

  1. Dans la console Google Cloud, démarrez une instance Cloud Shell :
    Ouvrir Cloud Shell

  2. Téléchargez le code source pour cet exemple d'application :

    git clone https://github.com/GoogleCloudPlatform/kubernetes-engine-samples
    cd kubernetes-engine-samples/databases/stateful-workload-filestore
    
  3. Définissez les variables d'environnement par défaut :

    gcloud config set project PROJECT_ID
    gcloud config set compute/region COMPUTE_REGION
    gcloud config set compute/zone COMPUTE_ZONE
    gcloud config set filestore/zone COMPUTE_ZONE
    gcloud config set filestore/region COMPUTE_REGION
    

    Remplacez les valeurs suivantes :

Créer un cluster GKE

  1. Créez un cluster GKE nommé stateful-cluster :

    gcloud container clusters create-auto stateful-cluster --region COMPUTE_REGION
    

    Une fois le cluster créé, le résultat ressemble à ce qui suit:

      gcloud container clusters describe stateful-cluster
      NAME: stateful-cluster
      LOCATION: northamerica-northeast2
      MASTER_VERSION: 1.21.11-gke.1100
      MASTER_IP: 34.130.255.70
      MACHINE_TYPE: e2-medium
      NODE_VERSION: 1.21.11-gke.1100
      NUM_NODES: 3
      STATUS: RUNNING
    

    STATUS est RUNNING pour stateful-cluster.

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/<FILESTORE_ZONE>/<INSTANCE_NAME>/<FILESTORE_SHARE_NAME>"
    volumeAttributes:
      ip: <IP_ADDRESS> # Modify this to Pre-provisioned Filestore instance IP
      volume: <FILESTORE_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

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
    

Effectuer un nettoyage

Pour éviter que les ressources utilisées lors de ce tutoriel soient facturées sur votre compte Google Cloud, supprimez le projet contenant les ressources, ou conservez le projet et supprimez les ressources individuelles.

Supprimer le projet

  1. In the Google Cloud console, go to the Manage resources page.

    Go to Manage resources

  2. In the project list, select the project that you want to delete, and then click Delete.
  3. In the dialog, type the project ID, and then click Shut down to delete the project.

Supprimer les ressources individuelles

  1. Supprimez le service d'équilibrage de charge:

    kubectl delete service reader-lb
    

    Attendez que l'équilibreur de charge provisionné pour le service de lecture soit supprimé.

  2. Vérifiez que la liste renvoie Listed 0 items:

    gcloud compute forwarding-rules list
    
  3. Supprimer les déploiements

    kubectl delete deployment writer
    kubectl delete deployment reader
    
  4. Vérifiez que les pods sont supprimés et renvoie le résultat No resources found in default namespace.

    kubectl get pods
    
  5. Supprimez la PVC. Cela supprimera également le PV et l'instance Filestore en raison de la règle de conservation définie sur delete.

    kubectl delete pvc fileserver
    
  6. Supprimez le cluster GKE :

    gcloud container clusters delete stateful-cluster --zone=COMPUTE_ZONE
    

    Cela supprime les ressources qui composent le cluster GKE, y compris les pods de lecteur et de rédacteur.

Étape suivante