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
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.
Nesse manifesto:
- O ResourceFlavor
on-demand
tem o rótulo definido comocloud.google.com/gke-provisioning: standard
. - O ResourceFlavor
spot
tem o rótulo definido comocloud.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.
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
:
Faça o download do código-fonte do operador do Prometheus:
cd git clone https://github.com/prometheus-operator/kube-prometheus.git
Crie os CustomResourceDefinitions(CRDs):
kubectl create -f kube-prometheus/manifests/setup
Crie os componentes de monitoramento:
kubectl create -f kube-prometheus/manifests
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
Mude para o diretório de trabalho:
cd kubernetes-engine-samples/batch/kueue-cohort
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
Abra a interface da Web do Prometheus em localhost:9090 no navegador.
No Cloud Shell:
Clique em Visualização da Web.
Clique em Alterar porta e defina o número da porta como
9090
.Clique em Alterar e visualizar.
A seguinte UI da Web do Prometheus aparece.
Na caixa de consulta Expressão, insira a consulta a seguir para criar o primeiro painel que monitora as cargas de trabalho ativas da ClusterQueue
cq-team-a
:kueue_pending_workloads{cluster_queue="cq-team-a", status="active"} or kueue_admitted_active_workloads{cluster_queue="cq-team-a"}
Clique em Adicionar painel.
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"}
Clique em Adicionar painel.
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.
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 namespacekueue-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 namespacekueue-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 ClusterRolekueue-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
Configure o RoleBinding para o Google Cloud Managed Service para Prometheus:
Dependendo se você estiver usando um cluster Autopilot ou Standard, será necessário criar o RoleBinding no namespace
gke-gmp-system
ougmp-system
. Esse recurso permite que a conta de serviço do coletor acesse o segredokueue-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
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: 8443 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, uso 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 entre o uso atual da CPU e a 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.
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
.
Inicie um novo terminal e execute este script para gerar um job a cada segundo:
./create_jobs.sh job-team-a.yaml 1
Inicie outro terminal e crie jobs para o namespace
team-b
:./create_jobs.sh job-team-b.yaml 1
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.
Quando houver jobs enfileirados para os ClusterQueues
cq-team-a
ecq-team-b
, interrompa o script do namespaceteam-b
pressionandoCTRL+c
no terminal correspondente.Depois que todos os jobs pendentes do namespace
team-b
forem processados, os jobs do namespaceteam-a
poderão usar os recursos disponíveis emcq-team-b
:kubectl describe clusterqueue cq-team-a
Como
cq-team-a
ecq-team-b
compartilham a mesma coorte chamadaall-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
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 a0
, enquanto os recursos decq-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:
Crie um novo ClusterQueue chamado
cq-spot
com a coorte definida comoall-teams
:Como essa ClusterQueue compartilha a mesma coorte com
cq-team-a
ecq-team-b
, acq-team-a
e acq-team-b
podem receber recursos de até 15 solicitações de CPU e 15 Gi de memória.kubectl apply -f cq-spot.yaml
No Prometheus, observe como as cargas de trabalho admitidas aumentam para
cq-team-a
ecq-team-b
graças à cota adicionada porcq-spot
que compartilha a mesma coorte. Ou com este comando:watch -n 2 kubectl get clusterqueues -o wide
No Prometheus, observe o número de nós no cluster. Ou com este comando:
watch -n 2 kubectl get nodes -o wide
Interrompa os dois scripts pressionando
CTRL+c
para os namespacesteam-a
eteam-b
.