Implantar uma carga de trabalho com estado usando o Filestore


Neste tutorial, mostramos como implantar uma carga de trabalho com estado simples de leitor/gravador usando umaVolume permanente (PV) e umaReivindicação de volume permanente (PVC) no Google Kubernetes Engine (GKE). Siga este tutorial para saber como projetar para escalonabilidade usando o Filestore, o sistema de arquivos de rede gerenciado do Google Cloud.

Experiência

Por natureza, os pods são temporários. Isso significa que o GKE destrói o estado e o valor armazenados em um pod quando é excluído, removido ou reprogramado.

Como um operador de aplicativo, talvez você queira manter cargas de trabalho com estado. Exemplos dessas cargas de trabalho incluem aplicativos que processam artigos do WordPress, apps de mensagens e aplicativos que processam operações de machine learning.

Ao usar o Filestore no GKE, é possível realizar as seguintes operações:

  • Implante cargas de trabalho com estado escalonáveis.
  • Ative vários pods para que eles tenham ReadWriteMany como accessMode. Assim, vários pods poderão ler e gravar ao mesmo tempo no mesmo armazenamento.
  • Configure o GKE para ativar volumes em vários pods simultaneamente.
  • Persistência de armazenamento quando os pods são removidos
  • Ative os pods para compartilhar dados e escalonar facilmente.

Objetivos

Este tutorial é destinado a operadores de aplicativos e outros usuários que querem configurar uma carga de trabalho com estado escalonável no GKE usando PVC e NFS.

Diagrama de GKE com carga de trabalho com estado

Este tutorial inclui as etapas a seguir:

  1. Criar um cluster do GKE.
  2. Configurar o armazenamento de arquivos gerenciados com o Filestore usando CSI.
  3. Criar um leitor e um pod de gravação.
  4. Expor e acessar o pod do leitor para um balanceador de carga de serviço;
  5. Aumente a escala do gravador.
  6. Acesse dados do pod de gravador.

Custos

Neste tutorial, usamos os seguintes componentes faturáveis do Google Cloud:

Use a calculadora de preços para gerar uma estimativa de custo com base no uso previsto.

Ao concluir este tutorial, exclua os recursos criados para evitar o faturamento contínuo. Para mais informações, consulte Limpeza.


Para seguir as instruções detalhadas desta tarefa diretamente no console do Google Cloud , clique em Orientação:

Orientações


Antes de começar

Criar o 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.

    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

  8. Definir padrões para a Google Cloud CLI

    1. No Google Cloud console, inicie uma instância do Cloud Shell:
      Abrir o Cloud Shell

    2. Faça o download do código-fonte para este app de amostra:

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

      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:

    Criar 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: o local do Compute Engine do plano de controle do cluster. Forneça uma região para clusters regionais ou uma zona para clusters zonais.

      Após a criação do cluster, o resultado será semelhante a este:

        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 a STATUS é RUNNING.

    Configurar o armazenamento de arquivos gerenciados com o Filestore usando CSI

    O GKE oferece uma maneira de implantar e gerenciar automaticamente o driver CSI do Kubernetes Filestore nos clusters. Usar o CSI do Filestore permite criar ou excluir instâncias do Filestore de forma dinâmica e usá-las nas cargas de trabalho do Kubernetes com um StorageClass ou Deployment.

    É possível criar uma nova instância do Filestore criando um PVC que provisione dinamicamente uma instância do Filestore e o PV ou acesse instâncias pré-provisionadas do Filestore em cargas de trabalho do Kubernetes.

    Nova instância

    Crie o 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 é definido como Immediate, o que permite o provisionamento do volume imediatamente.
    • tier é definido como standard para acelerar o tempo de criação da instância do Filestore. Se você precisar de mais armazenamento NFS disponível, snapshots para backup de dados, replicação de dados em várias zonas e outros recursos de nível empresarial, defina tier como enterprise. Observação: a política de reivindicação para PV criada dinamicamente será definida como Delete se o reclaimPolicy no StorageClass não estiver definido.
    1. Criar o recurso StorageClass:

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

      kubectl get sc
      

      O resultado será assim:

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

    Instância pré-provisionada

    Crie o StorageClass

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

    Quando volumeBindingMode é definido como Immediate, ele permite que o provisionamento do volume comece imediatamente.

    1. Criar o recurso StorageClass:

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

        kubectl get sc
      

      O resultado será assim:

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

    Criar um volume permanente 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 preexistente do Filestore está pronta:

        gcloud filestore instances list
      

      A resposta será semelhante a esta, 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
      

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

    2. Preencha as variáveis do console 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 de marcador pelas variáveis do console coletadas acima no arquivo 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. Criar o PV

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

        kubectl get pv
      

      O resultado será assim:

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

    Usar um PersistentVolumeClaim para acessar o volume

    O manifesto pvc.yaml a seguir faz referência ao StorageClass do driver CSI do Filestore chamado filestore-sc.

    Para que vários pods leiam e gravem 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. Implante o PVC:

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

      kubectl get pvc
      

      O resultado será assim:

      NAME         STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS        AGE
      fileserver   Bound    pvc-aadc7546-78dd-4f12-a909-7f02aaedf0c3   1Ti        RWX            filestore-sc        92m
      
    3. Verifique se a instância recém-criada do Filestore está pronta:

      gcloud filestore instances list
      

      O resultado será assim:

      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
      

    Criar um leitor e um pod de gravação

    Nesta seção, você vai criar um pod de leitura e um pod de gravação. Neste tutorial, usamos implantações do Kubernetes para criar os pods. Uma implantação é um objeto da API Kubernetes que permite executar várias réplicas de pods distribuídos entre os nós de um cluster.

    Criar o pod do leitor

    O pod do leitor vai ler o arquivo que está sendo gravado pelos pods de gravação. Os pods do leitor verão qual hora e qual réplica de pod de gravação escreveu no arquivo.

    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 pod do leitor vai ler o caminho /usr/share/nginx/html, que é compartilhado entre todos os pods.

    1. Implante o pod do leitor:

      kubectl apply -f reader-fs.yaml
      
    2. Consulte a lista de pods para verificar se as réplicas do leitor estão em execução:

      kubectl get pods
      

      O resultado será assim:

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

    Crie o pod do gravador

    O pod de gravador grava periodicamente em um arquivo compartilhado que outros pods de gravador e de leitor podem acessar. O pod de gravador grava a presença gravando o nome do host no arquivo compartilhado.

    A imagem usada para o pod do gravador é uma imagem personalizada do Alpine Linux, usada para utilitários e aplicativos de produção. Ela inclui um script indexInfo.html que receberá os metadados do gravador mais recente e manterá a contagem de todos os gravadores exclusivos e o total de gravaçõ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

    Neste tutorial, o pod de gravação grava 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. Implante o pod de gravador:

      kubectl apply -f writer-fs.yaml
      
    2. Consulte a lista de pods para verificar se eles estão em execução:

      kubectl get pods
      

      O resultado será assim:

      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
      

    Expor e acessar a carga de trabalho do leitor em um balanceador de carga de serviço

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

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

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

      kubectl get svc --watch
      

      Quando Service estiver pronto, a coluna EXTERNAL-IP exibirá 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. Pressione Ctrl+C para encerrar o processo de observação.

    4. Use um navegador da Web para navegar até o EXTERNAL-IP atribuído ao balanceador de carga. A página é atualizada a cada 30 segundos. Quanto mais pods de gravadores e menor a frequência, mais entradas serão exibidas.

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

    Escalone o gravador

    Como o PV accessMode foi definido como ReadWriteMany, o GKE pode escalonar o número de pods para que mais pods de gravação possam gravar nesse volume compartilhado (ou mais leitores podem ler para lê-los).

    1. Aumente os recursos do writer para cinco réplicas:

      kubectl scale deployment writer --replicas=5
      

      O resultado será assim:

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

      kubectl get pods
      

      O resultado será assim:

      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 da Web para navegar novamente para o EXTERNAL-IP atribuído ao balanceador de carga.

    Neste ponto, você configurou e escalonou seu cluster para aceitar cinco pods de gravador com estado. Onde vários pods de gravação estão gravando no mesmo arquivo simultaneamente. Os pods do leitor também podem ser escalonados facilmente.

    Opcional: acessar dados do pod de gravador

    Nesta seção, demonstramos como usar uma interface de linha de comando para acessar um pod de leitor ou de gravador. É possível ver o componente compartilhado em que o autor está escrevendo e o leitor está lendo.

    1. Consiga o nome do pod do gravador:

      kubectl get pods
      

      O resultado será assim:

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

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

    2. Execute o seguinte comando para acessar o pod de gravador:

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

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

      echo '' > indexData.html
      

      Atualize o navegador da Web que hospeda o endereço do EXTERNAL-IP para ver a alteração.

    5. Saia do ambiente:

      exit
      

    Limpar

    Para evitar cobranças na sua conta do Google Cloud pelos recursos usados no tutorial, exclua o projeto que os contém ou mantenha o projeto e exclua os recursos individuais.

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

    Excluir recursos individuais

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

      kubectl delete service reader-lb
      

      Aguarde até que o balanceador de carga provisionado para o serviço de leitor seja excluído

    2. Verifique se a lista retorna Listed 0 items:

      gcloud compute forwarding-rules list
      
    3. Excluir as implantações

      kubectl delete deployment writer
      kubectl delete deployment reader
      
    4. Verifique se os pods foram excluídos e retorne No resources found in default namespace.

      kubectl get pods
      
    5. Exclua a PVC. Isso também excluirá o PV e a instância do Filestore devido à política de retenção definida como delete

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

      gcloud container clusters delete CLUSTER_NAME --location=CONTROL_PLANE_LOCATION
      

      Isso exclui os recursos que compõem o cluster do GKE, incluindo os pods de leitor e de gravação.

    A seguir