Neste documento, descrevemos como ativar o escalonamento automático de pods horizontal (HPA) para o Google Cloud Managed Service para Prometheus. É possível ativar o HPA de uma das seguintes maneiras:
- Uso da biblioteca Custom Metrics Stackdriver Adapter, desenvolvida e com suporte do Google Cloud.
- Usar a biblioteca de terceiros Prometheus Adapter.
É preciso escolher uma abordagem ou outra. Não é possível usar ambos porque as definições dos recursos se sobrepõem, conforme descrito em Solução de problemas.
Usar o adaptador de métricas personalizadas do Stackdriver
O adaptador de métricas personalizadas do Stackdriver dá suporte a métricas de consulta do Managed Service para Prometheus, começando com a versão v0.13.1 do adaptador.
Para definir um exemplo de configuração do HPA usando o adaptador de métricas personalizadas do Stackdriver, faça o seguinte:
- Configure a coleção gerenciada no cluster.
Instale o adaptador de métricas personalizadas do Stackdriver no cluster.
kubectl apply -f https://raw.githubusercontent.com/GoogleCloudPlatform/k8s-stackdriver/master/custom-metrics-stackdriver-adapter/deploy/production/adapter_new_resource_model.yaml
Implante um exportador de métricas do Prometheus e um recurso de HPA:
kubectl apply -f https://raw.githubusercontent.com/GoogleCloudPlatform/k8s-stackdriver/master/custom-metrics-stackdriver-adapter/examples/prometheus-to-sd/custom-metrics-prometheus-sd.yaml
Esse comando implanta um aplicativo exportador que emite a métrica
foo
e um recurso HPA. O HPA escalona esse aplicativo em até cinco réplicas para atingir o valor pretendido da métricafoo
.Se você usar a Identidade da carga de trabalho, também precisará conceder acesso ao papel de Leitor do Monitoring para a conta de serviço em que o adaptador é executado. Pule esta etapa se você não tiver a Identidade da carga de trabalho ativada no seu cluster do Kubernetes; especificado.
export PROJECT_NUMBER=$(gcloud projects describe PROJECT_ID --format 'get(projectNumber)') gcloud projects add-iam-policy-binding projects/PROJECT_ID \ --role roles/monitoring.viewer \ --member=principal://iam.googleapis.com/projects/$PROJECT_NUMBER/locations/global/workloadIdentityPools/PROJECT_ID.svc.id.goog/subject/ns/custom-metrics/sa/custom-metrics-stackdriver-adapter
Defina um recurso PodMonitoring colocando a seguinte configuração em um arquivo chamado
podmonitoring.yaml
.apiVersion: monitoring.googleapis.com/v1 kind: PodMonitoring metadata: name: prom-example spec: selector: matchLabels: run: custom-metric-prometheus-sd endpoints: - port: 8080 interval: 30s
Implante o novo recurso PodMonitoring:
kubectl -n default apply -f podmonitoring.yaml
Em alguns minutos, o Managed Service para Prometheus processa as métricas extraídas do exportador e as armazena no Cloud Monitoring usando um nome de formato longo. As métricas do Prometheus são armazenadas com as seguintes convenções:
- O prefixo
prometheus.googleapis.com
. - Esse sufixo geralmente é
gauge
,counter
,summary
ouhistogram
, embora as métricas sem tipo possam ter o sufixounknown
ouunknown:counter
. Para verificar o sufixo, procure a métrica no Cloud Monitoring usando o Metrics Explorer.
- O prefixo
Atualizar o HPA implantado para consultar a métrica do Cloud Monitoring. A métrica
foo
é ingerida comoprometheus.googleapis.com/foo/gauge
. Para tornar a métrica consultável pelo recurso HorizontalPodAutoscaler implantado, use o nome de formato longo no HPA implantado, mas é necessário modificá-lo substituindo todas as barras (/
) pelo caractere de barra vertical (|
):prometheus.googleapis.com|foo|gauge
. Para saber mais, consulte a seção Métricas disponíveis no Stackdriver do repositório de métricas personalizadas do Stackdriver Adapter.Atualize o HPA implantado executando o seguinte comando:
kubectl edit hpa custom-metric-prometheus-sd
Mude o valor do campo
pods.metric.name
defoo
paraprometheus.googleapis.com|foo|gauge
. A seçãospec
será parecida com o exemplo a seguir:spec: maxReplicas: 5 metrics: - pods: metric: name: prometheus.googleapis.com|foo|gauge target: averageValue: "20" type: AverageValue type: Pods minReplicas: 1
Neste exemplo, a configuração do HPA procura o valor médio da métrica
prometheus.googleapis.com/foo/gauge
como20
. Como a implantação define o valor da métrica como40
, o controlador HPA aumenta o número de pods até o valor do campomaxReplicas
(5
) para tentar reduzir o valor médio da métrica em todos os pods para20
.O escopo da consulta HPA é do namespace e do cluster em que o recurso HPA está instalado. Portanto, métricas idênticas em outros clusters e namespaces não afetam o escalonamento automático.
Para observar o aumento da carga de trabalho, execute o seguinte comando:
kubectl get hpa custom-metric-prometheus-sd --watch
O valor do campo
REPLICAS
muda de1
para5
.NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE custom-metric-prometheus-sd Deployment/custom-metric-prometheus-sd 40/20 1 5 5 *
Para reduzir a implantação, atualize o valor da métrica de destino para ser maior que o valor da métrica exportada. Neste exemplo, a implantação define o valor da métrica
prometheus.googleapis.com/foo/gauge
como40
. Se você definir o valor de destino como um número maior que40
, a implantação reduzirá a escala vertical.Por exemplo, use
kubectl edit
para alterar o valor do campopods.target.averageValue
na configuração do HPA de20
para100
.kubectl edit hpa custom-metric-prometheus-sd
Modifique a seção de especificações para que corresponda ao seguinte:
spec: maxReplicas: 5 metrics: - pods: metric: name: prometheus.googleapis.com|foo|gauge target: averageValue: "100" type: AverageValue type: Pods minReplicas: 1
Para observar a redução da carga de trabalho, execute o seguinte comando:
kubectl get hpa custom-metric-prometheus-sd --watch
O valor do campo
REPLICAS
muda de5
para1
. Por padrão, isso ocorre mais lentamente do que ao escalonar o número de pods:NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE custom-metric-prometheus-sd Deployment/custom-metric-prometheus-sd 40/100 1 5 1 *
Para limpar o exemplo implantado, execute os seguintes comandos:
kubectl delete -f https://raw.githubusercontent.com/GoogleCloudPlatform/k8s-stackdriver/master/custom-metrics-stackdriver-adapter/deploy/production/adapter_new_resource_model.yaml kubectl delete -f https://raw.githubusercontent.com/GoogleCloudPlatform/k8s-stackdriver/master/custom-metrics-stackdriver-adapter/examples/prometheus-to-sd/custom-metrics-prometheus-sd.yaml kubectl delete podmonitoring/prom-example
Para ver mais informações, consulte o exemplo do Prometheus no repositório de adaptadores de métricas personalizadas do Stackdriver ou consulte Como escalonar um aplicativo.
Usar o adaptador do Prometheus
As configurações existentes do prometheus-adapter podem ser usadas para escalonamento automático com apenas algumas alterações. A configuração do prometheus-adapter para escalonamento usando o Managed Service para Prometheus tem duas restrições extras em comparação com o escalonamento usando o upstream do Prometheus:
As consultas precisam ser roteadas pelo proxy da interface do front-end do Prometheus, da mesma forma que acontece ao consultar o Managed Service para Prometheus usando a API ou a interface do Prometheus. Para o prometheus-adapter, é necessário editar a implantação do
prometheus-adapter
para alterar o valor doprometheus-url
da seguinte maneira:--prometheus-url=http://frontend.NAMESPACE_NAME.svc:9090/
em que NAMESPACE_NAME é o namespace em que o front-end é implantado.
Não é possível usar uma correspondência de regex em um nome de métrica no campo
.seriesQuery
da configuração de regras. Em vez disso, você precisa especificar totalmente os nomes das métricas.
Como os dados podem demorar um pouco mais para ficar disponíveis no Managed Service para Prometheus em comparação com o upstream do Prometheus, configurar uma lógica de escalonamento automático excessivamente ávida pode causar comportamentos indesejados. Não há garantia de atualização de dados, mas eles geralmente ficam disponíveis para consulta de três a sete segundos após o envio para o Managed Service para Prometheus, excluindo qualquer latência de rede.
Todas as consultas emitidas pelo adaptador de prometheus têm escopo global. Isso significa que,
se você tiver aplicativos em dois namespaces que emitem métricas com nomes idênticos,
uma configuração do HPA que usa essa métrica é escalonada usando dados dos dois
aplicativos. Recomendamos sempre usar filtros namespace
ou cluster
na
PromQL para evitar o escalonamento usando dados incorretos.
Para definir uma configuração de HPA de exemplo usando o prometheus-adapter e a coleção gerenciada, siga estas etapas:
- Configure a coleção gerenciada no cluster.
- Implante o proxy de IU do front-end do Prometheus no cluster. Se você usar a Identidade da carga de trabalho, também precisará configurar e autorizar uma conta de serviço.
- Implante os manifestos no diretório
examples/hpa/
no repositório do prometheus-engine:example-app.yaml
: um exemplo de implantação e serviço que emite métricas.pod-monitoring.yaml
: um recurso que configura a raspagem de dados de métricas de exemplo.hpa.yaml
: o recurso HPA que configura o escalonamento da carga de trabalho.
Verifique se
prometheus-adapter
está instalado no cluster. Para isso, implante o exemplo de manifesto de instalação no cluster. Esse manifesto é configurado para o seguinte:- Consultar um proxy de front-end implantado no namespace
default
. - Solicitar que o PromQL calcule e retorne a métrica
http_requests_per_second
da implantação de exemplo.
- Consultar um proxy de front-end implantado no namespace
Execute os seguintes comandos, cada um em uma sessão de terminal separada:
- Gere a carga HTTP no serviço
prometheus-example-app
:kubectl run -i --tty load-generator --rm --image=busybox:1.28 --restart=Never -- /bin/sh -c "while sleep 0.01; do wget -q -O- http://prometheus-example-app; done"
- Observe o escalonador automático horizontal de pods:
kubectl get hpa prometheus-example-app --watch
- Observe o escalonamento vertical da carga de trabalho:
kubectl get po -lapp.kubernetes.io/name=prometheus-example-app --watch
- Gere a carga HTTP no serviço
Para parar a geração de carga HTTP, use Ctrl+C e observe a redução da escala vertical da carga de trabalho.
Solução de problemas
O adaptador de métricas personalizadas do Stackdriver usa definições de recursos com os mesmos nomes do adaptador Prometheus, prometheus-adapter. Essa sobreposição de nomes significa que a execução de mais de um adaptador no mesmo cluster causa erros.
A instalação do Adaptador do Prometheus em um cluster que tinha o Adaptador das métricas
personalizadas do Stackdriver instalado pode gerar erros, como
FailedGetObjectMetric
devido a nomes de colisão. Para resolver esse problema, talvez seja necessário
excluir os apiservices v1beta1.external.metrics.k8s.io
,
v1beta1.custom.metrics.k8s.io
e v1beta2.custom.metrics.k8s.io
registrados anteriormente pelo adaptador de métricas personalizadas.
Dicas para solução de problemas:
Algumas métricas do sistema do Cloud Monitoring, como as métricas do Pub/Sub, têm um atraso de 60 segundos ou mais. Como o adaptador do Prometheus executa consultas usando a marcação de tempo atual, a consulta dessas métricas com o adaptador do Prometheus pode não resultar em dados. Para consultar métricas atrasadas, use o modificador
offset
no PromQL para alterar o ajuste de horário da consulta pelo valor necessário.Para verificar se o proxy de IU de front-end está funcionando como esperado e se não há problemas com permissões, execute o seguinte comando em um terminal:
kubectl -n NAMESPACE_NAME port-forward svc/frontend 9090
Em seguida, abra outro terminal e execute o seguinte comando:
curl --silent 'localhost:9090/api/v1/series?match%5B%5D=up'
Quando o proxy de IU de front-end estiver funcionando corretamente, a resposta no segundo terminal será semelhante a esta:
curl --silent 'localhost:9090/api/v1/series?match%5B%5D=up' | jq . { "status": "success", "data": [ ... ] }
Se você receber um erro 403, significa que o proxy de IU de front-end não está configurado corretamente. Para informações sobre como resolver um erro 403, consulte o guia Configurar e autorizar uma conta de serviço.
Para verificar se o apiserver de métricas personalizadas está disponível, execute o seguinte comando:
kubectl get apiservices.apiregistration.k8s.io v1beta1.custom.metrics.k8s.io
Quando o apiserver está disponível, a resposta é semelhante a esta:
$ kubectl get apiservices.apiregistration.k8s.io v1beta1.custom.metrics.k8s.io NAME SERVICE AVAILABLE AGE v1beta1.custom.metrics.k8s.io monitoring/prometheus-adapter True 33m
Para verificar se o HPA está funcionando conforme o esperado, execute o seguinte comando:
$ kubectl describe hpa prometheus-example-app Name: prometheus-example-app Namespace: default Labels:
Annotations: Reference: Deployment/prometheus-example-app Metrics: ( current / target ) "http_requests_per_second" on pods: 11500m / 10 Min replicas: 1 Max replicas: 10 Deployment pods: 2 current / 2 desired Conditions: Type Status Reason Message ---- ------ ------ ------- AbleToScale True ReadyForNewScale recommended size matches current size ScalingActive True ValidMetricFound the HPA was able to successfully calculate a replica count from pods metric http_requests_per_second ScalingLimited False DesiredWithinRange the desired count is within the acceptable range Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal SuccessfulRescale 47s horizontal-pod-autoscaler New size: 2; reason: pods metric http_requests_per_second above target Quando a resposta contém uma instrução como
FailedGetPodsMetric
, o HPA falha. Veja a seguir uma resposta à chamadadescribe
quando o HPA falhar:$ kubectl describe hpa prometheus-example-app Name: prometheus-example-app Namespace: default Reference: Deployment/prometheus-example-app Metrics: ( current / target ) "http_requests_per_second" on pods:
/ 10 Min replicas: 1 Max replicas: 10 Deployment pods: 1 current / 1 desired Conditions: Type Status Reason Message ---- ------ ------ ------- AbleToScale True ReadyForNewScale recommended size matches current size ScalingActive False FailedGetPodsMetric the HPA was unable to compute the replica count: unable to get metric http_requests_per_second: unable to fetch metrics from custom metrics API: the server could not find the metric http_requests_per_second for pods ScalingLimited False DesiredWithinRange the desired count is within the acceptable range Events: Type Reason Age From Message ---- ------ ---- ---- ------- Warning FailedGetPodsMetric 104s (x11 over 16m) horizontal-pod-autoscaler unable to get metric http_requests_per_second: unable to fetch metrics from custom metrics API: the server could not find the metric http_requests_per_second for pods Quando o HPA falhar, verifique se você está gerando métricas com o
load-generator
. Verifique a API de métricas personalizadas diretamente com o comando:kubectl get --raw "/apis/custom.metrics.k8s.io/v1beta1/" | jq .
Uma saída bem-sucedida será semelhante a esta:
$ kubectl get --raw "/apis/custom.metrics.k8s.io/v1beta1/" | jq . { "kind": "APIResourceList", "apiVersion": "v1", "groupVersion": "custom.metrics.k8s.io/v1beta1", "resources": [ { "name": "namespaces/http_requests_per_second", "singularName": "", "namespaced": false, "kind": "MetricValueList", "verbs": [ "get" ] }, { "name": "pods/http_requests_per_second", "singularName": "", "namespaced": true, "kind": "MetricValueList", "verbs": [ "get" ] } ] }
Se não houver métricas, não haverá dados em
"resources"
na saída, por exemplo:kubectl get --raw "/apis/custom.metrics.k8s.io/v1beta1/" | jq . { "kind": "APIResourceList", "apiVersion": "v1", "groupVersion": "custom.metrics.k8s.io/v1beta1", "resources": [] }