En este documento, se describe cómo habilitar el ajuste de escala automático horizontal de pods (HPA) de Google Cloud Managed Service para Prometheus. Para habilitar el HPA, sigue uno de estos pasos:
- Usa la biblioteca del adaptador de métricas personalizadas de Stackdriver, que desarrolla y mantiene Google Cloud.
- Usa la biblioteca de terceros del adaptador de Prometheus.
Debes elegir un enfoque. No puedes usar ambos porque sus definiciones de recursos se superponen, como se describe en Solución de problemas.
Usa el adaptador de Stackdriver para métricas personalizadas
El adaptador de métricas personalizadas de Stackdriver admite las consultas de métricas del servicio administrado para Prometheus a partir de la versión v0.13.1 del adaptador.
A fin de establecer un ejemplo de configuración de HPA con el adaptador de métricas personalizadas de Stackdriver, haz lo siguiente:
- Configurar la recopilación administrada para tu clúster.
Instala el adaptador de métricas personalizadas de Stackdriver en tu clúster.
kubectl apply -f https://raw.githubusercontent.com/GoogleCloudPlatform/k8s-stackdriver/master/custom-metrics-stackdriver-adapter/deploy/production/adapter_new_resource_model.yaml
Implementa un exportador de métricas de Prometheus de ejemplo y un 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
Con este comando, se implementa una aplicación de exportador que emite la métrica
foo
y un recurso de HPA. El HPA escala esta aplicación hasta 5 réplicas a fin de lograr el valor objetivo para la métricafoo
.Si usas Workload Identity Federation for GKE, también debes otorgar el rol de visualizador de Monitoring a la cuenta de servicio en la que se ejecuta el adaptador. Omite este paso si no tienes Workload Identity Federation for GKE habilitado en tu clúster de Kubernetes.
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
Para definir un recurso PodMonitoring, coloca la siguiente configuración en un archivo llamado
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
Implementa el recurso nuevo de PodMonitoring:
kubectl -n default apply -f podmonitoring.yaml
En unos minutos, Managed Service para Prometheus procesa las métricas recopiladas del exportador y las almacena en Cloud Monitoring mediante un nombre de forma larga. Las métricas de Prometheus se almacenan con las siguientes convenciones:
- El prefijo
prometheus.googleapis.com
. - Este sufijo suele ser uno de los siguientes:
gauge
,counter
,summary
ohistogram
, aunque las métricas sin tipo podrían tener el sufijounknown
ounknown:counter
. Para verificar el sufijo, busca la métrica en Cloud Monitoring mediante el Explorador de métricas.
- El prefijo
Actualiza el HPA implementado para consultar la métrica desde Cloud Monitoring. La métrica
foo
se transfiere comoprometheus.googleapis.com/foo/gauge
. Para que el recurso HorizontalPodAutoscaler implementado pueda consultar la métrica, usa el nombre con formato largo en el HPA implementado, pero debes modificarlo reemplazando todas las barras diagonales (/
) por el carácter de barra vertical (|
):prometheus.googleapis.com|foo|gauge
. Para obtener más información, consulta la sección de Métricas disponibles de Stackdriver del repositorio de adaptadores de métricas personalizadas de Stackdriver.Actualiza el HPA implementado mediante la ejecución del siguiente comando:
kubectl edit hpa custom-metric-prometheus-sd
Cambia el valor del campo
pods.metric.name
defoo
aprometheus.googleapis.com|foo|gauge
. La secciónspec
debería ser como la siguiente:spec: maxReplicas: 5 metrics: - pods: metric: name: prometheus.googleapis.com|foo|gauge target: averageValue: "20" type: AverageValue type: Pods minReplicas: 1
En este ejemplo, la configuración del HPA busca que el valor promedio de la métrica
prometheus.googleapis.com/foo/gauge
sea20
. Debido a que la implementación establece el valor de la métrica en40
, el controlador de HPA aumenta la cantidad de Pods hasta el valor del campomaxReplicas
(5
) para tratar de reducir el valor promedio de la métrica entre todos los Pods.20
.La consulta del HPA se limita al espacio de nombres y al clúster en el que se instala el recurso de HPA, por lo que las métricas idénticas en otros clústeres y espacios de nombres no afectan el ajuste de escala automático.
Para mirar cómo se escala verticalmente la carga de trabajo, ejecuta el siguiente comando:
kubectl get hpa custom-metric-prometheus-sd --watch
El valor del campo
REPLICAS
cambia de1
a5
.NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE custom-metric-prometheus-sd Deployment/custom-metric-prometheus-sd 40/20 1 5 5 *
Para reducir la escala de la implementación verticalmente, actualiza el valor de la métrica de destino para que sea más alto que el valor de la métrica exportada. En este ejemplo, la implementación establece el valor de la métrica
prometheus.googleapis.com/foo/gauge
en40
. Si estableces el valor objetivo en un número mayor que40
, la implementación reducirá la escala verticalmente.Por ejemplo, usa
kubectl edit
para cambiar el valor del campopods.target.averageValue
en la configuración del HPA de20
a100
.kubectl edit hpa custom-metric-prometheus-sd
Modifica la sección de especificaciones para que coincida con la siguiente información:
spec: maxReplicas: 5 metrics: - pods: metric: name: prometheus.googleapis.com|foo|gauge target: averageValue: "100" type: AverageValue type: Pods minReplicas: 1
Para ver cómo se reduce verticalmente la escala de la carga de trabajo, ejecuta el siguiente comando:
kubectl get hpa custom-metric-prometheus-sd --watch
El valor del campo
REPLICAS
cambia de5
a1
. Por diseño, esto sucede con más lentitud que cuando se escala verticalmente la cantidad de Pods:NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE custom-metric-prometheus-sd Deployment/custom-metric-prometheus-sd 40/100 1 5 1 *
Para limpiar el ejemplo implementado, ejecuta los siguientes 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 obtener más información, consulta el ejemplo de Prometheus en el repositorio del adaptador de las métricas personalizadas de Stackdriver o consulta Escala una aplicación.
Usa el adaptador de Prometheus
Las configuraciones existentes de prometheus-adapter se pueden usar para realizar un ajuste de escala automático con solo unos pocos cambios. La configuración de prometheus-adapter para escalar mediante el servicio administrado para Prometheus tiene dos restricciones adicionales en comparación con el escalamiento mediante Prometheus:
Las consultas deben enrutarse a través del proxy de IU de frontend de Prometheus, al igual que cuando consultas el servicio administrado para Prometheus mediante la API o la IU de Prometheus. Para prometheus-adapter, debes editar la implementación
prometheus-adapter
para cambiar el valorprometheus-url
de la siguiente manera:--prometheus-url=http://frontend.NAMESPACE_NAME.svc:9090/
donde NAMESPACE_NAME es el espacio de nombres en el que se implementa el frontend.
No puedes usar un comparador de regex en un nombre de métrica en el campo
.seriesQuery
de la configuración de reglas. En su lugar, debes especificar por completo los nombres de las métricas.
Como los datos pueden tardar un poco más en estar disponibles dentro del servicio administrado para Prometheus en comparación con el procesamiento ascendente de Prometheus, la configuración de un ajuste de escala automático demasiado fácil puede provocar un comportamiento no deseado. Aunque no hay garantía de que los datos se actualicen, por lo general, los datos están disponibles para consultar entre 3 y 7 segundos después de enviarlos al servicio administrado para Prometheus, sin incluir ninguna latencia de red.
Todas las consultas emitidas por prometheus-adapter son de alcance global. Esto significa que si tienes aplicaciones en dos espacios de nombres que emiten métricas con nombre idéntico, una configuración de HPA que usa esa métrica se escala con datos de ambas aplicaciones. Recomendamos usar siempre los filtros namespace
o cluster
en tu PromQL para evitar el escalamiento con datos incorrectos.
Para establecer una configuración de HPA de ejemplo con prometheus-adapter y la colección administrada, sigue estos pasos:
- Configurar la recopilación administrada para tu clúster.
- Implementa el proxy de la IU del frontend de Prometheus en tu clúster. Si usas Workload Identity Federation for GKE, también debes configurar y autorizar una cuenta de servicio.
- Implementa los manifiestos en el directorio
examples/hpa/
dentro del repositorio de prometheus-engine:example-app.yaml
: Un ejemplo de implementación y servicio que emite métricas.pod-monitoring.yaml
: Un recurso que configura la recopilación de las métricas de ejemplo.hpa.yaml
: El recurso de HPA que configura el escalamiento para tu carga de trabajo.
Asegúrate de que
prometheus-adapter
esté instalado en tu clúster. Para ello, implementa el manifiesto de instalación de ejemplo en tu clúster. Este manifiesto se configuró para lo siguiente:- Consultar un proxy de frontend implementado en el espacio de nombres
default
. - Emitir PromQL para calcular y mostrar la métrica
http_requests_per_second
de la implementación de ejemplo.
- Consultar un proxy de frontend implementado en el espacio de nombres
Ejecuta los siguientes comandos, cada uno en una sesión de terminal independiente:
- Genera una carga HTTP en el servicio
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"
- Mira el escalador automático horizontal del pod:
kubectl get hpa prometheus-example-app --watch
- Mira el escalamiento vertical de la carga de trabajo:
kubectl get po -lapp.kubernetes.io/name=prometheus-example-app --watch
- Genera una carga HTTP en el servicio
Detén la generación de carga HTTP mediante Ctrl+C y observa cómo se reduce la escala de la carga de trabajo.
Soluciona problemas
El adaptador de métricas personalizadas de Stackdriver usa definiciones de recursos con los mismos nombres que los del adaptador de Prometheus, prometheus-Adapter. Esta superposición en los nombres significa que ejecutar más de un adaptador en el mismo clúster genera errores.
Instala el adaptador de Prometheus en un clúster que antes tenía las métricas personalizadas instaladas. El adaptador de Stackdriver instalado podría generar errores como FailedGetObjectMetric
debido a los nombres con conflictos. Para resolver esto, es posible que debas borrar los apiservices v1beta1.external.metrics.k8s.io
, v1beta1.custom.metrics.k8s.io
y v1beta2.custom.metrics.k8s.io
que registró previamente el adaptador de métricas personalizadas.
Sugerencias para solucionar problemas:
Algunas métricas del sistema de Cloud Monitoring, como las métricas de Pub/Sub, se retrasan 60 segundos o más. A medida que el adaptador de Prometheus ejecuta consultas con la marca de tiempo actual, consultar estas métricas mediante el adaptador de Prometheus podría generar datos de forma incorrecta. Para consultar las métricas retrasadas, usa el modificador
offset
en PromQL para cambiar la compensación de tiempo de tu consulta en la cantidad necesaria.Para verificar que el proxy de la IU de frontend funcione según lo previsto y que no haya problemas con los permisos, ejecuta el siguiente comando en una terminal:
kubectl -n NAMESPACE_NAME port-forward svc/frontend 9090
A continuación, abre otra terminal y ejecuta el siguiente comando:
curl --silent 'localhost:9090/api/v1/series?match%5B%5D=up'
Cuando el proxy de IU de frontend funciona de forma correcta, la respuesta en la segunda terminal es similar a la siguiente:
curl --silent 'localhost:9090/api/v1/series?match%5B%5D=up' | jq . { "status": "success", "data": [ ... ] }
Si recibes un error 403, entonces el proxy de la IU de frontend no está configurado de forma correcta. Para obtener información sobre cómo resolver un error 403, consulta la guía Configura y autoriza una cuenta de servicio.
Para verificar que el apiserver de métricas personalizadas esté disponible, ejecuta el siguiente comando:
kubectl get apiservices.apiregistration.k8s.io v1beta1.custom.metrics.k8s.io
Cuando el apiserver está disponible, la respuesta es similar a la siguiente:
$ 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 que tu HPA funcione según lo previsto, ejecuta el siguiente 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 Cuando la respuesta contiene una sentencia como
FailedGetPodsMetric
, el HPA falla. A continuación, se ilustra una respuesta a la llamadadescribe
cuando el HPA falla:$ 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 Cuando el HPA falle, asegúrate de generar métricas con el
load-generator
. Puedes verificar la API de métricas personalizadas directamente con el siguiente comando:kubectl get --raw "/apis/custom.metrics.k8s.io/v1beta1/" | jq .
Un resultado correcto debería verse de la siguiente manera:
$ 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" ] } ] }
Si no hay métricas, no habrá datos en
"resources"
en el resultado, por ejemplo:kubectl get --raw "/apis/custom.metrics.k8s.io/v1beta1/" | jq . { "kind": "APIResourceList", "apiVersion": "v1", "groupVersion": "custom.metrics.k8s.io/v1beta1", "resources": [] }