Implemente um sistema de processamento em lote com o Kueue

Este tutorial mostra como otimizar os recursos disponíveis agendando tarefas no Google Kubernetes Engine (GKE) com o Kueue. Neste tutorial, vai aprender a usar o Kueue para gerir e agendar eficazmente trabalhos em lote, melhorar a utilização de recursos e simplificar a gestão da carga de trabalho. Configura um cluster partilhado para duas equipas de inquilinos, em que cada equipa tem o seu próprio espaço de nomes e cada equipa cria tarefas que partilham recursos globais. Também configura o Kueue para agendar as tarefas com base nas quotas de recursos que definir.

Este tutorial destina-se a arquitetos da nuvem e engenheiros de plataformas que tenham interesse em implementar um sistema de processamento em lote através do GKE. Para saber mais sobre as funções comuns e as tarefas de exemplo referidas no Google Cloud conteúdo, consulte o artigo Funções e tarefas comuns do utilizador do GKE.

Antes de ler esta página, certifique-se de que conhece o seguinte:

Contexto

As tarefas são aplicações executadas até à conclusão, como aprendizagem automática, renderização, simulação, estatísticas, CI/CD e cargas de trabalho semelhantes.

O Kueue é um programador de tarefas nativo da nuvem que funciona com o programador do Kubernetes predefinido, o controlador de tarefas e o dimensionamento automático de clusters para fornecer um sistema de processamento em lote completo. O Kueue implementa o enfileiramento de tarefas, decidindo quando as tarefas devem esperar e quando devem começar, com base em quotas e numa hierarquia para partilhar recursos de forma justa entre as equipas.

O Kueue tem as seguintes características:

  • Está otimizado para arquiteturas de nuvem, onde os recursos são heterogéneos, intercambiáveis e escaláveis.
  • Oferece um conjunto de APIs para gerir quotas elásticas e gerir o enfileiramento de tarefas.
  • Não reimplementa capacidades existentes, como o dimensionamento automático, o agendamento de pods ou a gestão do ciclo de vida de tarefas.
  • O Kueue tem suporte incorporado para a API Kubernetesbatch/v1.Job.
  • Pode integrar-se com outras APIs de tarefas.

O Kueue refere-se a tarefas definidas com qualquer API como cargas de trabalho, para evitar a confusão com a API Kubernetes Job específica.

Objetivos

  1. Crie um cluster do GKE
  2. Crie o ResourceFlavor
  3. Crie o ClusterQueue
  4. Crie o LocalQueue
  5. Crie tarefas e observe as cargas de trabalho admitidas

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, evite a faturação contínua eliminando os recursos que criou. Para mais informações, consulte o artigo Limpe.

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 GKE API.

    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 API

  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 GKE API.

    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 API

  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/batch/kueue-intro
      
    3. Defina as variáveis de ambiente predefinidas:

      gcloud config set project PROJECT_ID
      gcloud config set compute/region CONTROL_PLANE_LOCATION
      

      Substitua os seguintes valores:

      • PROJECT_ID: o ID do projeto do Google Cloud.
      • CONTROL_PLANE_LOCATION: a região do Compute Engine do plano de controlo do cluster.

    Crie um cluster do GKE

    1. Crie um cluster do GKE Autopilot com o nome kueue-autopilot:

      gcloud container clusters create-auto kueue-autopilot \
        --release-channel "rapid" --location CONTROL_PLANE_LOCATION
      

      Os clusters do Autopilot são totalmente geridos e têm escalabilidade automática incorporada. Saiba mais acerca do GKE Autopilot.

      O Kueue também suporta o GKE padrão com o aprovisionamento automático de nós e os conjuntos de nós com dimensionamento automático normal.

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

        NAME: kueue-autopilot
        LOCATION: us-central1
        MASTER_VERSION: 1.26.2-gke.1000
        MASTER_IP: 35.193.173.228
        MACHINE_TYPE: e2-medium
        NODE_VERSION: 1.26.2-gke.1000
        NUM_NODES: 3
        STATUS: RUNNING
      

      Onde o STATUS é RUNNING para o kueue-autopilot.

    2. Obtenha credenciais de autenticação para o cluster:

      gcloud container clusters get-credentials kueue-autopilot
      
    3. Instale o Kueue no cluster:

      VERSION=VERSION
      kubectl apply --server-side -f \
        https://github.com/kubernetes-sigs/kueue/releases/download/$VERSION/manifests.yaml
      

      Substitua VERSION pela versão mais recente do Kueue. Para mais informações sobre as versões do Kueue, consulte o artigo Lançamentos do Kueue.

    4. Aguarde até que os pods do Kueue estejam prontos:

      watch kubectl -n kueue-system get pods
      

      A saída deve ser semelhante à seguinte antes de poder continuar:

      NAME                                        READY   STATUS    RESTARTS   AGE
      kueue-controller-manager-66d8bb946b-wr2l2   2/2     Running   0          3m36s
      
    5. Crie dois novos espaços de nomes denominados team-a e team-b:

      kubectl create namespace team-a
      kubectl create namespace team-b
      

    Crie o ResourceFlavor

    Um ResourceFlavor é um objeto que representa as variações nos nós disponíveis no seu cluster, associando-os a etiquetas e taints de nós. Por exemplo, pode usar ResourceFlavors para representar VMs com diferentes garantias de aprovisionamento (por exemplo, spot versus a pedido), arquiteturas (por exemplo, CPUs x86 versus ARM), marcas e modelos (por exemplo, GPUs Nvidia A100 versus T4).

    Neste tutorial, o cluster kueue-autopilot tem recursos homogéneos. Como resultado, crie um único ResourceFlavor para CPU, memória, armazenamento temporário e GPUs, sem etiquetas nem restrições.

    apiVersion: kueue.x-k8s.io/v1beta1
    kind: ResourceFlavor
    metadata:
      name: default-flavor # This ResourceFlavor will be used for all the resources
    Implemente o ResourceFlavor:

    kubectl apply -f flavors.yaml
    

    Crie a ClusterQueue

    Uma ClusterQueue é um objeto com âmbito de cluster que gere um conjunto de recursos, como CPU, memória e GPU. Faz a gestão dos ResourceFlavors e limita a utilização, além de determinar a ordem em que as cargas de trabalho são admitidas.

    apiVersion: kueue.x-k8s.io/v1beta1
    kind: ClusterQueue
    metadata:
      name: cluster-queue
    spec:
      namespaceSelector: {} # Available to all namespaces
      queueingStrategy: BestEffortFIFO # Default queueing strategy
      resourceGroups:
      - coveredResources: ["cpu", "memory", "nvidia.com/gpu", "ephemeral-storage"]
        flavors:
        - name: "default-flavor"
          resources:
          - name: "cpu"
            nominalQuota: 10
          - name: "memory"
            nominalQuota: 10Gi
          - name: "nvidia.com/gpu"
            nominalQuota: 10
          - name: "ephemeral-storage"
            nominalQuota: 10Gi

    Implemente a ClusterQueue:

    kubectl apply -f cluster-queue.yaml
    

    A ordem de consumo é determinada por .spec.queueingStrategy, em que existem duas configurações:

    • BestEffortFIFO

      • A configuração da estratégia de colocação em fila predefinida.
      • A admissão da carga de trabalho segue a regra de primeiro a entrar, primeiro a sair (FIFO), mas se não houver quota suficiente para admitir a carga de trabalho no início da fila, é tentada a seguinte na fila.
    • StrictFIFO

      • Garante a semântica FIFO.
      • A carga de trabalho no início da fila pode bloquear o enfileiramento até que a carga de trabalho possa ser admitida.

    Em cluster-queue.yaml, cria uma nova ClusterQueue denominada cluster-queue. Esta ClusterQueue gere quatro recursos: cpu, memory, nvidia.com/gpu e ephemeral-storage com o tipo criado em flavors.yaml. A quota é consumida pelos pedidos nas especificações do pod da carga de trabalho.

    Cada variante inclui limites de utilização representados como .spec.resourceGroups[].flavors[].resources[].nominalQuota. Neste caso, o ClusterQueue admite cargas de trabalho se e só se:

    • A soma dos pedidos de CPU é inferior ou igual a 10
    • A soma dos pedidos de memória é inferior ou igual a 10 Gi
    • A soma dos pedidos de GPU é inferior ou igual a 10
    • A soma do armazenamento usado é inferior ou igual a 10 Gi

    Crie o LocalQueue

    Uma LocalQueue é um objeto com espaço de nomes que aceita cargas de trabalho de utilizadores no espaço de nomes. As LocalQueues de diferentes espaços de nomes podem apontar para a mesma ClusterQueue, onde podem partilhar a quota de recursos. Neste caso, LocalQueue do espaço de nomes team-a e team-b aponta para o mesmo ClusterQueue cluster-queue em .spec.clusterQueue.

    apiVersion: kueue.x-k8s.io/v1beta1
    kind: LocalQueue
    metadata:
      namespace: team-a # LocalQueue under team-a namespace
      name: lq-team-a
    spec:
      clusterQueue: cluster-queue # Point to the ClusterQueue
    ---
    apiVersion: kueue.x-k8s.io/v1beta1
    kind: LocalQueue
    metadata:
      namespace: team-b # LocalQueue under team-b namespace
      name: lq-team-b
    spec:
      clusterQueue: cluster-queue # Point to the ClusterQueue

    Cada equipa envia as respetivas cargas de trabalho para a LocalQueue no seu próprio espaço de nomes. Que são, em seguida, recursos atribuídos pela ClusterQueue.

    Implemente as LocalQueues:

    kubectl apply -f local-queue.yaml
    

    Crie tarefas e observe as cargas de trabalho admitidas

    Nesta secção, cria tarefas do Kubernetes no espaço de nomes team-a. Um controlador de tarefas no Kubernetes cria um ou mais pods e garante que executam com êxito uma tarefa específica.

    O serviço no espaço de nomes team-a tem os seguintes atributos:

    • Aponta para o lq-team-a LocalQueue.
    • Pede recursos de GPU definindo o campo nodeSelector como nvidia-tesla-t4.
    • É composto por três pods que ficam em suspensão durante 10 segundos em paralelo. As tarefas são limpas após 60 segundos, de acordo com o valor definido no campo ttlSecondsAfterFinished.
    • Requer 1500 milliCPU, 1536 Mi de memória, 1536 Mi de armazenamento efémero e três GPUs, uma vez que existem três pods.
    apiVersion: batch/v1
    kind: Job
    metadata:
      namespace: team-a # Job under team-a namespace
      generateName: sample-job-team-a-
      annotations:
        kueue.x-k8s.io/queue-name: lq-team-a # Point to the LocalQueue
    spec:
      ttlSecondsAfterFinished: 60 # Job will be deleted after 60 seconds
      parallelism: 3 # This Job will have 3 replicas running at the same time
      completions: 3 # This Job requires 3 completions
      suspend: true # Set to true to allow Kueue to control the Job when it starts
      template:
        spec:
          nodeSelector:
            cloud.google.com/gke-accelerator: "nvidia-tesla-t4" # Specify the GPU hardware
          containers:
          - name: dummy-job
            image: gcr.io/k8s-staging-perf-tests/sleep:latest
            args: ["10s"] # Sleep for 10 seconds
            resources:
              requests:
                cpu: "500m"
                memory: "512Mi"
                ephemeral-storage: "512Mi"
                nvidia.com/gpu: "1"
              limits:
                cpu: "500m"
                memory: "512Mi"
                ephemeral-storage: "512Mi"
                nvidia.com/gpu: "1"
          restartPolicy: Never

    As tarefas também são criadas no ficheiro job-team-b.yaml, em que o respetivo espaço de nomes pertence a team-b, com pedidos para representar diferentes equipas com diferentes necessidades.

    Para saber mais, consulte o artigo sobre a implementação de cargas de trabalho de GPU no Autopilot.

    1. Num novo terminal, observe o estado da ClusterQueue que é atualizado a cada dois segundos:

      watch -n 2 kubectl get clusterqueue cluster-queue -o wide
      
    2. Num novo terminal, observe o estado dos nós:

      watch -n 2 kubectl get nodes -o wide
      
    3. Num novo terminal, crie trabalhos para LocalQueue a partir do espaço de nomes team-a e team-b a cada 10 segundos:

      ./create_jobs.sh job-team-a.yaml job-team-b.yaml 10
      
    4. Observe as tarefas a serem colocadas em fila, admitidas na ClusterQueue e os nós a serem iniciados com o GKE Autopilot.

    5. Obter uma tarefa do espaço de nomes team-a:

      kubectl -n team-a get jobs
      

      O resultado é semelhante ao seguinte:

      NAME                      COMPLETIONS   DURATION   AGE
      sample-job-team-b-t6jnr   3/3           21s        3m27s
      sample-job-team-a-tm7kc   0/3                      2m27s
      sample-job-team-a-vjtnw   3/3           30s        3m50s
      sample-job-team-b-vn6rp   0/3                      40s
      sample-job-team-a-z86h2   0/3                      2m15s
      sample-job-team-b-zfwj8   0/3                      28s
      sample-job-team-a-zjkbj   0/3                      4s
      sample-job-team-a-zzvjg   3/3           83s        4m50s
      
    6. Copie um nome de tarefa do passo anterior e observe o estado de admissão e os eventos de uma tarefa através da API Workloads:

      kubectl -n team-a describe workload JOB_NAME
      
    7. Quando os trabalhos pendentes começarem a aumentar a partir da ClusterQueue, termine o script premindo CTRL + C no script em execução.

    8. Quando todas as tarefas estiverem concluídas, repare que os nós estão a ser reduzidos.

    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 o recurso individual

    1. Elimine o sistema de quotas do Kueue:

      kubectl delete -n team-a localqueue lq-team-a
      kubectl delete -n team-b localqueue lq-team-b
      kubectl delete clusterqueue cluster-queue
      kubectl delete resourceflavor default-flavor
      
    2. Elimine o manifesto do Kueue:

      VERSION=VERSION
      kubectl delete -f \
        https://github.com/kubernetes-sigs/kueue/releases/download/$VERSION/manifests.yaml
      
    3. Elimine o cluster:

      gcloud container clusters delete kueue-autopilot --location=CONTROL_PLANE_LOCATION
      

    O que se segue?