Acelere o carregamento de dados de IA/ML com o Hyperdisk ML

Este guia aborda como simplificar e acelerar o carregamento de ponderações de modelos de IA/AA no Google Kubernetes Engine (GKE) através do Hyperdisk ML. O controlador CSI do Persistent Disk do Compute Engine é a principal forma de aceder ao armazenamento de ML do Hyperdisk com clusters do GKE.

Vista geral

O Hyperdisk ML é uma solução de armazenamento de alto desempenho que pode ser usada para escalar horizontalmente as suas aplicações. Oferece um elevado débito agregado a muitas máquinas virtuais em simultâneo, o que o torna ideal se quiser executar cargas de trabalho de IA/AA que precisam de acesso a grandes quantidades de dados.

Quando ativado no modo de leitura para muitos, pode usar o Hyperdisk ML para acelerar o carregamento dos pesos dos modelos até 11,9 vezes em relação ao carregamento diretamente a partir de um registo de modelos. Esta aceleração é possível graças à arquitetura do Google Cloud Hyperdisk que permite escalar para 2500 nós simultâneos a 1,2 TiB/s. Isto permite-lhe gerar melhores tempos de carregamento e reduzir o aprovisionamento excessivo de pods para as suas cargas de trabalho de inferência de IA/ML.

Os passos de nível elevado para criar e usar o Hyperdisk ML são os seguintes:

  1. Pré-armazenar em cache ou preencher dados numa imagem de disco de disco persistente: carregue volumes do Hyperdisk ML com dados de uma origem de dados externa (por exemplo, ponderações do Gemma carregadas a partir do Cloud Storage) que podem ser usados para publicação. O Persistent Disk para a imagem do disco tem de ser compatível com o Google Cloud Hyperdisk.
  2. Crie um volume de ML do Hyperdisk usando um Google Cloud Hyperdisk pré-existente: crie um volume do Kubernetes que faça referência ao volume de ML do Hyperdisk carregado com dados. Opcionalmente, pode criar classes de armazenamento multizona para garantir que os seus dados estão disponíveis em todas as zonas em que os seus pods vão ser executados.
  3. Crie uma implementação do Kubernetes para consumir o volume de ML do Hyperdisk: faça referência ao volume de ML do Hyperdisk com o carregamento de dados acelerado para as suas aplicações consumirem.

Volumes de ML de Hyperdisk multizona

Os discos de ML Hyperdisk só estão disponíveis numa única zona. Opcionalmente, pode usar a funcionalidade multizona do Hyperdisk ML para associar dinamicamente vários discos zonais que contêm o mesmo conteúdo num único PersistentVolumeClaim e PersistentVolume lógico. Os discos zonais referenciados pela funcionalidade de várias zonas têm de estar localizados na mesma região. Por exemplo, se o cluster regional for criado em us-central1, os discos multizona têm de estar localizados na mesma região (por exemplo, us-central1-a e us-central1-b).

Um exemplo de utilização comum para a inferência de IA/AM é executar pods em várias zonas para melhorar a disponibilidade dos aceleradores e a rentabilidade com VMs Spot. Uma vez que o Hyperdisk ML é zonal, se o seu servidor de inferência executar muitos pods em várias zonas, o GKE clona automaticamente os discos em várias zonas para garantir que os seus dados seguem a sua aplicação.

Atualização do Hyperdisk ML a partir de origens de dados externas e criação de PVs multizonais para aceder aos dados em várias zonas.

Os volumes de ML Hyperdisk multizona têm as seguintes limitações:

  • As operações de redimensionamento e instantâneos de volume não são suportadas.
  • Os volumes de ML Hyperdisk multizona só são suportados no modo de leitura.
  • Quando usa discos pré-existentes com um volume de ML do Hyperdisk de várias zonas, o GKE não realiza verificações para validar se o conteúdo do disco em todas as zonas é o mesmo. Se algum dos discos contiver conteúdo divergente, certifique-se de que a sua aplicação tem em conta a potencial inconsistência entre zonas.

Para saber mais, consulte o artigo Crie um volume ML Hyperdisk ReadOnlyMany de várias zonas a partir de um VolumeSnapshot.

Antes de começar

Antes de começar, certifique-se de que realizou as seguintes tarefas:

  • Ative a API Google Kubernetes Engine.
  • Ative a API Google Kubernetes Engine
  • Se quiser usar a CLI gcloud para esta tarefa, instale-a e, em seguida, inicialize-a. Se instalou anteriormente a CLI gcloud, execute gcloud components update para obter a versão mais recente.
  • Defina a região e a zona predefinidas para um dos valores suportados.
  • Certifique-se de que o seu Trusted Cloud projeto tem quota suficiente para criar os nós necessários neste guia. O código de exemplo para a criação de recursos do cluster do GKE e do Kubernetes requer a seguinte quota mínima na região à sua escolha: 88 CPUs C3 e 8 GPUs NVIDIA L4.

Requisitos

Para usar volumes de ML do Hyperdisk no GKE, os seus clusters têm de cumprir os seguintes requisitos:

  • Use clusters Linux com a versão 1.30.2-gke.1394000 ou posterior do GKE. Se usar um canal de lançamento, certifique-se de que o canal tem a versão mínima do GKE ou posterior que é necessária para este controlador.
  • Certifique-se de que o controlador CSI do Persistent Disk do Compute Engine está ativado. O controlador de disco persistente do Compute Engine está ativado por predefinição em novos clusters do Autopilot e Standard, e não pode ser desativado nem editado quando usa o Autopilot. Se precisar de ativar o controlador CSI do Persistent Disk do Compute Engine a partir do cluster, consulte o artigo Ativar o controlador CSI do Persistent Disk do Compute Engine num cluster existente.
  • Se quiser ajustar o valor de leitura antecipada, use a versão 1.29.2-gke.1217000 ou posterior do GKE.
  • Se quiser usar a funcionalidade de aprovisionamento dinâmico de várias zonas, use a versão 1.30.2-gke.1394000 ou posterior do GKE.
  • O Hyperdisk ML só é suportado em determinados tipos de nós e zonas. Para saber mais, consulte o artigo Acerca do Hyperdisk ML na documentação do Compute Engine.

Aceda ao modelo

Para aceder aos modelos Gemma para implementação no GKE, primeiro tem de assinar o contrato de consentimento de licença e, em seguida, gerar um token de acesso do Hugging Face.

Tem de assinar o contrato de consentimento para usar o Gemma. Siga estas instruções:

  1. Aceda à página de consentimento do modelo em Kaggle.com.
  2. Valide o consentimento através da sua conta do Hugging Face.
  3. Aceite os termos do modelo.

Gere um token de acesso

Para aceder ao modelo através do Hugging Face, precisa de um token do Hugging Face.

Siga estes passos para gerar um novo token se ainda não tiver um:

  1. Clique em O seu perfil > Definições > Tokens de acesso.
  2. Selecione Novo token.
  3. Especifique um nome à sua escolha e uma função de, pelo menos, Read.
  4. Selecione Gerar um token.
  5. Copie o token gerado para a área de transferência.

Crie um cluster do GKE

Pode publicar MDIs em GPUs num cluster padrão ou do GKE Autopilot. Recomendamos que use um cluster do Autopilot para uma experiência do Kubernetes totalmente gerida. Para escolher o modo de funcionamento do GKE mais adequado às suas cargas de trabalho, consulte o artigo Escolha um modo de funcionamento do GKE.

Piloto automático

  1. No Cloud Shell, execute o seguinte comando:

    gcloud container clusters create-auto hdml-gpu-l4 \
      --project=PROJECT \
      --location=CONTROL_PLANE_LOCATION \
      --release-channel=rapid \
      --cluster-version=1.30.2-gke.1394000
    

    Substitua os seguintes valores:

    • PROJECT: o Trusted Cloud by S3NS ID do projeto.
    • CONTROL_PLANE_LOCATION: a região do Compute Engine do plano de controlo do seu cluster. Indique uma região que suporte o tipo de acelerador que quer usar, por exemplo, us-east4 para a GPU L4.

    O GKE cria um cluster do Autopilot com nós de CPU e GPU, conforme solicitado pelas cargas de trabalho implementadas.

  2. Configure kubectl para comunicar com o cluster:

    gcloud container clusters get-credentials hdml-gpu-l4 \
      --location=CONTROL_PLANE_LOCATION
    

Standard

  1. No Cloud Shell, execute o seguinte comando para criar um cluster padrão e node pools:

    gcloud container clusters create hdml-gpu-l4 \
        --location=CONTROL_PLANE_LOCATION \
        --num-nodes=1 \
        --machine-type=c3-standard-44 \
        --release-channel=rapid \
        --cluster-version=CLUSTER_VERSION \
        --node-locations=ZONES \
        --project=PROJECT
    
    gcloud container node-pools create gpupool \
        --accelerator type=nvidia-l4,count=2,gpu-driver-version=latest \
        --location=CONTROL_PLANE_LOCATION \
        --project=PROJECT \
        --node-locations=ZONES \
        --cluster=hdml-gpu-l4 \
        --machine-type=g2-standard-24 \
        --num-nodes=2
    

    Substitua os seguintes valores:

    • CLUSTER_VERSION: a versão do seu cluster do GKE (por exemplo, 1.30.2-gke.1394000).
    • CONTROL_PLANE_LOCATION: a localização do Compute Engine do plano de controlo do seu cluster. Para clusters regionais, indique uma região com uma zona que suporte o acelerador que quer usar. Para clusters zonais, indique uma zona que suporte o acelerador que quer usar. Para verificar onde estão disponíveis aceleradores específicos, consulte o artigo Disponibilidade de GPUs por regiões e zonas.
    • ZONES: as zonas nas quais os nós são criados. Pode especificar quantas zonas forem necessárias para o seu cluster. Todas as zonas têm de estar na mesma região que o plano de controlo do cluster, especificado pela flag --location. Para clusters zonais, --node-locations tem de conter a zona principal do cluster.
    • PROJECT: o Trusted Cloud by S3NS ID do projeto.

    A criação do cluster pode demorar vários minutos.

  2. Configure kubectl para comunicar com o cluster:

    gcloud container clusters get-credentials hdml-gpu-l4
    

Pré-cache dados numa imagem de disco do Persistent Disk

Para usar o Hyperdisk ML, pré-armazena dados em cache numa imagem de disco e cria um volume do Hyperdisk ML para acesso de leitura pela sua carga de trabalho no GKE. Esta abordagem (também denominada preenchimento de dados) garante que os seus dados estão disponíveis quando a sua carga de trabalho precisar deles.

Os passos seguintes descrevem como copiar manualmente dados de uma origem, como o repositório do Hugging Face, diretamente para um volume de ML do Hyperdisk através de um trabalho do Kubernetes.

Se os seus dados já estiverem num contentor do Cloud Storage, pode usar o Hyperdisk ML para automatizar a transferência de dados do Cloud Storage para o Hyperdisk ML. Isto elimina a necessidade dos passos de criação manual de tarefas descritos nas secções seguintes.

Crie uma StorageClass que suporte o Hyperdisk ML

  1. Guarde o seguinte manifesto StorageClass num ficheiro com o nome hyperdisk-ml.yaml.

    apiVersion: storage.k8s.io/v1
    kind: StorageClass
    metadata:
        name: hyperdisk-ml
    parameters:
        type: hyperdisk-ml
        provisioned-throughput-on-create: "2400Mi"
    provisioner: pd.csi.storage.gke.io
    allowVolumeExpansion: false
    reclaimPolicy: Delete
    volumeBindingMode: WaitForFirstConsumer
    mountOptions:
      - read_ahead_kb=4096
    
  2. Execute este comando para criar a StorageClass:

    kubectl create -f hyperdisk-ml.yaml
    

Crie um PersistentVolumeClaim (PVC) ReadWriteOnce (RWO)

  1. Guarde o seguinte manifesto PersistentVolumeClaim num ficheiro com o nome producer-pvc.yaml. Vai usar a StorageClass que criou anteriormente. Este PVC usa o modo de acesso ReadWriteOnce porque é usado por um trabalho do Kubernetes para transferir dados do modelo para o disco persistente, o que requer acesso de escrita. O modo de acesso ReadWriteMany não é suportado pelo Google Cloud Hyperdisk. Certifique-se de que o disco tem capacidade suficiente para armazenar os seus dados.

    kind: PersistentVolumeClaim
    apiVersion: v1
    metadata:
      name: producer-pvc
    spec:
      storageClassName: hyperdisk-ml
      accessModes:
      - ReadWriteOnce
      resources:
        requests:
          storage: 300Gi
    
  2. Execute este comando para criar o PersistentVolumeClaim:

    kubectl create -f producer-pvc.yaml
    

Crie um trabalho do Kubernetes para preencher o volume do Google Cloud Hyperdisk montado

Esta secção mostra um exemplo de criação de uma tarefa do Kubernetes que aprovisiona um disco e transfere o modelo ajustado de instruções Gemma 7B do Hugging Face para o volume do Google Cloud Hyperdisk montado.

  1. Para aceder ao MDG do Gemma usado nos exemplos deste guia, crie um segredo do Kubernetes que contenha o token do Hugging Face:

    kubectl create secret generic hf-secret \
        --from-literal=hf_api_token=HF_TOKEN\
        --dry-run=client -o yaml | kubectl apply -f -
    

    Substitua HF_TOKEN pelo token do Hugging Face que gerou anteriormente.

  2. Guarde o seguinte manifesto de exemplo como producer-job.yaml:

    apiVersion: batch/v1
    kind: Job
    metadata:
      name: producer-job
    spec:
      template:
        spec:
          affinity:
            # Node affinity ensures that Pods are scheduled on the nodes that support Hyperdisk ML.
            nodeAffinity:
              requiredDuringSchedulingIgnoredDuringExecution:
                nodeSelectorTerms:
                - matchExpressions:
                  # Specifies the Performance compute class. For more information,
                  # see https://cloud.google.com/kubernetes-engine/docs/concepts/autopilot-compute-classes#when-to-use.
                  - key: cloud.google.com/compute-class
                    operator: In
                    values:
                    - "Performance"
                - matchExpressions:
                  - key: cloud.google.com/machine-family
                    operator: In
                    values:
                    - "c3"
                - matchExpressions:
                  # Restricts Pod scheduling to a specific zone because Hyperdisk ML disks
                  # are a zonal resource.
                  - key: topology.kubernetes.io/zone
                    operator: In
                    values:
                    - "ZONE"
          containers:
          - name: copy
            resources:
              requests:
                cpu: "32"
              limits:
                cpu: "32"
             # The image used to download models from Hugging Face.
            image: huggingface/downloader:0.17.3
            command: [ "huggingface-cli" ]
            args:
            - download
            # The Hugging Face model to download.
            - google/gemma-1.1-7b-it
            # Destination directory within the container.
            - --local-dir=/data/gemma-7b
            - --local-dir-use-symlinks=False
            env:
            - name: HUGGING_FACE_HUB_TOKEN
              valueFrom:
                secretKeyRef:
                  name: hf-secret
                  key: hf_api_token
            volumeMounts:
              # Mount path for the PersistentVolume.
              - mountPath: "/data"
                name: volume
          # Prevents Pod restarts on scheduling failures. The Job will create new Pods
          # for retries, up to the specified "backoffLimit".
          restartPolicy: Never
          volumes:
            - name: volume
              persistentVolumeClaim:
                # References the Hyperdisk ML PVC created earlier.
                claimName: producer-pvc
      # Runs only one Pod at any given time.
      parallelism: 1
      # After the Pod runs successfully, the Job is complete.
      completions: 1
      # Max retries on Pod failure.
      backoffLimit: 4
    

    Substitua ZONE pela zona de computação onde quer criar o Hyperdisk. Se o estiver a usar com o exemplo de implementação, certifique-se de que é uma zona com capacidade de máquinas G2.

  3. Execute este comando para criar a tarefa:

    kubectl apply -f producer-job.yaml
    

    A tarefa pode demorar alguns minutos a concluir a cópia dos dados para o volume do disco persistente. Quando a tarefa conclui o aprovisionamento, o respetivo estado é marcado como "Concluído".

  4. Para verificar o progresso do estado da tarefa, execute o seguinte comando:

    kubectl get job producer-job
    
  5. Quando a tarefa estiver concluída, pode limpar a tarefa executando este comando:

    kubectl delete job producer-job
    

Crie um volume de ML Hyperdisk ReadOnlyMany a partir de um Hyperdisk do Google Cloud pré-existente

Esta secção aborda os passos para criar um par ReadOnlyMany (ROM) PersistentVolume e PersistentVolumeClaim a partir de um volume do Google Cloud Hyperdisk pré-existente. Para saber mais, consulte o artigo Usar discos persistentes pré-existentes como PersistentVolumes.

  1. Na versão 1.30.2-gke.1394000 e posteriores do GKE, o GKE converte automaticamente o modo de acesso de um volume do Google Cloud Hyperdisk para READ_ONLY_MANY.READ_WRITE_SINGLE

    Se estiver a usar um volume do Google Cloud Hyperdisk pré-existente numa versão anterior do GKE, tem de modificar o modo de acesso manualmente executando o seguinte comando:

    gcloud compute disks update HDML_DISK_NAME \
        --zone=ZONE \
        --access-mode=READ_ONLY_MANY
    

    Substitua os seguintes valores:

    • HDML_DISK_NAME: o nome do seu volume do Hyperdisk ML.
    • ZONE: a zona de computação onde o volume do Hyperdisk do Google Cloud pré-existente é criado.
  2. Crie um par PersistentVolume e PersistentVolumeClaim, referenciando o disco que preencheu anteriormente.

    1. Guarde o seguinte manifesto como hdml-static-pv.yaml:

      apiVersion: v1
      kind: PersistentVolume
      metadata:
        name: hdml-static-pv
      spec:
        storageClassName: "hyperdisk-ml"
        capacity:
          storage: 300Gi
        # The "ReadOnlyMany" access mode allows the volume to be mounted by multiple
        # nodes for read-only access.
        accessModes:
          - ReadOnlyMany
        # ClaimRef links this PersistentVolume to a PersistentVolumeClaim.
        claimRef:
          namespace: default
          name: hdml-static-pvc
        csi:
          driver: pd.csi.storage.gke.io
          # The unique identifier of the Compute Engine disk resource backing
          # this volume.
          volumeHandle: projects/PROJECT/zones/ZONE/disks/DISK_NAME
          fsType: ext4
          readOnly: true
        # Node affinity ensures that Pod is scheduled in a zone where the volume
        # is replicated.
        nodeAffinity:
          required:
            nodeSelectorTerms:
            - matchExpressions:
              - key: topology.gke.io/zone
                operator: In
                values:
                - ZONE
      ---
      apiVersion: v1
      kind: PersistentVolumeClaim
      metadata:
        namespace: default
        name: hdml-static-pvc
      spec:
        storageClassName: "hyperdisk-ml"
        volumeName: hdml-static-pv
        accessModes:
        - ReadOnlyMany
        resources:
          requests:
            storage: 300Gi
      

      Substitua os seguintes valores:

      • PROJECT: o projeto onde o cluster do GKE é criado.
      • ZONE: a zona onde o volume do Hyperdisk do Google Cloud preexistente é criado.
      • DISK_NAME: o nome do volume do Hyperdisk do Google Cloud pré-existente.
    2. Execute este comando para criar os recursos PersistentVolume e PersistentVolumeClaim:

      kubectl apply -f hdml-static-pv.yaml
      

Crie um volume de ML Hyperdisk ReadOnlyMany de várias zonas a partir de um VolumeSnapshot

Esta secção aborda os passos para criar um volume de ML do Hyperdisk no modo de acesso ReadOnlyMany. Usa um VolumeSnapshot para uma imagem de disco do Persistent Disk pré-existente. Para saber mais, consulte o artigo Crie uma cópia de segurança do armazenamento do disco persistente com instantâneos de volumes.

Para criar o volume de ML do Hyperdisk multizonal, siga estes passos:

Crie um VolumeSnapshot do seu disco

  1. Guarde o seguinte manifesto como um ficheiro denominado disk-image-vsc.yaml.

    apiVersion: snapshot.storage.k8s.io/v1
    kind: VolumeSnapshotClass
    metadata:
      name: disk-image-vsc
    driver: pd.csi.storage.gke.io
    # The snapshot will be deleted when the "VolumeSnapshot" object is deleted.
    deletionPolicy: Delete
    parameters:
      snapshot-type: images
    
  2. Crie o VolumeSnapshotClass executando o seguinte comando:

    kubectl apply -f disk-image-vsc.yaml
    
  3. Guarde o seguinte manifesto como um ficheiro denominado my-snapshot.yaml. Vai fazer referência ao PersistentVolumeClaim que criou anteriormente em Crie um PersistentVolumeClaim (RWO) ReadWriteOnce.

    apiVersion: snapshot.storage.k8s.io/v1
    kind: VolumeSnapshot
    metadata:
      name: my-snapshot
    spec:
      volumeSnapshotClassName: disk-image-vsc
      source:
        # The name of the PersistentVolumeClaim to snapshot.
        persistentVolumeClaimName: producer-pvc
    
  4. Crie o VolumeSnapshot executando o seguinte comando:

    kubectl apply -f my-snapshot.yaml
    
  5. Quando o VolumeSnapshot estiver marcado como "Pronto", execute o seguinte comando para criar o volume de ML do Hyperdisk:

    kubectl wait --for=jsonpath='{.status.readyToUse}'=true \
        --timeout=300s volumesnapshot my-snapshot
    

Crie uma StorageClass multizona

Se quiser que as cópias dos seus dados estejam acessíveis em mais do que uma zona, especifique o parâmetro enable-multi-zone-provisioning na StorageClass, que cria discos nas zonas especificadas no campo allowedTopologies.

Para criar a StorageClass, siga estes passos:

  1. Guarde o seguinte manifesto como um ficheiro denominado hyperdisk-ml-multi-zone.yaml.

    apiVersion: storage.k8s.io/v1
    kind: StorageClass
    metadata:
      name: hyperdisk-ml-multi-zone
    parameters:
      type: hyperdisk-ml
      provisioned-throughput-on-create: "4800Mi"
      enable-multi-zone-provisioning: "true"
    provisioner: pd.csi.storage.gke.io
    allowVolumeExpansion: false
    reclaimPolicy: Delete
    volumeBindingMode: Immediate
    allowedTopologies:
    - matchLabelExpressions:
      - key: topology.gke.io/zone
        values:
        - ZONE_1
        - ZONE_2
    mountOptions:
      - read_ahead_kb=8192
    

    Substitua ZONE_1, ZONE_2, ..., ZONE_N pelas zonas onde o seu armazenamento pode ser acedido.

    Este exemplo define o volumeBindingMode como Immediate, o que permite ao GKE aprovisionar o PersistentVolumeClaim antes de qualquer consumidor fazer referência ao mesmo.

  2. Execute o seguinte comando para criar a StorageClass:

    kubectl apply -f hyperdisk-ml-multi-zone.yaml
    

Crie um PersistentVolumeClaim que use a StorageClass multizona

O passo seguinte é criar um PersistentVolumeClaim que faça referência à StorageClass.

O GKE usa o conteúdo da imagem do disco especificada para aprovisionar automaticamente um volume do Hyperdisk ML em cada zona especificada na sua captura de ecrã.

Para criar o PersistentVolumeClaim, siga estes passos:

  1. Guarde o seguinte manifesto como um ficheiro denominado hdml-consumer-pvc.yaml.

    kind: PersistentVolumeClaim
    apiVersion: v1
    metadata:
      name: hdml-consumer-pvc
    spec:
      # Specifies that the new PersistentVolumeClaim should be provisioned from the
      # contents of the volume snapshot named "my-snapshot".
      dataSource:
        name: my-snapshot
        kind: VolumeSnapshot
        apiGroup: snapshot.storage.k8s.io
      accessModes:
      - ReadOnlyMany
      storageClassName: hyperdisk-ml-multi-zone
      resources:
        requests:
          storage: 300Gi
    
  2. Crie o PersistentVolumeClaim executando o seguinte comando:

    kubectl apply -f hdml-consumer-pvc.yaml
    

Crie uma implementação para consumir o volume de ML do Hyperdisk

Quando usar pods com volumes persistentes, recomendamos que use um controlador de carga de trabalho (como uma implementação ou um StatefulSet).

Se quiser usar um PersistentVolume pré-existente no modo ReadOnlyMany com uma implementação, consulte o artigo Use discos persistentes com vários leitores.

Para criar e testar a implementação, siga estes passos:

  1. Guarde o seguinte manifesto de exemplo como vllm-gemma-deployment.

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: vllm-gemma-deployment
    spec:
      replicas: 2
      selector:
        # Labels used to select the Pods managed by this Deployment.
        matchLabels:
          app: gemma-server
      template:
        metadata:
          labels:
            app: gemma-server
            # Labels for AI/GKE integration.
            ai.gke.io/model: gemma-7b
            ai.gke.io/inference-server: vllm
        spec:
          affinity:
            # Node affinity ensures Pods run on nodes with L4 GPUs.
            nodeAffinity:
              requiredDuringSchedulingIgnoredDuringExecution:
                nodeSelectorTerms:
                - matchExpressions:
                  - key: cloud.google.com/gke-accelerator
                    operator: In
                    values:
                    - nvidia-l4
            # Pod anti-affinity prefers scheduling Pods in different zones for
            # higher availability.
            podAntiAffinity:
              preferredDuringSchedulingIgnoredDuringExecution:
              - weight: 100
                podAffinityTerm:
                  labelSelector:
                    matchExpressions:
                    - key: app
                      operator: In
                      values:
                      - gemma-server
                  topologyKey: topology.kubernetes.io/zone
          containers:
          - name: inference-server
            # The container image for the vLLM inference server.
            image: us-docker.pkg.dev/vertex-ai/vertex-vision-model-garden-dockers/pytorch-vllm-serve:latest
            resources:
              requests:
                cpu: "2"
                memory: "25Gi"
                ephemeral-storage: "25Gi"
                nvidia.com/gpu: 2
              limits:
                cpu: "2"
                memory: "25Gi"
                ephemeral-storage: "25Gi"
                nvidia.com/gpu: 2
            # Command to run the vLLM API server.
            command: ["python3", "-m", "vllm.entrypoints.api_server"]
            args:
            # Specifies the model to load, using an environment variable.
            - --model=$(MODEL_ID)
            - --tensor-parallel-size=2
            env:
            # Environment variable to define the model path.
            - name: MODEL_ID
              value: /models/gemma-7b
            volumeMounts:
            - mountPath: /dev/shm
              name: dshm
            # Mount point for the Hyperdisk ML volume containing the model.
            - mountPath: /models
              name: gemma-7b
          volumes:
          - name: dshm
            emptyDir:
                medium: Memory
          - name: gemma-7b
            # References the PersistentVolumeClaim for the Hyperdisk ML volume.
            persistentVolumeClaim:
              claimName: CLAIM_NAME
    ---
    apiVersion: v1
    kind: Service
    metadata:
      name: llm-service
    spec:
      # Selects Pods with the label "app: gemma-server".
      selector:
        app: gemma-server
      # The "ClusterIP" field makes the Service reachable only within the cluster.
      type: ClusterIP
      ports:
        - protocol: TCP
          port: 8000
          targetPort: 8000
    

    Substitua CLAIM_NAME por um destes valores:

    • hdml-static-pvc: se estiver a usar um volume de ML do Hyperdisk a partir de um Hyperdisk do Google Cloud existente.
    • hdml-consumer-pvc: se estiver a usar um volume de ML do Hyperdisk a partir de uma imagem de disco VolumeSnapshot.
  2. Execute o seguinte comando para aguardar que o servidor de inferência fique disponível:

    kubectl wait --for=condition=Available --timeout=700s deployment/vllm-gemma-deployment
    
  3. Para testar se o servidor vLLM está em funcionamento, siga estes passos:

    1. Execute o seguinte comando para configurar o encaminhamento de portas para o modelo:

      kubectl port-forward service/llm-service 8000:8000
      
    2. Execute um comando curl para enviar um pedido ao modelo:

      USER_PROMPT="I'm new to coding. If you could only recommend one programming language to start with, what would it be and why?"
      
      curl -X POST http://localhost:8000/generate \
      -H "Content-Type: application/json" \
      -d @- <<EOF
      {
          "prompt": "<start_of_turn>user\n${USER_PROMPT}<end_of_turn>\n",
          "temperature": 0.90,
          "top_p": 1.0,
          "max_tokens": 128
      }
      EOF
      

    A saída seguinte mostra um exemplo da resposta do modelo:

    {"predictions":["Prompt:\n<start_of_turn>user\nI'm new to coding. If you could only recommend one programming language to start with, what would it be and why?<end_of_turn>\nOutput:\nPython is often recommended for beginners due to its clear, readable syntax, simple data types, and extensive libraries.\n\n**Reasons why Python is a great language for beginners:**\n\n* **Easy to read:** Python's syntax is straightforward and uses natural language conventions, making it easier for beginners to understand the code.\n* **Simple data types:** Python has basic data types like integers, strings, and lists that are easy to grasp and manipulate.\n* **Extensive libraries:** Python has a vast collection of well-documented libraries covering various tasks, allowing beginners to build projects without reinventing the wheel.\n* **Large supportive community:**"]}
    

Ajuste o valor de leitura antecipada

Se tiver cargas de trabalho que executam E/S sequenciais, podem beneficiar da otimização do valor de leitura antecipada. Isto aplica-se normalmente a cargas de trabalho de inferência ou preparação que precisam de carregar pesos de modelos de IA/ML na memória. A maioria das cargas de trabalho com E/S sequencial normalmente observa uma melhoria no desempenho com um valor de leitura antecipada de 1024 KB ou superior.

Ajuste o valor de leitura antecipada para novos volumes

Pode especificar esta opção adicionando read_ahead_kb ao campo mountOptions na sua StorageClass. O exemplo seguinte mostra como pode ajustar o valor de leitura antecipada para 4096 KB. Isto aplica-se a novos volumes persistentes aprovisionados dinamicamente criados com a hyperdisk-ml StorageClass.

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
    name: hyperdisk-ml
parameters:
    type: hyperdisk-ml
provisioner: pd.csi.storage.gke.io
allowVolumeExpansion: false
reclaimPolicy: Delete
volumeBindingMode: WaitForFirstConsumer
mountOptions:
  - read_ahead_kb=4096

Ajuste o valor de leitura antecipada para volumes existentes

Para volumes aprovisionados estaticamente ou PersistentVolumes pré-existentes, pode especificar esta opção adicionando read_ahead_kb ao campo spec.mountOptions. O exemplo seguinte mostra como pode ajustar o valor de leitura antecipada para 4096 KB.

apiVersion: v1
kind: PersistentVolume
  name: DISK_NAME
spec:
  accessModes:
  - ReadOnlyMany
  capacity:
    storage: 300Gi
  csi:
    driver: pd.csi.storage.gke.io
    fsType: ext4
    readOnly: true
    # The unique identifier of the Compute Engine disk resource backing this volume.
    volumeHandle: projects/PROJECT/zones/ZONE/disks/DISK_NAME
  # Node affinity ensures that Pods are scheduled in the zone where the volume exists.
  nodeAffinity:
    required:
      nodeSelectorTerms:
      - matchExpressions:
        - key: topology.gke.io/zone
          operator: In
          values:
          - ZONE
  storageClassName: hyperdisk-ml
  mountOptions:
  - read_ahead_kb=4096

Substitua os seguintes valores:

  • DISK_NAME: o nome do volume do Hyperdisk do Google Cloud pré-existente.
  • ZONE: a zona onde o volume do Hyperdisk do Google Cloud preexistente é criado.

Teste e compare o desempenho do volume de ML do Hyperdisk

Esta secção mostra como pode usar o Flexible I/O Tester (FIO) para testar o desempenho dos seus volumes de ML do Hyperdisk para ler dados pré-existentes . Pode usar estas métricas para avaliar o desempenho do volume para cargas de trabalho e configurações específicas.

  1. Guarde o seguinte manifesto de exemplo como benchmark-job.yaml:

    apiVersion: batch/v1
    kind: Job
    metadata:
      name: benchmark-job
    spec:
      template:  # Template for the Pods the Job will create.
        spec:
          affinity:
            nodeAffinity:
              requiredDuringSchedulingIgnoredDuringExecution:
                nodeSelectorTerms:
                - matchExpressions:
                  - key: cloud.google.com/compute-class
                    operator: In
                    values:
                    - "Performance"
                - matchExpressions:
                  - key: cloud.google.com/machine-family
                    operator: In
                    values:
                    - "c3"
    
          containers:
          - name: fio
            resources:
              requests:
                cpu: "32"
            image: litmuschaos/fio
            args:
            - fio
            # Specifies the files to use for the benchmark. Multiple files can be separated by colons.
            - --filename
            - /models/gemma-7b/model-00001-of-00004.safetensors:/models/gemma-7b/model-00002-of-00004.safetensors:/models/gemma-7b/model-00003-of-00004.safetensors:/models/gemma-7b/model-00004-of-00004.safetensors:/models/gemma-7b/model-00004-of-00004.safetensors
            # Use non-buffered I/O.
            - --direct=1
            # Set the I/O pattern to read.
            - --rw=read
            # Open files in read-only mode.
            - --readonly
            # Block size for I/O operations.
            - --bs=4096k
            # I/O engine to use.
            - --ioengine=libaio
            # Number of I/O units to keep in flight against each file.
            - --iodepth=8
            # Duration of the test in seconds.
            - --runtime=60
            # Number of jobs to run.
            - --numjobs=1
            # Name of the job.
            - --name=read_benchmark
            volumeMounts:
            - mountPath: "/models"
              name: volume
          restartPolicy: Never
          volumes:
          - name: volume
            persistentVolumeClaim:
              claimName: hdml-static-pvc
      parallelism: 1
      completions: 1
      backoffLimit: 1
    

    Substitua CLAIM_NAME pelo nome do seu PersistentVolumeClaim (por exemplo, hdml-static-pvc).

  2. Crie a tarefa executando o seguinte comando:

    kubectl apply -f benchmark-job.yaml.
    
  3. Use os registos kubectl para ver o resultado da ferramenta fio:

    kubectl logs benchmark-job-nrk88 -f
    

    O resultado tem um aspeto semelhante ao seguinte:

    read_benchmark: (g=0): rw=read, bs=4M-4M/4M-4M/4M-4M, ioengine=libaio, iodepth=8
    fio-2.2.10
    Starting 1 process
    
    read_benchmark: (groupid=0, jobs=1): err= 0: pid=32: Fri Jul 12 21:29:32 2024
    read : io=18300MB, bw=2407.3MB/s, iops=601, runt=  7602msec
        slat (usec): min=86, max=1614, avg=111.17, stdev=64.46
        clat (msec): min=2, max=33, avg=13.17, stdev= 1.08
        lat (msec): min=2, max=33, avg=13.28, stdev= 1.06
        clat percentiles (usec):
        |  1.00th=[11072],  5.00th=[12352], 10.00th=[12608], 20.00th=[12736],
        | 30.00th=[12992], 40.00th=[13120], 50.00th=[13248], 60.00th=[13376],
        | 70.00th=[13504], 80.00th=[13632], 90.00th=[13888], 95.00th=[14016],
        | 99.00th=[14400], 99.50th=[15296], 99.90th=[22144], 99.95th=[25728],
        | 99.99th=[33024]
        bw (MB  /s): min= 2395, max= 2514, per=100.00%, avg=2409.79, stdev=29.34
        lat (msec) : 4=0.39%, 10=0.31%, 20=99.15%, 50=0.15%
    cpu          : usr=0.28%, sys=8.08%, ctx=4555, majf=0, minf=8203
    IO depths    : 1=0.1%, 2=0.1%, 4=0.1%, 8=99.8%, 16=0.0%, 32=0.0%, >=64=0.0%
        submit    : 0=0.0%, 4=100.0%, 8=0.0%, 16=0.0%, 32=0.0%, 64=0.0%, >=64=0.0%
        complete  : 0=0.0%, 4=100.0%, 8=0.1%, 16=0.0%, 32=0.0%, 64=0.0%, >=64=0.0%
        issued    : total=r=4575/w=0/d=0, short=r=0/w=0/d=0, drop=r=0/w=0/d=0
        latency   : target=0, window=0, percentile=100.00%, depth=8
    
    Run status group 0 (all jobs):
    READ: io=18300MB, aggrb=2407.3MB/s, minb=2407.3MB/s, maxb=2407.3MB/s, mint=7602msec, maxt=7602msec
    
    Disk stats (read/write):
    nvme0n2: ios=71239/0, merge=0/0, ticks=868737/0, in_queue=868737, util=98.72%
    

Monitorize a taxa de transferência ou as IOPS num volume do Hyperdisk ML

Para monitorizar o desempenho aprovisionado do seu volume de ML Hyperdisk, consulte o artigo Analise os IOPS e a taxa de transferência aprovisionados na documentação do Compute Engine.

Para atualizar o débito aprovisionado ou os IOPS de um volume do Hyperdisk ML existente, ou para saber mais acerca dos parâmetros adicionais do Google Cloud Hyperdisk que pode especificar na sua StorageClass, consulte o artigo Aumente o desempenho do armazenamento com o Google Cloud Hyperdisk.

Resolução de problemas

Esta secção fornece orientações de resolução de problemas para resolver problemas com volumes de ML do Hyperdisk no GKE.

Não é possível atualizar o modo de acesso ao disco

O seguinte erro ocorre quando um volume de ML do Hyperdisk já está a ser usado e anexado por um nó no modo de acesso ReadWriteOnce.

AttachVolume.Attach failed for volume ... Failed to update access mode:
failed to set access mode for zonal volume ...
'Access mode cannot be updated when the disk is attached to instance(s).'., invalidResourceUsage

O GKE atualiza automaticamente o accessMode do volume do Hyperdisk ML de READ_WRITE_SINGLE para READ_ONLY_MANY quando é usado por um PersistentVolume no modo de acesso ReadOnlyMany. Esta atualização é feita quando o disco é anexado a um novo nó.

Para resolver este problema, elimine todos os pods que referenciam o disco através de um PersistentVolume no modo ReadWriteOnce. Aguarde até que o disco seja separado e, em seguida, recrie a carga de trabalho que consome o PersistentVolume no modo ReadOnlyMany.

Não é possível anexar o disco com o modo READ_WRITE

O seguinte erro indica que o GKE tentou anexar um volume do Hyperdisk ML no modo de acesso READ_ONLY_MANY a um nó do GKE usando o modo de acesso ReadWriteOnce.

AttachVolume.Attach failed for volume ...
Failed to Attach: failed cloud service attach disk call ...
The disk cannot be attached with READ_WRITE mode., badRequest

O GKE atualiza automaticamente o accessMode do volume do Hyperdisk ML de READ_WRITE_SINGLE para READ_ONLY_MANY quando é usado por um PersistentVolume no modo de acesso ReadOnlyMany. No entanto, o GKE não atualiza automaticamente o modo de acesso de READ_ONLY_MANY para READ_WRITE_SINGLE. Este é um mecanismo de segurança para garantir que os discos de várias zonas não são escritos por engano, uma vez que isto pode resultar em conteúdo divergente entre os discos de várias zonas.

Para resolver este problema, recomendamos que siga o fluxo de trabalho de pré-armazenamento em cache de dados numa imagem de disco do disco persistente se precisar de conteúdo atualizado. Se precisar de mais controlo sobre o modo de acesso e outras definições do volume de ML do Hyperdisk, consulte o artigo Modifique as definições de um volume do Trusted Cloud by S3NS Hyperdisk.

Quota excedida: quota de débito insuficiente

O seguinte erro indica que não existia quota de débito de ML do Hyperdisk suficiente no momento do aprovisionamento do disco.

failed to provision volume with StorageClass ... failed (QUOTA_EXCEEDED): Quota 'HDML_TOTAL_THROUGHPUT' exceeded

Para resolver este problema, consulte o artigo Quotas de disco para saber mais acerca da quota do Hyperdisk e como aumentar a quota de disco no seu projeto.

Para ver orientações de resolução de problemas adicionais, consulte o artigo Aumente o desempenho do armazenamento com o Google Cloud Hyperdisk.

O que se segue?