5 min read | by Jordi Prats
Using an external metrics provider (Kubernetes 1.10+) we can use an HorizontalPodAutoscaler to automatically scale applications using any metric collected by Prometheus. Let's take a look on how to configure it
To test this out we'll need to have prometheus and prometheus-adapter installed, to do so we can use it's community-supported helm chart. First we'll need to add it's repository:
$ helm repo add prometheus-community https://prometheus-community.github.io/helm-charts helm repo update
Then we'll have to install both charts:
$ helm install prometheus prometheus-community/prometheus --namespace prometheus $ helm install prometheus-adapter prometheus-community/prometheus-adapter --namespace prometheus
We are going to use the prometheus-adapter to be able to present prometheus metrics to the cluster in a way it can understand and therefore suitable for autoscaling using an HorizontalPodAutoscaler
Let's suppose we have an application that exposes metrics using /metrics, first we'll need to let prometheus know this endpoint can be scrapped using the following annotations on the Pod template:
apiVersion: apps/v1 kind: Deployment metadata: name: demo-prometheus-enabled-app spec: selector: matchLabels: app: metricsdemo template: metadata: annotations: prometheus.io/path: "/metrics" prometheus.io/scrape: "true" prometheus.io/port: "8000" labels: app: metricsdemo spec: containers: - name: metricsdemo image: "jordiprats/demoappprometrics:1.0"
Prometheus once it sees these annotations, it will start scrapping it's metrics. Once we have the metrics available on prometheus, they might not be entirely suitable to use it together with the HorizontalPodAutoscaler. We can transform them using some rules, to do so we'll have to update the prometheus-adapter values to include the rules we need using the rules.custom option.
For example, let's assume the application publishes a metricsdemo_requests that we want to average within a 2 minutes window and then calculate it's rate. To do so we would need to create the following rule:
rules: custom: - seriesQuery: "metricsdemo_requests" resources: overrides: kubernetes_namespace: resource: metricsdemo kubernetes_pod_name: resource: pod name: matches: "^(.*)" as: "\u0024{1}_avg" metricsQuery: "sum(rate(<<.Series>>[2m])) by (<<.GroupBy>>)"
Once we push this config to Kubernetes, it will take a while for it to become available. We can check when it's available using the following command:
$ kubectl get --raw /apis/custom.metrics.k8s.io/v1beta1 | python -m json.tool { "kind": "APIResourceList", "apiVersion": "v1", "groupVersion": "custom.metrics.k8s.io/v1beta1", "resources": [ { "name": "pods/metricsdemo_requests_avg", "singularName": "", "namespaced": true, "kind": "MetricValueList", "verbs": [ "get" ] }, { "name": "namespaces/metricsdemo_requests_avg", "singularName": "", "namespaced": false, "kind": "MetricValueList", "verbs": [ "get" ] } ] }
Once it's available, we can start creating HorizontalPodAutoscaler objects using it, for example:
apiVersion: autoscaling/v1 kind: HorizontalPodAutoscaler metadata: name: demo-prometheus-enabled-app labels: {{- include "metricsdemo.labels" . | nindent 4 }} spec: scaleTargetRef: apiVersion: apps/v1 kind: Deployment name: demo-prometheus-enabled-app minReplicas: 3 maxReplicas: 30 metrics: - type: Pods pods: metricName: metricsdemo_requests_avg targetAverageValue: 10
Once we apply it, it will control the number of replicas of the Deployment so we won't be able to use kubectl scale:
$ kubectl describe hpa metricsdemo -n metricsdemo Name: metricsdemo Namespace: metricsdemo (...) Reference: Deployment/metricsdemo Metrics: ( current / target ) "metricsdemo_requests_avg" on pods: 0 / 10 Min replicas: 3 Max replicas: 30 Deployment pods: 3 current / 3 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 metricsdemo_requests_avg ScalingLimited True TooFewReplicas the desired replica count is less than the minimum replica count Events: <none>
As soon as the metrics reaches the configured threshold, the HPA will kicks in changing the number of replicas of the Deployment (please notice the Deployment pods line)
$ kubectl describe hpa -n metricsdemo Name: metricsdemo Namespace: metricsdemo (...) Reference: Deployment/metricsdemo Metrics: ( current / target ) "metricsdemo_requests_avg" on pods: 794791m / 10 Min replicas: 3 Max replicas: 30 Deployment pods: 3 current / 6 desired Conditions: Type Status Reason Message ---- ------ ------ ------- AbleToScale True SucceededRescale the HPA controller was able to update the target scale to 6 ScalingActive True ValidMetricFound the HPA was able to successfully calculate a replica count from pods metric metricsdemo_requests_avg ScalingLimited True ScaleUpLimit the desired replica count is increasing faster than the maximum scale rate (...) $ kubectl describe hpa -n metricsdemo Name: metricsdemo Namespace: metricsdemo (...) Reference: Deployment/metricsdemo Metrics: ( current / target ) "metricsdemo_requests_avg" on pods: 794791m / 10 Min replicas: 3 Max replicas: 30 Deployment pods: 6 current / 6 desired Conditions: Type Status Reason Message ---- ------ ------ ------- AbleToScale False FailedUpdateScale the HPA controller was unable to update the target scale: Operation cannot be fulfilled on deployments.apps "metricsdemo": the object has been modified; please apply your changes to the latest version and try again ScalingActive True ValidMetricFound the HPA was able to successfully calculate a replica count from pods metric metricsdemo_requests_avg ScalingLimited True ScaleUpLimit the desired replica count is increasing faster than the maximum scale rate (...) $ kubectl describe hpa -n metricsdemo Name: metricsdemo Namespace: metricsdemo (...) Reference: Deployment/metricsdemo Metrics: ( current / target ) "metricsdemo_requests_avg" on pods: 0 / 10 Min replicas: 3 Max replicas: 30 Deployment pods: 24 current / 30 desired Conditions: Type Status Reason Message ---- ------ ------ ------- AbleToScale True SucceededRescale the HPA controller was able to update the target scale to 30 ScalingActive True ValidMetricFound the HPA was able to successfully calculate a replica count from pods metric metricsdemo_requests_avg ScalingLimited True TooManyReplicas the desired replica count is more than the maximum replica count Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal SuccessfulRescale 11m horizontal-pod-autoscaler New size: 3; reason: Current number of replicas below Spec.MinReplicas (...)
We can achieve similar results using datadog as an external metrics provider
Posted on 05/04/2022