Implementa una carga de trabajo con estado con Filestore

En este instructivo, se muestra cómo implementar una carga de trabajo simple de lector o escritor con estado a través de un volumen persistente (PV) y una reclamación de volumen persistente (PVC) en Google Kubernetes Engine (GKE). Sigue este instructivo para aprender a diseñar para la escalabilidad con Filestore, el sistema de archivos de red administrado de Google Cloud.

Antecedentes

Por naturaleza, los pods son efímeros. Esto significa que GKE destruye el estado y el valor almacenado en un pod cuando se borra, expulsa o reprograma.

Como operador de la aplicación, recomendamos mantener las cargas de trabajo con estado. Entre los ejemplos de cargas de trabajo, se incluyen las aplicaciones que procesan artículos de WordPress, las apps de mensajería y las apps que procesan operaciones de aprendizaje automático.

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

  • Implementar cargas de trabajo con estado que sean escalables
  • Habilitar varios pods para tener ReadWriteMany como su accessMode, de modo que varios pods puedan leer y escribir al mismo tiempo en el mismo almacenamiento
  • Configura GKE para activar volúmenes en varios pods de forma simultánea.
  • Conserva el almacenamiento cuando se quitan los Pods.
  • Habilita los Pods para compartir datos y escalar con facilidad.

Objetivos

Este instructivo es para operadores de aplicaciones y otros usuarios que desean configurar una carga de trabajo con estado escalable en GKE a través de PVC y NFS.

Diagrama de GKE de cargas de trabajo con estado

En este instructivo se abarcan los siguientes pasos:

  1. Crear un clúster de GKE.
  2. Configura el almacenamiento de archivos administrados con Filestore a través de CSI.
  3. Crea un lector y un Pod de escritor.
  4. Expón y accede al pod de lector a un balanceador de cargas de servicio.
  5. Escala verticalmente el escritor.
  6. Accede a los datos desde el pod escritor.

Costos

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

Usa la calculadora de precios para generar una estimación de los costos según el uso previsto.

Cuando finalices este instructivo, puedes borrar los recursos creados para evitar que se te siga facturando. Para obtener más información, consulta Cómo realizar una limpieza.


Para seguir la guía paso a paso sobre esta tarea directamente en la consola Google Cloud , haz clic en Guiarme:

Guiarme


Antes de comenzar

Configura tu 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. Establece valores predeterminados para Google Cloud CLI

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

    2. Descarga el código fuente para esta app de ejemplo:

      git clone https://github.com/GoogleCloudPlatform/kubernetes-engine-samples
      cd kubernetes-engine-samples/databases/stateful-workload-filestore
      
    3. Configura 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
      

      Reemplaza los siguientes valores:

    Crea un clúster de GKE

    1. Crea un clúster de GKE:

      gcloud container clusters create-auto CLUSTER_NAME --location CONTROL_PLANE_LOCATION
      

      Reemplaza el siguiente valor:

      • CLUSTER_NAME: Es el nombre de tu clúster.
      • CONTROL_PLANE_LOCATION: Es 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 crea 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
      

      En el ejemplo anterior, STATUS es RUNNING.

    Configura el almacenamiento de archivos administrado con Filestore a través de CSI

    GKE proporciona una forma de implementar y administrar automáticamente el controlador CSI de Kubernetes Filestore en tus clústeres. El uso de CSI de Filestore te permite crear o borrar instancias de Filestore de forma dinámica y usarlas en cargas de trabajo de Kubernetes con una StorageClass o una Deployment.

    Puedes crear una nueva instancia de Filestore si creas un PVC que aprovisione de forma dinámica una instancia de Filestore y el PV, o accede a instancias de Filestore aprovisionadas con anterioridad en cargas de trabajo de Kubernetes.

    Instancia nueva

    Crea una 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 establece en WaitForFirstConsumer, lo que retrasa el aprovisionamiento del volumen hasta que un Pod lo use. Este parámetro de configuración permite que el plano de control conozca la ubicación del volumen (Kubernetes llama a esto su topología) y permite que este ejemplo funcione para clústeres nuevos sin nodos, en los que aún no hay topología.
    • tier se configura como standard para un tiempo de creación de instancia de Filestore más rápido. Si necesitas más almacenamiento NFS disponible, instantáneas para copia de seguridad de datos, replicación de datos en varias zonas y otras funciones a nivel de empresa, configura tier como enterprise. Nota: La política de reclamo para PV creado de forma dinámica es Delete de forma predeterminada si no se configura reclaimPolicy en 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 es similar a este:

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

    Instancia aprovisionada con anterioridad

    Crea una clase de almacenamiento

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

    Cuando volumeBindingMode se establece en Immediate, permite que el aprovisionamiento del volumen comience de inmediato.

    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 es similar a este:

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

    Crea 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. Verifica que la instancia de Filestore preexistente esté lista:

        gcloud filestore instances list
      

      El resultado es similar al siguiente, en el que el valor 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
      

      Observe la INSTANCE_NAME, la LOCATION, la FILE_SHARE_NAME y la IP_ADDRESS de la instancia de Filestore.

    2. Propaga 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. Reemplaza las variables de marcador de posición por las variables de consola que se obtuvieron antes del 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 el PV

        kubectl apply -f preprov-pv.yaml
      
    5. Verifica que el STATUS del PV esté configurado como Bound:

        kubectl get pv
      

      El resultado es similar a este:

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

    Usa un objeto PersistentVolumeClaim para acceder al volumen

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

    Para que varios Pods lean y escriban en el volumen, accessMode se establece en ReadWriteMany.

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

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

      kubectl get pvc
      

      El resultado es similar a lo siguiente:

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

    Crea un lector y un pod escritor

    En esta sección, crearás un Pod de lector y un Pod de escritor. En este instructivo, 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 que se distribuyen entre los nodos de un clúster.

    Crea el Pod del lector

    El Pod del lector leerá el archivo que escriben los Pods del escritor. Los Pods del lector verán a qué hora y qué réplica del Pod de escritor escribió 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 del lector leerá desde la ruta de acceso /usr/share/nginx/html que se comparte entre todos los Pods.

    1. Implementa el Pod del lector:

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

      gcloud filestore instances list
      

      El resultado es similar a lo 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. Consulta la lista de Pods para verificar que las réplicas de lector estén en ejecución:

      kubectl get pods
      

      El resultado es similar a lo siguiente:

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

    Crea el Pod escritor

    El Pod del escritor escribirá periódicamente en un archivo compartido al que pueden acceder otros Pods del escritor y del lector. El Pod del escritor registra su presencia y escribe su nombre de host en el archivo compartido.

    La imagen que usa 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 mantendrá el recuento 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 instructivo, el Pod del escritor escribe cada 30 segundos en la ruta de acceso /html/index.html. Modifica el valor del número sleep para que tenga una frecuencia de escritura diferente.

    1. Implementa el Pod de escritor:

      kubectl apply -f writer-fs.yaml
      
    2. Consulta la lista de Pods para verificar que los Pods del escritor se estén ejecutando:

      kubectl get pods
      

      El resultado es similar a este:

      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
      

    Expón y accede a la carga de trabajo del lector en un balanceador de cargas de servicio

    Para exponer una carga de trabajo fuera del clúster, crea un Service de tipo LoadBalancer. Este tipo de servicio crea un balanceador de cargas externo con una dirección IP a la que se puede acceder a través de Internet.

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

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

      kubectl get svc --watch
      

      Cuando Service está lista, la columna EXTERNAL-IP muestra la dirección IP pública del balanceador de cargas:

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

    4. Usa un navegador web para navegar al EXTERNAL-IP asignado al balanceador de cargas. La página se actualiza cada 30 segundos. Cuantos más pods de escritores y menor frecuencia, mayor será la cantidad de entradas que se mostrarán.

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

    Escala el escritor

    Debido a que el PV accessMode se configuró como ReadWriteMany, GKE puede escalar verticalmente la cantidad de Pods para que más Pods del escritor puedan escribir en este volumen compartido (o más lectores puedan leerlos).

    1. Escala verticalmente writer a cinco réplicas:

      kubectl scale deployment writer --replicas=5
      

      El resultado es similar a este:

      deployment.extensions/writer scaled
      
    2. Verifica la cantidad de réplicas en ejecución:

      kubectl get pods
      

      El resultado es similar a este:

      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 navegar a EXTERNAL-IP asignado al balanceador de cargas.

    En este punto, configuraste y escalaste tu clúster para admitir cinco pods de escritor con estado. En el que varios Pods del escritor escriben en el mismo archivo de forma simultánea. Los Pods del lector también se pueden escalar con facilidad.

    Accede a los datos desde el pod del escritor (opcional)

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

    1. Obtén el nombre del Pod del escritor:

      kubectl get pods
      

      El resultado es similar a este:

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

      Toma nota del nombre de host de un Pod del escritor (ejemplo: writer-5465d65b46-7hxv4).

    2. Ejecuta el siguiente comando para acceder al Pod del escritor:

      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. Sal del entorno:

      exit
      

    Realiza una limpieza

    Para evitar que se apliquen cargos a tu cuenta de Google Cloud por los recursos usados en este instructivo, borra el proyecto que contiene los recursos o conserva el proyecto y borra los recursos individuales.

    Borra 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.

    Borra los recursos individuales

    1. Borra el Service del balanceador de cargas:

      kubectl delete service reader-lb
      

      Espera hasta que se borre el balanceador de cargas aprovisionado para el servicio de lector.

    2. Verifica que la lista muestre Listed 0 items:

      gcloud compute forwarding-rules list
      
    3. Borra las implementaciones

      kubectl delete deployment writer
      kubectl delete deployment reader
      
    4. Verifica que se borren los Pods y muestre No resources found in default namespace.

      kubectl get pods
      
    5. Borra el PVC. Esto también borrará el PV y la instancia de Filestore debido a que la política de retención establecida en delete

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

      gcloud container clusters delete CLUSTER_NAME --location=CONTROL_PLANE_LOCATION
      

      Esto borra los recursos que conforman el clúster de GKE, incluidos los Pods del lector y del escritor.

    ¿Qué sigue?