Desplegar un sistema por lotes con Kueue

En este tutorial se muestra cómo optimizar los recursos disponibles programando trabajos en Google Kubernetes Engine (GKE) con Kueue. En este tutorial, aprenderás a usar Kueue para gestionar y programar de forma eficaz trabajos por lotes, mejorar el uso de los recursos y simplificar la gestión de las cargas de trabajo. Configuras un clúster compartido para dos equipos de clientes, donde cada equipo tiene su propio espacio de nombres y crea trabajos que comparten recursos globales. También puedes configurar Kueue para programar las tareas en función de las cuotas de recursos que definas.

Este tutorial está dirigido a arquitectos de Cloud e ingenieros de plataformas que quieran implementar un sistema de procesamiento por lotes con GKE. Para obtener más información sobre los roles habituales y las tareas de ejemplo que se mencionan en el contenido, consulta Roles y tareas de usuario habituales de GKE. Google Cloud

Antes de leer esta página, asegúrese de que conoce los siguientes conceptos:

Fondo

Los trabajos son aplicaciones que se ejecutan hasta completarse, como el aprendizaje automático, el renderizado, la simulación, las analíticas, la integración y la entrega continuas (CI/CD) y cargas de trabajo similares.

Kueue es un programador de tareas nativo de la nube que funciona con el programador predeterminado de Kubernetes, el controlador de tareas y el autoescalador de clústeres para proporcionar un sistema de procesamiento por lotes integral. Kueue implementa la puesta en cola de trabajos, decidiendo cuándo deben esperar los trabajos y cuándo deben iniciarse, en función de las cuotas y una jerarquía para compartir recursos de forma equitativa entre los equipos.

Kueue tiene las siguientes características:

  • Está optimizado para arquitecturas de nube, donde los recursos son heterogéneos, intercambiables y escalables.
  • Proporciona un conjunto de APIs para gestionar cuotas elásticas y colas de trabajos.
  • No vuelve a implementar funciones ya disponibles, como el escalado automático, la programación de pods o la gestión del ciclo de vida de los trabajos.
  • Kueue tiene compatibilidad integrada con la API de Kubernetesbatch/v1.Job.
  • Se puede integrar con otras APIs de empleo.

Kueue se refiere a los trabajos definidos con cualquier API como cargas de trabajo para evitar la confusión con la API de trabajo específica de Kubernetes.

Objetivos

  1. Crear un clúster de GKE
  2. Crea el ResourceFlavor.
  3. Crea el ClusterQueue.
  4. Crea la LocalQueue.
  5. Crea trabajos y observa las cargas de trabajo admitidas

Costes

En este tutorial se usan los siguientes componentes facturables de Google Cloud:

Usa la calculadora de precios para generar una estimación de costes basada en el uso previsto.

Cuando termines este tutorial, elimina los recursos que hayas creado para evitar que se te siga facturando. Para obtener más información, consulta la sección Limpiar.

Antes de empezar

Configurar el proyecto

  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 (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 (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. Definir valores predeterminados para Google Cloud CLI

    1. En la Google Cloud consola, inicia una instancia de Cloud Shell:
      Abrir Cloud Shell

    2. Descarga el código fuente de esta aplicación de ejemplo:

      git clone https://github.com/GoogleCloudPlatform/kubernetes-engine-samples
      cd kubernetes-engine-samples/batch/kueue-intro
      
    3. Define las variables de entorno predeterminadas:

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

      Sustituye los siguientes valores:

      • PROJECT_ID: tu ID de proyecto de Google Cloud.
      • CONTROL_PLANE_LOCATION: la región de Compute Engine del plano de control de tu clúster.

    Crear un clúster de GKE

    1. Crea un clúster de Autopilot de GKE llamado kueue-autopilot:

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

      Los clústeres Autopilot están totalmente gestionados y tienen autoescalado integrado. Consulta más información sobre Autopilot de GKE.

      Kueue también admite GKE estándar con aprovisionamiento automático de nodos y grupos de nodos con escalado automático normal.

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

        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
      

      Donde STATUS es RUNNING para kueue-autopilot.

    2. Obtén las credenciales de autenticación del clúster:

      gcloud container clusters get-credentials kueue-autopilot
      
    3. Instala Kueue en el clúster:

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

      Sustituye VERSION por la versión más reciente de Kueue. Para obtener más información sobre las versiones de Kueue, consulta Lanzamientos de Kueue.

    4. Espera hasta que los pods de Kueue estén listos:

      watch kubectl -n kueue-system get pods
      

      La salida debería ser similar a la siguiente para que puedas continuar:

      NAME                                        READY   STATUS    RESTARTS   AGE
      kueue-controller-manager-66d8bb946b-wr2l2   2/2     Running   0          3m36s
      
    5. Crea dos espacios de nombres llamados team-a y team-b:

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

    Crear el ResourceFlavor

    Un ResourceFlavor es un objeto que representa las variaciones de los nodos disponibles en tu clúster asociándolos con etiquetas y taints de nodo. Por ejemplo, puedes usar ResourceFlavors para representar máquinas virtuales con diferentes garantías de aprovisionamiento (por ejemplo, de tipo spot o bajo demanda), arquitecturas (por ejemplo, CPUs x86 o ARM), marcas y modelos (por ejemplo, GPUs Nvidia A100 o T4).

    En este tutorial, el clúster kueue-autopilot tiene recursos homogéneos. Por lo tanto, crea un único ResourceFlavor para CPU, memoria, almacenamiento efímero y GPUs, sin etiquetas ni taints.

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

    kubectl apply -f flavors.yaml
    

    Crear el ClusterQueue

    Un ClusterQueue es un objeto con ámbito de clúster que gestiona un conjunto de recursos, como CPU, memoria y GPU. Gestiona los ResourceFlavors, limita el uso y determina el orden en el que se admiten las cargas de trabajo.

    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

    Despliega ClusterQueue:

    kubectl apply -f cluster-queue.yaml
    

    El orden de consumo se determina mediante .spec.queueingStrategy, que tiene dos configuraciones:

    • BestEffortFIFO

      • La configuración predeterminada de la estrategia de colas.
      • La admisión de cargas de trabajo sigue la regla de FIFO (primero en entrar, primero en salir), pero si no hay suficiente cuota para admitir la carga de trabajo que está al principio de la cola, se intenta con la siguiente.
    • StrictFIFO

      • Garantiza la semántica FIFO.
      • La carga de trabajo al principio de la cola puede bloquear la puesta en cola hasta que se pueda admitir la carga de trabajo.

    En cluster-queue.yaml, crea un ClusterQueue llamado cluster-queue. Este ClusterQueue gestiona cuatro recursos: cpu, memory, nvidia.com/gpu y ephemeral-storage, con el sabor creado en flavors.yaml. La cuota se consume con las solicitudes de las especificaciones de los pods de la carga de trabajo.

    Cada variante incluye límites de uso representados como .spec.resourceGroups[].flavors[].resources[].nominalQuota. En este caso, ClusterQueue admite cargas de trabajo si y solo si:

    • La suma de las solicitudes de CPU es inferior o igual a 10
    • La suma de las solicitudes de memoria es inferior o igual a 10 Gi
    • La suma de las solicitudes de GPU es inferior o igual a 10
    • La suma del almacenamiento utilizado es inferior o igual a 10 Gi

    Crea el LocalQueue

    LocalQueue es un objeto con espacio de nombres que acepta cargas de trabajo de los usuarios del espacio de nombres. Las LocalQueues de diferentes espacios de nombres pueden apuntar a la misma ClusterQueue, donde pueden compartir la cuota de recursos. En este caso, LocalQueue de los espacios de nombres team-a y team-b apunta al mismo ClusterQueue cluster-queue en .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 equipo envía sus cargas de trabajo a LocalQueue en su propio espacio de nombres. A los que ClusterQueue asigna recursos.

    Implementa LocalQueues:

    kubectl apply -f local-queue.yaml
    

    Crea trabajos y observa las cargas de trabajo admitidas

    En esta sección, creará trabajos de Kubernetes en el espacio de nombres team-a. Un controlador de trabajo de Kubernetes crea uno o varios pods y se asegura de que ejecuten correctamente una tarea específica.

    El trabajo del espacio de nombres team-a tiene los siguientes atributos:

    • Apunta a lq-team-a LocalQueue.
    • Solicita recursos de GPU asignando el valor nvidia-tesla-t4 al campo nodeSelector.
    • Se compone de tres pods que duermen durante 10 segundos en paralelo. Las tareas se eliminan después de 60 segundos, según el valor definido en el campo ttlSecondsAfterFinished.
    • Requiere 1500 miliCPU, 1536 Mi de memoria, 1536 Mi de almacenamiento efímero y tres GPUs, ya que hay tres 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

    Los trabajos también se crean en el archivo job-team-b.yaml cuyo espacio de nombres pertenece a team-b, con solicitudes para representar diferentes equipos con diferentes necesidades.

    Para obtener más información, consulta el artículo sobre cómo desplegar cargas de trabajo de GPUs en Autopilot.

    1. En una terminal nueva, observa el estado de ClusterQueue, que se actualiza cada dos segundos:

      watch -n 2 kubectl get clusterqueue cluster-queue -o wide
      
    2. En una terminal nueva, observa el estado de los nodos:

      watch -n 2 kubectl get nodes -o wide
      
    3. En un terminal nuevo, crea tareas en LocalQueue desde el espacio de nombres team-a y team-b cada 10 segundos:

      ./create_jobs.sh job-team-a.yaml job-team-b.yaml 10
      
    4. Observa las tareas que se ponen en cola, se admiten en ClusterQueue y los nodos que se activan con Autopilot de GKE.

    5. Obtener un trabajo del espacio de nombres team-a:

      kubectl -n team-a get jobs
      

      El resultado es similar al siguiente:

      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. Copia el nombre de un trabajo del paso anterior y observa el estado de admisión y los eventos de un trabajo a través de la API Workloads:

      kubectl -n team-a describe workload JOB_NAME
      
    7. Cuando los trabajos pendientes empiecen a aumentar en ClusterQueue, finaliza la secuencia de comandos pulsando CTRL + C en la secuencia de comandos en ejecución.

    8. Una vez que se hayan completado todos los trabajos, verás que los nodos se reducen.

    Limpieza

    Para evitar que los recursos utilizados en este tutorial se cobren en tu cuenta de Google Cloud, elimina el proyecto que contiene los recursos o conserva el proyecto y elimina los recursos.

    Eliminar el proyecto

    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.

    Eliminar el recurso concreto

    1. Elimina el sistema de cuotas de 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. Elimina el manifiesto de Kueue:

      VERSION=VERSION
      kubectl delete -f \
        https://github.com/kubernetes-sigs/kueue/releases/download/$VERSION/manifests.yaml
      
    3. Elimina el clúster:

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

    Siguientes pasos