Desplegar una carga de trabajo con estado con Filestore

En este tutorial se explica cómo desplegar una carga de trabajo con estado de lector/escritor sencilla mediante un volumen persistente (PV) y una reclamación de volumen persistente (PVC) en Google Kubernetes Engine (GKE). Sigue este tutorial para aprender a diseñar con escalabilidad mediante Filestore, el sistema de archivos de red gestionado de Google Cloud.

Fondo

Por naturaleza, los pods son efímeros. Esto significa que GKE destruye el estado y el valor almacenados en un pod cuando se elimina, se expulsa o se vuelve a programar.

Como operador de aplicaciones, puede que quieras mantener cargas de trabajo con reconocimiento del estado. Entre estas cargas de trabajo se incluyen las aplicaciones que procesan artículos de WordPress, las aplicaciones de mensajería y las aplicaciones que procesan operaciones de aprendizaje automático.

Si usas Filestore en GKE, puedes realizar las siguientes operaciones:

  • Despliega cargas de trabajo con estado que sean escalables.
  • Permite que varios pods tengan ReadWriteMany como accessMode, de forma que varios pods puedan leer y escribir al mismo tiempo en el mismo almacenamiento.
  • Configura GKE para montar volúmenes en varios pods simultáneamente.
  • Conserva el almacenamiento cuando se eliminen los pods.
  • Permite que los pods compartan datos y se escalen fácilmente.

Objetivos

Este tutorial está dirigido a operadores de aplicaciones y otros usuarios que quieran configurar una carga de trabajo con estado escalable en GKE mediante PVC y NFS.

Diagrama de carga de trabajo con reconocimiento del estado de GKE

Este tutorial abarca los siguientes pasos:

  1. Crea un clúster de GKE.
  2. Configura el almacenamiento de archivos gestionado con Filestore mediante CSI.
  3. Crea un pod de lectura y otro de escritura.
  4. Expón el pod del lector a un balanceador de carga de servicio y accede a él.
  5. Amplía el texto.
  6. Acceder a los datos del pod de escritura.

Costes

En este tutorial se usan los siguientes componentes facturables de Google Cloud:

Usa la calculadora de precios para generar una estimación de costes basada en el uso previsto.

Cuando termines este tutorial, puedes evitar que se te siga facturando eliminando los recursos que has creado. Para obtener más información, consulta la sección Limpiar.


Para seguir las instrucciones paso a paso de esta tarea directamente en la Google Cloud consola, haz clic en Ayúdame:

Guíame


Antes de empezar

Configurar el proyecto

  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.

    Roles required to create a project

    To create a project, you need the Project Creator role (roles/resourcemanager.projectCreator), which contains the resourcemanager.projects.create permission. Learn how to grant roles.

    Go to project selector

  3. Verify that billing is enabled for your Google Cloud project.

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

    Roles required to enable APIs

    To enable APIs, you need the Service Usage Admin IAM role (roles/serviceusage.serviceUsageAdmin), which contains the serviceusage.services.enable permission. Learn how to grant roles.

    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.

    Roles required to create a project

    To create a project, you need the Project Creator role (roles/resourcemanager.projectCreator), which contains the resourcemanager.projects.create permission. Learn how to grant roles.

    Go to project selector

  6. Verify that billing is enabled for your Google Cloud project.

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

    Roles required to enable APIs

    To enable APIs, you need the Service Usage Admin IAM role (roles/serviceusage.serviceUsageAdmin), which contains the serviceusage.services.enable permission. Learn how to grant roles.

    Enable the APIs

  8. Definir valores predeterminados para Google Cloud CLI

    1. En la Google Cloud consola, inicia una instancia de Cloud Shell:
      Abrir Cloud Shell

    2. Descarga el código fuente de esta aplicación de ejemplo:

      git clone https://github.com/GoogleCloudPlatform/kubernetes-engine-samples
      cd kubernetes-engine-samples/databases/stateful-workload-filestore
      
    3. Define las variables de entorno predeterminadas:

      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
      

      Sustituye los siguientes valores:

    Crear un clúster de GKE

    1. Crea un clúster de GKE:

      gcloud container clusters create-auto CLUSTER_NAME --location CONTROL_PLANE_LOCATION
      

      Sustituye el siguiente valor:

      • CLUSTER_NAME: el nombre del clúster.
      • CONTROL_PLANE_LOCATION: la ubicación de Compute Engine del plano de control de tu clúster. Proporciona una región para los clústeres regionales o una zona para los clústeres zonales.

      El resultado es similar al siguiente una vez que se ha creado el clúster:

        gcloud container clusters describe CLUSTER_NAME
        NAME: CLUSTER_NAME
        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
      

      Donde STATUS es RUNNING.

    Configurar el almacenamiento de archivos gestionado con Filestore mediante CSI

    GKE ofrece una forma de desplegar y gestionar automáticamente el controlador de CSI de Filestore para Kubernetes en tus clústeres. Con el controlador de CSI para Filestore, puedes crear o eliminar instancias de Filestore de forma dinámica y usarlas en cargas de trabajo de Kubernetes con un StorageClass o un Deployment.

    Puedes crear una instancia de Filestore creando un PVC que aprovisione dinámicamente una instancia de Filestore y el PV, o bien acceder a instancias de Filestore aprovisionadas previamente en cargas de trabajo de Kubernetes.

    Nueva instancia

    Crear la clase de almacenamiento

    apiVersion: storage.k8s.io/v1
    kind: StorageClass
    metadata:
      name: filestore-sc
    provisioner: filestore.csi.storage.gke.io
    volumeBindingMode: WaitForFirstConsumer
    allowVolumeExpansion: true
    parameters:
      tier: standard
      network: default
    • volumeBindingMode se define como WaitForFirstConsumer, lo que retrasa el aprovisionamiento del volumen hasta que un pod lo utilice. Este ajuste permite que el plano de control conozca la ubicación del volumen (Kubernetes lo llama topología) y que este ejemplo funcione en clústeres nuevos sin nodos, donde aún no hay topología.
    • tier se define como standard para que la instancia de Filestore se cree más rápido. Si necesitas un almacenamiento NFS con mayor disponibilidad, capturas para copias de seguridad de datos, replicación de datos en varias zonas y otras funciones de nivel empresarial, define tier como enterprise. Nota: La política de reclamación de los PV creados dinámicamente tiene el valor predeterminado Delete si no se define el reclaimPolicy en el StorageClass.
    1. Crea el recurso StorageClass:

      kubectl create -f filestore-storageclass.yaml
      
    2. Verifica que se haya creado la clase de almacenamiento:

      kubectl get sc
      

      El resultado debería ser similar al siguiente:

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

    Instancia preaprovisionada

    Crear la clase de almacenamiento

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

    Si volumeBindingMode tiene el valor Immediate, el aprovisionamiento del volumen puede empezar inmediatamente.

    1. Crea el recurso StorageClass:

        kubectl create -f preprov-storageclass.yaml
      
    2. Verifica que se haya creado la clase de almacenamiento:

        kubectl get sc
      

      El resultado debería ser similar al siguiente:

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

    Crear un volumen persistente para la instancia de 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. Comprueba que la instancia de Filestore ya creada esté lista:

        gcloud filestore instances list
      

      El resultado es similar al siguiente, donde el valor de STATE es 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
      

      Toma nota de los INSTANCE_NAME, LOCATION, FILE_SHARE_NAME y IP_ADDRESS de la instancia de Filestore.

    2. Rellena las variables de la consola de la instancia de Filestore:

        INSTANCE_NAME=INSTANCE_NAME
        LOCATION=LOCATION
        FILE_SHARE_NAME=FILE_SHARE_NAME
        IP_ADDRESS=IP_ADDRESS
      
    3. Sustituye las variables de marcador de posición por las variables de consola obtenidas anteriormente en el archivo 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. Crea la PV

        kubectl apply -f preprov-pv.yaml
      
    5. Comprueba que el valor de STATUS de la PV sea Bound:

        kubectl get pv
      

      El resultado debería ser similar al siguiente:

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

    Usar un PersistentVolumeClaim para acceder al volumen

    El siguiente manifiesto de pvc.yaml hace referencia al StorageClass del controlador de CSI de Filestore llamado filestore-sc.

    Para que varios pods puedan leer y escribir en el volumen, el valor de accessMode se define como ReadWriteMany.

    kind: PersistentVolumeClaim
    apiVersion: v1
    metadata:
      name: fileserver
    spec:
      accessModes:
      - ReadWriteMany
      storageClassName: filestore-sc
      resources:
        requests:
          storage: 1Ti
    1. Despliega el PVC:

      kubectl create -f pvc.yaml
      
    2. Verifica que se haya creado el PVC:

      kubectl get pvc
      

      El resultado debería ser similar al siguiente:

      NAME         STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS        AGE
      fileserver   Bound    pvc-aadc7546-78dd-4f12-a909-7f02aaedf0c3   1Ti        RWX            filestore-sc        92m
      

    Crear un pod de lectura y otro de escritura

    En esta sección, crearás un pod de lectura y un pod de escritura. En este tutorial se usan implementaciones de Kubernetes para crear los pods. Un Deployment es un objeto de la API de Kubernetes que te permite ejecutar varias réplicas de pods distribuidas entre los nodos de un clúster.

    Crear el Pod de lectura

    El pod de lectura leerá el archivo que escriban los pods de escritura. Los pods de lectura verán a qué hora y qué réplica del pod de escritura ha escrito en el archivo.

    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

    El pod de lectura leerá de la ruta /usr/share/nginx/html, que se comparte entre todos los pods.

    1. Implementa el pod de lector:

      kubectl apply -f reader-fs.yaml
      
    2. Comprueba que la instancia de Filestore que acabas de crear esté lista:

      gcloud filestore instances list
      

      El resultado debería ser similar al siguiente:

      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
      
    3. Comprueba que las réplicas de lectores se están ejecutando. Para ello, haz una consulta a la lista de pods:

      kubectl get pods
      

      El resultado debería ser similar al siguiente:

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

    Crea el Pod de redacción

    El pod de escritura escribirá periódicamente en un archivo compartido al que podrán acceder otros pods de escritura y lectura. El pod de escritura registra su presencia escribiendo el nombre de su host en el archivo compartido.

    La imagen utilizada para el pod del escritor es una imagen personalizada de Alpine Linux, que se usa para utilidades y aplicaciones de producción. Incluye una secuencia de comandos indexInfo.html que obtendrá los metadatos del escritor más reciente y llevará la cuenta de todos los escritores únicos y las escrituras totales.

    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

    En este tutorial, el pod de escritura escribe cada 30 segundos en la ruta /html/index.html. Modifica el valor del número sleep para que tenga una frecuencia de escritura diferente.

    1. Implementa el pod de escritura:

      kubectl apply -f writer-fs.yaml
      
    2. Comprueba que los pods de escritura se están ejecutando. Para ello, haz una consulta a la lista de pods:

      kubectl get pods
      

      El resultado debería ser similar al siguiente:

      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
      

    Exponer y acceder a la carga de trabajo de lectura en un balanceador de carga de servicio

    Para exponer una carga de trabajo fuera del clúster, crea un servicio de tipo LoadBalancer. Este tipo de servicio crea un balanceador de carga externo con una dirección IP accesible a través de Internet.

    1. Crea un servicio de tipo LoadBalancer llamado reader-lb:

      kubectl create -f loadbalancer.yaml
      
    2. Supervisa la implementación para ver que GKE asigna un EXTERNAL-IP al servicio reader-lb:

      kubectl get svc --watch
      

      Cuando el Service esté listo, la columna EXTERNAL-IP mostrará la dirección IP pública del balanceador de carga:

        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. Pulsa Ctrl+C para finalizar el proceso de monitorización.

    4. Usa un navegador web para ir a la EXTERNAL-IP asignada al balanceador de carga. La página se actualiza cada 30 segundos. Cuantos más escritores de pódcasts y menor sea la frecuencia, más entradas se mostrarán.

    Para ver más detalles sobre el servicio de balanceador de carga, consulta loadbalancer.yaml.

    Ampliar el escritor

    Como el PV accessMode se ha definido como ReadWriteMany, GKE puede aumentar el número de pods para que más pods de escritura puedan escribir en este volumen compartido (o para que más lectores puedan leerlos).

    1. Amplía writer a cinco réplicas:

      kubectl scale deployment writer --replicas=5
      

      El resultado debería ser similar al siguiente:

      deployment.extensions/writer scaled
      
    2. Verifica el número de réplicas en ejecución:

      kubectl get pods
      

      El resultado debería ser similar al siguiente:

      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. Usa un navegador web para volver a la EXTERNAL-IP asignada al balanceador de carga.

    En este punto, has configurado y escalado tu clúster para que admita cinco pods de escritura con estado. Cuando varios pods de escritura escriben en el mismo archivo simultáneamente. Los lectores de pódcasts también se pueden ampliar fácilmente.

    Opcional: Acceder a los datos del Pod de escritura

    En esta sección se muestra cómo usar una interfaz de línea de comandos para acceder a un pod de lectura o escritura. Puedes ver el componente compartido en el que escribe el escritor y del que lee el lector.

    1. Obtén el nombre del pod de escritura:

      kubectl get pods
      

      El resultado debería ser similar al siguiente:

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

      Anota el nombre de host de un pod de escritor (por ejemplo, writer-5465d65b46-7hxv4).

    2. Ejecuta el siguiente comando para acceder al pod de escritura:

      kubectl exec -it WRITER_HOSTNAME -- /bin/sh
      
    3. Consulta el componente compartido en el archivo indexData.html:

      cd /html
      cat indexData.html
      
    4. Borra el archivo indexData.html:

      echo '' > indexData.html
      

      Actualiza el navegador web que aloja la dirección EXTERNAL-IP para ver el cambio.

    5. Salir del entorno:

      exit
      

    Limpieza

    Para evitar que los recursos utilizados en este tutorial se cobren en tu cuenta de Google Cloud, elimina el proyecto que contiene los recursos o conserva el proyecto y elimina los recursos.

    Eliminar el proyecto

    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.

    Eliminar los recursos concretos

    1. Elimina el servicio del balanceador de carga:

      kubectl delete service reader-lb
      

      Espera a que se elimine el balanceador de carga aprovisionado para el servicio de lector.

    2. Verifica que la lista devuelva Listed 0 items:

      gcloud compute forwarding-rules list
      
    3. Eliminar los despliegues

      kubectl delete deployment writer
      kubectl delete deployment reader
      
    4. Verifica que los pods se han eliminado y devuelve No resources found in default namespace.

      kubectl get pods
      
    5. Elimina el PVC. También se eliminarán el PV y la instancia de Filestore debido a que la política de conservación se ha definido en delete.

      kubectl delete pvc fileserver
      
    6. Elimina el clúster de GKE:

      gcloud container clusters delete CLUSTER_NAME --location=CONTROL_PLANE_LOCATION
      

      De esta forma, se eliminan los recursos que componen el clúster de GKE, incluidos los pods de lectura y escritura.

    Siguientes pasos