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 de forma directa en la consola de Google Cloud, haz clic en Guiarme:

GUIARME


Antes de comenzar

Configura tu proyecto

  1. Accede a tu cuenta de Google Cloud. Si eres nuevo en Google Cloud, crea una cuenta para evaluar el rendimiento de nuestros productos en situaciones reales. Los clientes nuevos también obtienen $300 en créditos gratuitos para ejecutar, probar y, además, implementar cargas de trabajo.
  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. Asegúrate de que la facturación esté habilitada para tu proyecto de Google Cloud.

  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. Asegúrate de que la facturación esté habilitada para tu proyecto de Google Cloud.

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

    Enable the APIs

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:

Cree un clúster de GKE

  1. Crea un clúster de GKE llamado stateful-cluster:

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

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

      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
    

    En el ejemplo anterior, STATUS es RUNNING para stateful-cluster.

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: Immediate
allowVolumeExpansion: true
parameters:
  tier: standard
  network: default
  • volumeBindingMode se configura como Immediate, lo que permite que el aprovisionamiento del volumen comience de inmediato.
  • 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/<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. 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 este:

    NAME         STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS        AGE
    fileserver   Bound    pvc-aadc7546-78dd-4f12-a909-7f02aaedf0c3   1Ti        RWX            filestore-sc        92m
    
  3. Verifica que la instancia de Filestore que acabas de crear esté lista:

    gcloud filestore instances list
    

    El resultado es similar a este:

    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
    

Crea un lector y un pod escritor

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. 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 este:

    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. En la consola de Google Cloud, ve a la página Administrar recursos.

    Ir a Administrar recursos

  2. En la lista de proyectos, elige el proyecto que quieres borrar y haz clic en Borrar.
  3. En el diálogo, escribe el ID del proyecto y, luego, haz clic en Cerrar para borrar el proyecto.

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 stateful-cluster --zone=COMPUTE_ZONE
    

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

¿Qué sigue?