Implementar um sistema de enfileiramento de jobs com compartilhamento de cota entre namespaces no GKE


Neste tutorial, usamos o Kueue para mostrar como implementar um sistema de enfileiramento de jobs, configurar o recurso de carga de trabalho e o compartilhamento de cota entre diferentes namespaces no Google Kubernetes Engine (GKE) e maximizar a utilização do cluster.

Contexto

Como engenheiro de infraestrutura ou administrador de cluster, maximizar a utilização entre namespaces é muito importante. Um lote de jobs em um namespace pode não utilizar totalmente a cota completa atribuída ao namespace, enquanto outro namespace pode ter vários jobs pendentes. Para usar com eficiência os recursos do cluster entre jobs em namespaces diferentes e aumentar a flexibilidade do gerenciamento de cotas, configure coortes no Kueue. Uma coorte é um grupo de ClusterQueues que podem pedir emprestados cotas não utilizadas uns dos outros. Um ClusterQueue controla um conjunto de recursos, como aceleradores de hardware, memória e CPU.

Você pode encontrar uma definição mais detalhada de todos esses conceitos na documentação do Kueue

Objetivos

Este tutorial é para engenheiros de infraestrutura ou administradores de cluster que querem implementar um sistema de enfileiramento de jobs no Kubernetes usando o Kueue com compartilhamento de cota.

Este tutorial imitará duas equipes em dois namespaces diferentes, em que cada uma tem recursos dedicados, mas pode usar as outras. Um terceiro conjunto de recursos pode ser usado como sobrecarga quando os jobs se acumulam.

Use o operador Prometheus para monitorar jobs e alocação de recursos em namespaces diferentes.

Este tutorial aborda as seguintes etapas necessárias:

  1. Criar um cluster do GKE
  2. Crie os ResourceFlavors.
  3. Para cada equipe, crie um ClusterQueue e um LocalQueue
  4. Criar Jobs e observar as cargas de trabalho admitidas
  5. Pedir emprestado a cota não utilizada com coortes
  6. Adicionar um spilover ClusterQueue que rege as VMs spot

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.

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

    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.

    Go to project selector

  6. Make sure that billing is enabled for your Google Cloud project.

  7. Enable the GKE API.

    Enable the API

  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
      
    3. Defina as variáveis de ambiente padrão:

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

      Substitua os seguintes valores:

    Criar um cluster do GKE

    1. Crie um Cluster do GKE chamado kueue-cohort:

      Você vai criar um cluster com seis nós (dois por zona) no pool padrão e sem escalonamento automático. Esses serão todos os recursos disponíveis para as equipes no início, então elas precisarão competir por elas.

      Você verá como o Kueue gerencia as cargas de trabalho que as duas equipes enviarão às respectivas filas.

        gcloud container clusters create kueue-cohort --region COMPUTE_REGION \
        --release-channel rapid --machine-type e2-standard-4 --num-nodes 2
      

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

        kubeconfig entry generated for kueue-cohort.
        NAME: kueue-cohort
        LOCATION: us-central1
        MASTER_VERSION: 1.26.2-gke.1000
        MASTER_IP: 35.224.108.58
        MACHINE_TYPE: e2-medium
        NODE_VERSION: 1.26.2-gke.1000
        NUM_NODES: 6
        STATUS: RUNNING
      

      Em que a STATUS é RUNNING para a kueue-cluster.

    2. Crie um pool de nós chamado spot.

      Este pool de nós usa a VM do Spot, e o escalonamento automático está ativado. Ele começa com 0 nós, mas depois você o disponibilizará para as equipes para uso como capacidade de sobrecarga.

      gcloud container node-pools create spot --cluster=kueue-cohort --region COMPUTE_REGION  \
      --spot --enable-autoscaling --max-nodes 20 --num-nodes 0 \
      --machine-type e2-standard-4
      
    3. Instale a versão de lançamento do Kueue no cluster:

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

      Substitua VERSION pela letra v após a versão mais recente do Kueue, por exemplo, v0.4.0. Para conferir mais informações sobre as versões do Kueue, consulte as Versões do Kueue.

      Aguarde até que o controlador do Kueue esteja pronto:

      watch kubectl -n kueue-system get pods
      

      A saída será semelhante a esta antes de continuar:

      NAME                                        READY   STATUS    RESTARTS   AGE
      kueue-controller-manager-6cfcbb5dc5-rsf8k   2/2     Running   0          3m
      
    4. Crie dois novos namespaces chamados team-a e team-b:

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

      Os jobs serão gerados em cada namespace.

Criar o ResourceFlavors

Um ResourceFlavor representa variações de recursos nos nós do cluster, como VMs diferentes (por exemplo, spot versus sob demanda), arquiteturas (por exemplo, CPUs x86 x ARM), marcas e modelos (por exemplo, Nvidia A100 versus GPUs T4).

Os ResourceFlavors usam rótulos e taints de nós para fazer a correspondência com um conjunto de nós no cluster.

apiVersion: kueue.x-k8s.io/v1beta1
kind: ResourceFlavor
metadata:
  name: on-demand # This ResourceFlavor will be used for the CPU resource
spec:
  nodeLabels:
    cloud.google.com/gke-provisioning: standard # This label was applied automatically by GKE
---
apiVersion: kueue.x-k8s.io/v1beta1
kind: ResourceFlavor
metadata:
  name: spot # This ResourceFlavor will be used as added resource for the CPU resource
spec:
  nodeLabels:  
    cloud.google.com/gke-provisioning: spot # This label was applied automatically by GKE

Nesse manifesto:

  • O ResourceFlavor on-demand tem o rótulo definido como cloud.google.com/gke-provisioning: standard.
  • O ResourceFlavor spot tem o rótulo definido como cloud.google.com/gke-provisioning: spot.

Quando uma carga de trabalho é atribuída a um ResourceFlavor, o Kueue atribui os pods da carga aos nós que correspondem aos rótulos de nós definidos para o ResourceFlavor.

Implantar o ResourceFlavor:

kubectl apply -f flavors.yaml

Criar o ClusterQueue e a LocalQueue

Crie duas ClusterQueues cq-team-a e cq-team-b e as LocalQueues lq-team-a e lq-team-b correspondentes com os namespaces team-a e team-b, respectivamente.

ClusterQueues são objetos com escopo de cluster que controlam um pool de recursos, como aceleradores de hardware, memória e CPU. Os administradores em lote podem restringir a visibilidade desses objetos a usuários em lote.

LocalQueues são objetos com namespace que os usuários em lote podem listar. Eles apontam para CluterQueues, a partir dos quais os recursos são alocados para executar as cargas de trabalho da LocalQueue.

apiVersion: kueue.x-k8s.io/v1beta1
kind: ClusterQueue
metadata:
  name: cq-team-a
spec:
  cohort: all-teams # cq-team-a and cq-team-b share the same cohort
  namespaceSelector:
    matchLabels:
      kubernetes.io/metadata.name: team-a #Only team-a can submit jobs direclty to this queue, but will be able to share it through the cohort
  resourceGroups:
  - coveredResources: ["cpu", "memory"]
    flavors:
    - name: on-demand
      resources:
      - name: "cpu"
        nominalQuota: 10
        borrowingLimit: 5
      - name: "memory"
        nominalQuota: 10Gi
        borrowingLimit: 15Gi
    - name: spot # This ClusterQueue doesn't have nominalQuota for spot, but it can borrow from others
      resources:
      - name: "cpu"
        nominalQuota: 0
      - name: "memory"
        nominalQuota: 0
---
apiVersion: kueue.x-k8s.io/v1beta1
kind: LocalQueue
metadata:
  namespace: team-a # LocalQueue under team-a namespace
  name: lq-team-a
spec:
  clusterQueue: cq-team-a # Point to the ClusterQueue team-a-cq

ClusterQueues permite que os recursos tenham diversas variações. Nesse caso, as duas QueueQueues têm duas variações, on-demand e spot, cada uma fornecendo recursos cpu. A cota de spot do ResourceFlavor está definida como 0 e não será usada no momento.

As duas ClusterQueues compartilham a mesma coorte chamada all-teams, definida em .spec.cohort. Quando duas ou mais ClusterQueues compartilham a mesma coorte, é possível pedir emprestado uma cota não utilizada entre si.

Saiba mais sobre como as coortes funcionam e a semântica do empréstimo na documentação do Kueue

Implante as ClusterQueues e LocalQueues:

kubectl apply -f cq-team-a.yaml
kubectl apply -f cq-team-b.yaml

(Opcional) Monitorar cargas de trabalho usando o kube-prometheus

É possível usar o Prometheus para monitorar suas cargas de trabalho ativas e pendentes do Kueue. Para monitorar as cargas de trabalho que estão sendo criadas e observar a carga em cada ClusterQueue, implante o kube-prometheus no cluster no namespace monitoring:

  1. Faça o download do código-fonte do operador do Prometheus:

    cd
    git clone https://github.com/prometheus-operator/kube-prometheus.git
    
  2. Crie os CustomResourceDefinitions(CRDs):

    kubectl create -f kube-prometheus/manifests/setup
    
  3. Crie os componentes de monitoramento:

    kubectl create -f kube-prometheus/manifests
    
  4. Permita que o prometheus-operator colete métricas dos componentes do Kueue:

    kubectl apply -f https://github.com/kubernetes-sigs/kueue/releases/download/$VERSION/prometheus.yaml
    
  5. Mude para o diretório de trabalho:

    cd kubernetes-engine-samples/batch/kueue-cohort
    
  6. Configure o encaminhamento de portas para o serviço Prometheus em execução no cluster do GKE:

    kubectl --namespace monitoring port-forward svc/prometheus-k8s 9090
    
  7. Abra a interface da Web do Prometheus em localhost:9090 no navegador.

    No Cloud Shell:

    1. Clique em Visualização da Web.

    2. Clique em Alterar porta e defina o número da porta como 9090.

    3. Clique em Alterar e visualizar.

    A seguinte UI da Web do Prometheus aparece.

    Captura de tela da UI da Web do Prometheus

  8. Na caixa de consulta Expressão, insira a consulta a seguir para criar o primeiro painel que monitora as cargas de trabalho ativas para cq-team-a ClusterQueue:

    kueue_pending_workloads{cluster_queue="cq-team-a", status="active"} or kueue_admitted_active_workloads{cluster_queue="cq-team-a"}
    
  9. Clique em Adicionar painel.

  10. Na caixa de consulta Expressão, insira a consulta a seguir para criar outro painel que monitora as cargas de trabalho ativas da ClusterQueue cq-team-b:

    kueue_pending_workloads{cluster_queue="cq-team-b", status="active"} or kueue_admitted_active_workloads{cluster_queue="cq-team-b"}
    
  11. Clique em Adicionar painel.

  12. Na caixa de consulta Expressão, insira a consulta a seguir para criar um painel que monitora o número de nós no cluster:

    count(kube_node_info)
    

(Opcional) Monitorar cargas de trabalho usando o Google Cloud Managed Service para Prometheus

É possível usar o Google Cloud Managed Service para Prometheus para monitorar as cargas de trabalho ativas e pendentes do Kueue. Confira a lista completa de métricas na documentação do Kueue.

  1. Configure a identidade e o RBAC para acesso às métricas:

    A configuração a seguir cria quatro recursos do Kubernetes que fornecem acesso a métricas para os coletores do Google Cloud Managed Service para Prometheus.

    • Uma ServiceAccount chamada kueue-metrics-reader no namespace kueue-system será usada para autenticar ao acessar as métricas do Kueue.

    • Um Secret associado à conta de serviço kueue-metrics-reader, armazena um token de autenticação usado pelo coletor para se autenticar com o endpoint de métricas exposto pela implantação do Kueue.

    • Uma função chamada kueue-secret-reader no namespace kueue-system, que permite ler o secret que contém o token da conta de serviço.

    • Um ClusterRoleBinding que concede à conta de serviço kueue-metrics-reader o ClusterRole kueue-metrics-reader.

    apiVersion: v1
    kind: ServiceAccount
    metadata:
     name: kueue-metrics-reader
     namespace: kueue-system
    ---
    apiVersion: v1
    kind: Secret
    metadata:
     name: kueue-metrics-reader-token
     namespace: kueue-system
     annotations:
       kubernetes.io/service-account.name: kueue-metrics-reader
    type: kubernetes.io/service-account-token
    ---
    apiVersion: rbac.authorization.k8s.io/v1
    kind: Role
    metadata:
     name: kueue-secret-reader
     namespace: kueue-system
    rules:
    -   resources:
     -   secrets
     apiGroups: [""]
     verbs: ["get", "list", "watch"]
     resourceNames: ["kueue-metrics-reader-token"]
    ---
    apiVersion: rbac.authorization.k8s.io/v1
    kind: ClusterRoleBinding
    metadata:
     name: kueue-metrics-reader
    subjects:
    -   kind: ServiceAccount
     name: kueue-metrics-reader
     namespace: kueue-system
    roleRef:
     kind: ClusterRole
     name: kueue-metrics-reader
     apiGroup: rbac.authorization.k8s.io
    
  2. Configure o RoleBinding para o Google Cloud Managed Service para Prometheus:

    Dependendo se você estiver usando um cluster do Autopilot ou Standard, será necessário criar o RoleBinding no namespace gke-gmp-system ou gmp-system. Esse recurso permite que a conta de serviço do coletor acesse o secreto kueue-metrics-reader-token para autenticar e extrair as métricas do Kueue.

    Piloto automático

      apiVersion: rbac.authorization.k8s.io/v1
      kind: RoleBinding
      metadata:
        name: gmp-system:collector:kueue-secret-reader
        namespace: kueue-system
      roleRef:
        name: kueue-secret-reader
        kind: Role
        apiGroup: rbac.authorization.k8s.io
      subjects:
      -   name: collector
        namespace: gke-gmp-system
        kind: ServiceAccount
    

    Padrão

      apiVersion: rbac.authorization.k8s.io/v1
      kind: RoleBinding
      metadata:
        name: gmp-system:collector:kueue-secret-reader
        namespace: kueue-system
      roleRef:
        name: kueue-secret-reader
        kind: Role
        apiGroup: rbac.authorization.k8s.io
      subjects:
      -   name: collector
        namespace: gmp-system
        kind: ServiceAccount
    
  3. Configure o recurso PodMonitoring:

    O recurso a seguir configura o monitoramento da implantação do Kueue e especifica que as métricas são expostas no caminho /metrics por HTTPS. Ele usa o secret kueue-metrics-reader-token para autenticação ao extrair as métricas.

    apiVersion: monitoring.googleapis.com/v1
    kind: PodMonitoring
    metadata:
    name: kueue
    namespace: kueue-system
    spec:
    selector:
     matchLabels:
       control-plane: controller-manager
    endpoints:
    -   port: https
     interval: 30s
     path: /metrics
     scheme: https
     tls:
       insecureSkipVerify: true
     authorization:
       type: Bearer
       credentials:
         secret:
           name: kueue-metrics-reader-token
           key: token
    

Consultar métricas exportadas

Exemplos de consultas PromQL para monitorar sistemas baseados no Kueue

Com essas consultas do PromQL, é possível monitorar as principais métricas do Kueue, como capacidade de processamento de jobs, utilização de recursos por fila e tempos de espera da carga de trabalho, para entender o desempenho do sistema e identificar possíveis gargalos.

Capacidade de jobs

Isso calcula a taxa por segundo de cargas de trabalho aceitas em cinco minutos para cada cluster_queue. Essa métrica pode ajudar a detalhar por fila, identificar gargalos e somar o throughput geral do sistema.

Consulta:

sum(rate(kueue_admitted_workloads_total[5m])) by (cluster_queue)

Uso de recursos

Isso pressupõe que metrics.enableClusterQueueResources esteja ativado. Ele calcula a proporção do uso atual da CPU em relação à cota nominal de CPU para cada fila. Um valor próximo de 1 indica alta utilização. Você pode adaptar isso para memória ou outros recursos mudando o rótulo do recurso.

Para instalar uma versão lançada do Kueue com configuração personalizada no cluster, siga a documentação do Kueue.

Consulta:

sum(kueue_cluster_queue_resource_usage{resource="cpu"}) by (cluster_queue) / sum(kueue_cluster_queue_nominal_quota{resource="cpu"}) by (cluster_queue)

Tempo de espera na fila

Isso fornece o tempo de espera do 90º percentil para cargas de trabalho em uma fila específica. É possível modificar o valor do quantil (por exemplo, 0,5 para mediana, 0,99 para o percentil 99) para entender a distribuição do tempo de espera.

Consulta:

histogram_quantile(0.9, kueue_admission_wait_time_seconds_bucket{cluster_queue="QUEUE_NAME"})

Criar Jobs e observar as cargas de trabalho admitidas

Nesta seção, você cria jobs do Kubernetes nos namespaces team-a e team-b. Um controlador de job no Kubernetes cria um ou mais pods e garante que eles executem uma tarefa específica com sucesso.

Gerar jobs para os ClusterQueues que ficarão suspensos por 10 segundos, com três jobs em paralelo e com três conclusões concluídas. Em seguida, ele será limpo após 60 segundos.

apiVersion: batch/v1
kind: Job
metadata:
  namespace: team-a # Job under team-a namespace
  generateName: sample-job-team-a-
  labels:
    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:
      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"
      restartPolicy: Never

job-team-a.yaml cria jobs no namespace team-a e aponta para o LocalQueue lq-team-a e o ClusterQueue cq-team-a.

Da mesma forma, job-team-b.yaml cria jobs no namespace team-b e aponta para o LocalQueue lq-team-b e a ClusterQueue cq-team-b.

  1. Inicie um novo terminal e execute este script para gerar um job a cada segundo:

    ./create_jobs.sh job-team-a.yaml 1
    
  2. Inicie outro terminal e crie jobs para o namespace team-b:

    ./create_jobs.sh job-team-b.yaml 1
    
  3. Observe os jobs que estão sendo enfileirados no Prometheus. Ou com este comando:

    watch -n 2 kubectl get clusterqueues -o wide
    

A saída será semelhante a esta:

    NAME        COHORT      STRATEGY         PENDING WORKLOADS   ADMITTED WORKLOADS
    cq-team-a   all-teams   BestEffortFIFO   0                   5
    cq-team-b   all-teams   BestEffortFIFO   0                   4

Pedir emprestado cota não utilizada com coortes

As ClusterQueues podem não estar com capacidade total o tempo todo. O uso de cotas não é maximizado quando as cargas de trabalho não são distribuídas uniformemente entre os ClusterQueues. Se ClusterQueues compartilharem a mesma coorte entre si, elas poderão pegar emprestado cotas de outras ClusterQueues para maximizar a utilização da cota.

  1. Quando houver jobs enfileirados para os ClusterQueues cq-team-a e cq-team-b, interrompa o script do namespace team-b pressionando CTRL+c no terminal correspondente.

  2. Depois que todos os jobs pendentes do namespace team-b forem processados, os jobs do namespace team-a poderão usar os recursos disponíveis em cq-team-b:

    kubectl describe clusterqueue cq-team-a
    

    Como cq-team-a e cq-team-b compartilham a mesma coorte chamada all-teams, essas ClusterQueues podem compartilhar recursos que não são utilizados.

      Flavors Usage:
        Name:  on-demand
        Resources:
          Borrowed:  5
          Name:      cpu
          Total:     15
          Borrowed:  5Gi
          Name:      memory
          Total:     15Gi
    
  3. Retome o script para o namespace team-b.

    ./create_jobs.sh job-team-b.yaml 3
    

    Observe como os recursos emprestados de cq-team-a retornam a 0, enquanto os recursos de cq-team-b são usados para as próprias cargas de trabalho:

    kubectl describe clusterqueue cq-team-a
    
      Flavors Usage:
        Name:  on-demand
        Resources:
          Borrowed:  0
          Name:      cpu
          Total:     9
          Borrowed:  0
          Name:      memory
          Total:     9Gi
    

Aumentar a cota com VMs do Spot

Quando a cota precisar ser aumentada temporariamente, por exemplo, para atender à alta demanda em cargas de trabalho pendentes, é possível configurar o Kueue para acomodar a demanda adicionando mais ClusterQueues à coorte. ClusterQueues com recursos não utilizados podem compartilhá-los com outras ClusterQueues que pertencem à mesma coorte.

No início do tutorial, você criou um pool de nós chamado spot usando VMs do Spot e um ResourceFlavor chamado spot com o rótulo definido como cloud.google.com/gke-provisioning: spot. Crie um ClusterQueue para usar este pool de nós e o ResourceFlavor que o representa:

  1. Crie um novo ClusterQueue chamado cq-spot com a coorte definida como all-teams:

    apiVersion: kueue.x-k8s.io/v1beta1
    kind: ClusterQueue
    metadata:
      name: spot-cq
    spec:
      cohort: all-teams # Same cohort as cq-team-a and cq-team-b
      resourceGroups:
      - coveredResources: ["cpu", "memory"]
        flavors:
        - name: spot
          resources:
          - name: "cpu"
            nominalQuota: 40
          - name: "memory"
            nominalQuota: 144Gi

    Como essa ClusterQueue compartilha a mesma coorte com cq-team-a e cq-team-b, a cq-team-a e a cq-team-b podem receber recursos de até 15 solicitações de CPU e 15 Gi de memória.

    kubectl apply -f cq-spot.yaml
    
  2. No Prometheus, observe como as cargas de trabalho admitidas aumentam para cq-team-a e cq-team-b graças à cota adicionada por cq-spot que compartilha a mesma coorte. Ou com este comando:

    watch -n 2 kubectl get clusterqueues -o wide
    
  3. No Prometheus, observe o número de nós no cluster. Ou com este comando:

    watch -n 2 kubectl get nodes -o wide
    
  4. Interrompa os dois scripts pressionando CTRL+c para os namespaces team-a e team-b.

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

  1. Excluir o sistema de cotas do Kueue:

    kubectl delete -n team-a localqueue lq-team-a
    kubectl delete -n team-b localqueue lq-team-b
    kubectl delete clusterqueue cq-team-a
    kubectl delete clusterqueue cq-team-b
    kubectl delete clusterqueue cq-spot
    kubectl delete resourceflavor default
    kubectl delete resourceflavor on-demand
    kubectl delete resourceflavor spot
    
  2. Excluir o manifesto do Kueue:

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

    gcloud container clusters delete kueue-cohort --region=COMPUTE_REGION
    

A seguir