En este documento se describe cómo habilitar el escalado automático horizontal de pods (HPA) en Google Cloud Managed Service para Prometheus. Para habilitar HPA, puedes hacer lo siguiente:
- Con KEDA (Kubernetes Event-driven Autoscaling), una solución de código abierto que ha completado el programa de incubación de la Cloud Native Computing Foundation.
- Con la biblioteca Custom Metrics Stackdriver Adapter, desarrollada y mantenida por Google Cloud.
- Usando la biblioteca de terceros Prometheus Adapter.
No puedes usar el adaptador de Stackdriver y el de Prometheus al mismo tiempo en el mismo clúster porque sus definiciones de recursos se solapan, tal como se describe en la sección Solución de problemas. Recomendamos elegir solo una solución para HPA.
Usar KEDA
KEDA (Kubernetes Event-driven Autoscaling) es el autoescalador más reciente que usa métricas de Prometheus y se está convirtiendo en una solución popular en la comunidad de Prometheus.
Para empezar, consulta la documentación de KEDA sobre la integración con Google Cloud Managed Service para Prometheus.
Usar el adaptador de Stackdriver de métricas personalizadas
El adaptador de Stackdriver de métricas personalizadas admite consultas de métricas de Managed Service para Prometheus a partir de la versión v0.13.1 del adaptador.
Para configurar un ejemplo de HPA con el adaptador de métricas personalizadas de Stackdriver, siga estos pasos:
- Configure la recogida gestionada en su clúster.
Instala el adaptador de Stackdriver de métricas personalizadas 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
Despliega un exportador de métricas de Prometheus de ejemplo y un recurso 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
Este comando implementa una aplicación de exportador que emite la métrica
foo
y un recurso HPA. El HPA escala esta aplicación hasta 5 réplicas para alcanzar el valor objetivo de la métricafoo
.Si usas Workload Identity Federation para GKE, también debes asignar el rol Lector de Monitoring a la cuenta de servicio con la que se ejecuta el adaptador. Sáltate este paso si no tienes habilitada la federación de Workload Identity para GKE 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
Define un recurso de PodMonitoring colocando 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
Despliega el nuevo recurso de PodMonitoring:
kubectl -n default apply -f podmonitoring.yaml
En un par de minutos, Managed Service para Prometheus procesa las métricas recogidas del exportador y las almacena en Cloud Monitoring con un nombre largo. Las métricas de Prometheus se almacenan con las siguientes convenciones:
- El prefijo
prometheus.googleapis.com
. - Este sufijo suele ser
gauge
,counter
,summary
ohistogram
, aunque las métricas sin tipo pueden tener el sufijounknown
ounknown:counter
. Para verificar el sufijo, busca la métrica en Cloud Monitoring con el explorador de métricas.
- El prefijo
Actualiza el HPA desplegado para consultar la métrica de Cloud Monitoring. La métrica
foo
se ingiere comoprometheus.googleapis.com/foo/gauge
. Para que el recurso HorizontalPodAutoscaler implementado pueda consultar la métrica, debes usar el nombre completo en el HPA implementado, pero tienes que modificarlo sustituyendo 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 Métricas disponibles en Stackdriver del repositorio del adaptador de Stackdriver de métricas personalizadas.Para actualizar el HPA desplegado, ejecuta el 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 tener este aspecto: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 de HPA busca que el valor medio de la métrica
prometheus.googleapis.com/foo/gauge
sea20
. Como el valor de la métrica de Deployment es40
, el controlador de HPA aumenta el número de pods hasta el valor del campomaxReplicas
(5
) para intentar reducir el valor medio de la métrica en todos los pods a20
.La consulta de HPA se limita al espacio de nombres y al clúster en los que se instala el recurso de HPA, por lo que las métricas idénticas de otros clústeres y espacios de nombres no afectan al autoescalado.
Para ver cómo se escala 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, actualice el valor de la métrica objetivo para que sea superior al valor de la métrica exportada. En este ejemplo, Deployment define el valor de la métrica
prometheus.googleapis.com/foo/gauge
como40
. Si asignas al valor objetivo un número superior a40
, la implementación se reducirá.Por ejemplo, usa
kubectl edit
para cambiar el valor del campopods.target.averageValue
en la configuración de HPA de20
a100
.kubectl edit hpa custom-metric-prometheus-sd
Modifica la sección de especificaciones para que coincida con lo siguiente:
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 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 ocurre más lentamente que cuando se aumenta el 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 limpiar el ejemplo desplegado, 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 Stackdriver de métricas personalizadas o consulta Escalar una aplicación.
Usar el adaptador de Prometheus
Las configuraciones de prometheus-adapter se pueden usar para autoescalar con solo unos pocos cambios. Configurar prometheus-adapter para escalar con Managed Service para Prometheus tiene dos restricciones adicionales en comparación con el escalado con Prometheus upstream:
Las consultas deben enrutarse a través del proxy de la interfaz de usuario de frontend de Prometheus, al igual que cuando se consulta Managed Service para Prometheus mediante la API o la interfaz de usuario de Prometheus. En prometheus-adapter, debes editar el
prometheus-adapter
Deployment para cambiar elprometheus-url
valor 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 puede usar un comparador de expresiones regulares (
=~
o!~
) en un nombre de métrica en el campo.seriesQuery
de la configuración de reglas. En su lugar, debe especificar los nombres de las métricas por completo. Para ver algunas soluciones alternativas, consulta Compatibilidad con PromQL.
Como los datos pueden tardar un poco más en estar disponibles en Managed Service para Prometheus en comparación con Prometheus upstream, configurar una lógica de autoescalado demasiado impaciente puede provocar un comportamiento no deseado. Aunque no se garantiza la actualización de los datos, estos suelen estar disponibles para consultarse entre 3 y 7 segundos después de enviarse a Managed Service para Prometheus, sin incluir la latencia de la red.
Todas las consultas emitidas por prometheus-adapter son de ámbito global. Esto significa que, si tienes aplicaciones en dos espacios de nombres que emiten métricas con el mismo nombre, una configuración de HPA que use esa métrica se escalará usando datos de ambas aplicaciones. Te recomendamos que siempre uses filtros namespace
o cluster
en tu PromQL para evitar el escalado con datos incorrectos.
Para configurar un ejemplo de HPA con prometheus-adapter y la recogida gestionada, sigue estos pasos:
- Configure la recogida gestionada en su clúster.
- Despliega el proxy de la interfaz de usuario de frontend de Prometheus en tu clúster. Si usas Workload Identity Federation para GKE, también debes configurar y autorizar una cuenta de servicio.
- Despliega los manifiestos en el directorio
examples/hpa/
del repositorio prometheus-engine:example-app.yaml
: una implementación y un servicio de ejemplo que emiten métricas.pod-monitoring.yaml
: un recurso que configura el raspado de las métricas de ejemplo.hpa.yaml
: el recurso HPA que configura el escalado de tu carga de trabajo.
Asegúrate de que
prometheus-adapter
esté instalado en tu clúster. Para ello, puedes implementar el manifiesto de instalación de ejemplo en tu clúster. Este archivo de manifiesto está configurado para lo siguiente:- Consulta un proxy de frontend implementado en el espacio de nombres
default
. - Ejecuta PromQL para calcular y devolver la métrica
http_requests_per_second
de la implementación de ejemplo.
- Consulta un proxy de frontend implementado en el espacio de nombres
Ejecuta los siguientes comandos, cada uno en una sesión de terminal independiente:
- Genera 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"
- Consulta la herramienta de adaptación dinámica de pods horizontal:
kubectl get hpa prometheus-example-app --watch
- Observa cómo se escala la carga de trabajo:
kubectl get po -lapp.kubernetes.io/name=prometheus-example-app --watch
- Genera carga HTTP en el servicio
Detén la generación de carga HTTP con Ctrl+C y observa cómo se reduce la carga de trabajo.
Solución de problemas
El adaptador de Stackdriver de métricas personalizadas usa definiciones de recursos con los mismos nombres que los del adaptador de Prometheus, prometheus-adapter. Esta coincidencia de nombres significa que, si se ejecuta más de un adaptador en el mismo clúster, se producirán errores.
Si instalas el adaptador de Prometheus en un clúster que ya tenía instalado el adaptador de Stackdriver Custom Metrics, es posible que se produzcan errores como FailedGetObjectMetric
debido a que los nombres coinciden. Para solucionar este problema, es posible que tengas que eliminar las APIs v1beta1.external.metrics.k8s.io
, v1beta1.custom.metrics.k8s.io
y v1beta2.custom.metrics.k8s.io
apiservices que haya registrado anteriormente el adaptador de métricas personalizadas.
Consejos para solucionar problemas:
Algunas métricas del sistema de Cloud Monitoring, como las métricas de Pub/Sub, tienen un retraso de 60 segundos o más. Como Prometheus Adapter ejecuta consultas con la marca de tiempo actual, es posible que al consultar estas métricas con Prometheus Adapter no se obtengan datos. Para consultar métricas con retraso, usa el modificador
offset
en PromQL para cambiar el desfase de tiempo de tu consulta en la cantidad necesaria.Para verificar que el proxy de la interfaz de usuario frontend funciona correctamente y que no hay problemas con los permisos, ejecuta el siguiente comando en un terminal:
kubectl -n NAMESPACE_NAME port-forward svc/frontend 9090
A continuación, abre otro terminal y ejecuta el siguiente comando:
curl --silent 'localhost:9090/api/v1/series?match%5B%5D=up'
Si el proxy de la interfaz de usuario frontend funciona correctamente, la respuesta en la segunda terminal será similar a la siguiente:
curl --silent 'localhost:9090/api/v1/series?match%5B%5D=up' | jq . { "status": "success", "data": [ ... ] }
Si recibes un error 403, significa que el proxy de la interfaz de usuario frontend no está configurado correctamente. Para obtener información sobre cómo resolver un error 403, consulta la guía Configurar y autorizar 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 funciona correctamente, 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 instrucción como
FailedGetPodsMetric
, significa que el HPA falla. A continuación se muestra 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 Si el HPA falla, asegúrate de generar métricas con
load-generator
. Puede consultar la API de métricas personalizadas directamente con el comando:kubectl get --raw "/apis/custom.metrics.k8s.io/v1beta1/" | jq .
El resultado correcto es similar al siguiente:
$ 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": [] }