Implemente uma carga de trabalho com estado com o Filestore

Este tutorial mostra como implementar uma carga de trabalho com estado de leitura/gravação simples usando um volume persistente (PV) e uma reivindicação de volume persistente (PVC) no Google Kubernetes Engine (GKE). Siga este tutorial para saber como criar designs para escalabilidade usando o Filestore, o sistema de ficheiros de rede gerido da Google Cloud.

Contexto

Por natureza, os pods são efémeros. Isto significa que o GKE destrói o estado e o valor armazenados num pod quando este é eliminado, removido ou reagendado.

Como operador de aplicações, pode querer manter cargas de trabalho com estado. Alguns exemplos destas cargas de trabalho incluem aplicações que processam artigos do WordPress, apps de mensagens e apps que processam operações de aprendizagem automática.

Ao usar o Filestore no GKE, pode realizar as seguintes operações:

  • Implemente cargas de trabalho com estado escaláveis.
  • Permitir que vários pods tenham o ReadWriteMany como o respetivo accessMode, para que vários pods possam ler e escrever ao mesmo tempo no mesmo armazenamento.
  • Configure o GKE para montar volumes em vários pods em simultâneo.
  • Persistir o armazenamento quando os pods são removidos.
  • Permitir que os pods partilhem dados e sejam facilmente dimensionados.

Objetivos

Este tutorial destina-se a operadores de aplicações e outros utilizadores que queiram configurar uma carga de trabalho com estado escalável no GKE através de PVC e NFS.

Diagrama do GKE de carga de trabalho com estado

Este tutorial abrange os seguintes passos:

  1. Crie um cluster do GKE.
  2. Configure o armazenamento de ficheiros gerido com o Filestore através da CSI.
  3. Crie um Pod de leitor e um Pod de escritor.
  4. Exponha e aceda ao pod de leitura a um balanceador de carga de serviço.
  5. Aumente a escala do compositor.
  6. Aceder aos dados do pod de gravação.

Custos

Este tutorial usa os seguintes componentes faturáveis do Google Cloud:

Use a calculadora de preços para gerar uma estimativa de custo com base na sua utilização projetada.

Quando terminar este tutorial, pode evitar a faturação contínua eliminando os recursos que criou. Para mais informações, consulte o artigo Limpe.


Para seguir orientações passo a passo para esta tarefa diretamente na Google Cloud consola, clique em Orientar-me:

Visita guiada


Antes de começar

Configure o seu projeto

  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. Defina predefinições para a CLI Google Cloud

    1. Na Google Cloud consola, inicie uma instância do Cloud Shell:
      Abrir Cloud Shell

    2. Transfira o código-fonte desta app de exemplo:

      git clone https://github.com/GoogleCloudPlatform/kubernetes-engine-samples
      cd kubernetes-engine-samples/databases/stateful-workload-filestore
      
    3. Defina as variáveis de ambiente predefinidas:

      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
      

      Substitua os seguintes valores:

    Crie um cluster do GKE

    1. Crie um cluster do GKE:

      gcloud container clusters create-auto CLUSTER_NAME --location CONTROL_PLANE_LOCATION
      

      Substitua o seguinte valor:

      • CLUSTER_NAME: o nome do cluster.
      • CONTROL_PLANE_LOCATION: a localização do Compute Engine do plano de controlo do seu cluster. Indique uma região para clusters regionais ou uma zona para clusters zonais.

      O resultado é semelhante ao seguinte assim que o cluster é criado:

        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
      

      Em que o STATUS é RUNNING.

    Configure o armazenamento de ficheiros gerido com o Filestore através da CSI

    O GKE oferece uma forma de implementar e gerir automaticamente o controlador CSI do Kubernetes Filestore nos seus clusters. A utilização do CSI do Filestore permite-lhe criar ou eliminar dinamicamente instâncias do Filestore e usá-las em cargas de trabalho do Kubernetes com um StorageClass ou um Deployment.

    Pode criar uma nova instância do Filestore criando um PVC que aprovisiona dinamicamente uma instância do Filestore e o PV, ou aceder a instâncias do Filestore pré-aprovisionadas em cargas de trabalho do Kubernetes.

    Nova instância

    Crie a classe de armazenamento

    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 está definido como WaitForFirstConsumer, o que atrasa o aprovisionamento do volume até que um Pod o use. Esta definição permite que o plano de controlo saiba a localização do volume (o Kubernetes chama a isto a respetiva topologia) e permite que este exemplo funcione para novos clusters sem nós, onde ainda não existe topologia.
    • tier está definido como standard para um tempo de criação de instância do Filestore mais rápido. Se precisar de um armazenamento NFS disponível mais elevado, instantâneos para cópia de segurança de dados, replicação de dados em várias zonas e outras funcionalidades ao nível empresarial, defina tier como enterprise. Nota: a política de recuperação para PVs criados dinamicamente é predefinida como Delete se o reclaimPolicy no StorageClass não estiver definido.
    1. Crie o recurso StorageClass:

      kubectl create -f filestore-storageclass.yaml
      
    2. Verifique se a classe de armazenamento foi criada:

      kubectl get sc
      

      O resultado é semelhante ao seguinte:

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

    Instância pré-aprovisionada

    Crie a classe de armazenamento

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

    Quando volumeBindingMode está definido como Immediate, permite que o aprovisionamento do volume comece imediatamente.

    1. Crie o recurso StorageClass:

        kubectl create -f preprov-storageclass.yaml
      
    2. Verifique se a classe de armazenamento foi criada:

        kubectl get sc
      

      O resultado é semelhante ao seguinte:

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

    Crie um volume persistente para a instância do 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. Verifique se a instância do Filestore preexistente está pronta:

        gcloud filestore instances list
      

      A saída é semelhante à seguinte, em que o valor STATE é 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
      

      Tome nota do INSTANCE_NAME, LOCATION, FILE_SHARE_NAME e IP_ADDRESS da instância do Filestore.

    2. Preencha as variáveis da consola da instância do Filestore:

        INSTANCE_NAME=INSTANCE_NAME
        LOCATION=LOCATION
        FILE_SHARE_NAME=FILE_SHARE_NAME
        IP_ADDRESS=IP_ADDRESS
      
    3. Substitua as variáveis dos marcadores de posição pelas variáveis da consola obtidas acima no ficheiro 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. Crie a PV

        kubectl apply -f preprov-pv.yaml
      
    5. Verifique se o valor STATUS do PV está definido como Bound:

        kubectl get pv
      

      O resultado é semelhante ao seguinte:

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

    Use uma PersistentVolumeClaim para aceder ao volume

    O manifesto pvc.yaml seguinte faz referência ao controlador CSI do Filestore StorageClass denominado filestore-sc.

    Para que vários Pods leiam e escrevam no volume, o accessMode está definido como ReadWriteMany.

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

      kubectl create -f pvc.yaml
      
    2. Verifique se o PVC foi criado:

      kubectl get pvc
      

      O resultado é semelhante ao seguinte:

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

    Crie um Pod de leitor e um Pod de escritor

    Nesta secção, cria um Pod de leitura e um Pod de escrita. Este tutorial usa implementações do Kubernetes para criar os pods. Uma implementação é um objeto da API Kubernetes que lhe permite executar várias réplicas de pods distribuídos entre os nós num cluster.

    Crie o leitor Pod

    O pod de leitura lê o ficheiro que está a ser escrito pelos pods de escrita. Os pods de leitura veem a que horas e qual a réplica do pod de gravação que escreveu no ficheiro.

    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

    O agrupamento do leitor vai ler a partir do caminho /usr/share/nginx/html, que é partilhado entre todos os agrupamentos.

    1. Implemente o pod de leitor:

      kubectl apply -f reader-fs.yaml
      
    2. Confirme se a instância do Filestore recém-criada está pronta:

      gcloud filestore instances list
      

      O resultado é semelhante ao seguinte:

      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. Verifique se as réplicas de leitura estão em execução consultando a lista de pods:

      kubectl get pods
      

      O resultado é semelhante ao seguinte:

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

    Crie o pod de escritor

    O pod de gravação escreve periodicamente num ficheiro partilhado ao qual outros pods de gravação e leitura podem aceder. O pod de gravação regista a respetiva presença escrevendo o nome do anfitrião no ficheiro partilhado.

    A imagem usada para o pod do escritor é uma imagem personalizada do Alpine Linux, que é usada para utilitários e aplicações de produção. Inclui um script indexInfo.html que obtém os metadados do autor mais recente e mantém a contagem de todos os autores únicos e o total de edições.

    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

    Para este tutorial, o pod de gravação escreve a cada 30 segundos no caminho /html/index.html. Modifique o valor do número sleep para ter uma frequência de gravação diferente.

    1. Implemente o pod do escritor:

      kubectl apply -f writer-fs.yaml
      
    2. Verifique se os pods de gravação estão em execução consultando a lista de pods:

      kubectl get pods
      

      O resultado é semelhante ao seguinte:

      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
      

    Exponha e aceda à carga de trabalho do leitor a um balanceador de carga de serviço

    Para expor uma carga de trabalho fora do cluster, crie um serviço do tipo LoadBalancer. Este tipo de serviço cria um balanceador de carga externo com um endereço IP acessível através da Internet.

    1. Crie um serviço do tipo LoadBalancer com o nome reader-lb:

      kubectl create -f loadbalancer.yaml
      
    2. Monitorize a implementação para ver se o GKE atribui um EXTERNAL-IP ao serviço reader-lb:

      kubectl get svc --watch
      

      Quando o Service estiver pronto, a coluna EXTERNAL-IP apresenta o endereço IP público do 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. Prima Ctrl+C para terminar o processo de monitorização.

    4. Use um navegador de Internet para navegar para o EXTERNAL-IP atribuído ao equilibrador de carga. A página é atualizada a cada 30 segundos. Quanto mais escritores de posts e mais curta for a frequência, mais entradas são apresentadas.

    Para ver mais detalhes sobre o serviço de balanceamento de carga, consulte loadbalancer.yaml.

    Aumente a escala do compositor

    Uma vez que o PV accessMode foi definido como ReadWriteMany, o GKE pode aumentar o número de pods para que mais pods de gravação possam escrever neste volume partilhado (ou mais leitores possam lê-los).

    1. Aumente a escala do writer para cinco réplicas:

      kubectl scale deployment writer --replicas=5
      

      O resultado é semelhante ao seguinte:

      deployment.extensions/writer scaled
      
    2. Valide o número de réplicas em execução:

      kubectl get pods
      

      O resultado é semelhante ao seguinte:

      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. Use um navegador de Internet para navegar novamente para o EXTERNAL-IP atribuído ao equilibrador de carga.

    Neste ponto, configurou e dimensionou o cluster para suportar cinco pods de gravação com estado. Quando vários Pods de gravação estão a escrever no mesmo ficheiro em simultâneo. Os leitores Pods também podem ser facilmente expandidos.

    Opcional: aceda aos dados do pod de gravação

    Esta secção demonstra como usar uma interface de linha de comandos para aceder a um pod de leitura ou escrita. Pode ver o componente partilhado no qual o escritor está a escrever e o leitor está a ler.

    1. Obtenha o nome do agrupamento do escritor:

      kubectl get pods
      

      O resultado é semelhante ao seguinte:

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

      Tome nota do nome de anfitrião de um pod de gravação (exemplo: writer-5465d65b46-7hxv4).

    2. Execute o seguinte comando para aceder ao pod de gravação:

      kubectl exec -it WRITER_HOSTNAME -- /bin/sh
      
    3. Veja o componente partilhado no ficheiro indexData.html:

      cd /html
      cat indexData.html
      
    4. Limpe o ficheiro indexData.html:

      echo '' > indexData.html
      

      Atualize o navegador de Internet que aloja o endereço EXTERNAL-IP para ver a alteração.

    5. Saia do ambiente:

      exit
      

    Limpar

    Para evitar incorrer em custos na sua conta do Google Cloud pelos recursos usados neste tutorial, elimine o projeto que contém os recursos ou mantenha o projeto e elimine os recursos individuais.

    Elimine o projeto

    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.

    Elimine os recursos individuais

    1. Elimine o serviço do balanceador de carga:

      kubectl delete service reader-lb
      

      Aguarde até que o balanceador de carga aprovisionado para o serviço de leitor seja eliminado

    2. Verifique se a lista devolve Listed 0 items:

      gcloud compute forwarding-rules list
      
    3. Elimine as implementações

      kubectl delete deployment writer
      kubectl delete deployment reader
      
    4. Verifique se os Pods foram eliminados e devolve No resources found in default namespace.

      kubectl get pods
      
    5. Elimine o PVC. Esta ação também elimina o PV e a instância do Filestore devido à Política de Retenção definida como delete

      kubectl delete pvc fileserver
      
    6. Elimine o cluster do GKE:

      gcloud container clusters delete CLUSTER_NAME --location=CONTROL_PLANE_LOCATION
      

      Esta ação elimina os recursos que compõem o cluster do GKE, incluindo os pods de leitura e gravação.

    O que se segue?