Масштабирование приложения в Kubernetes на основе метрик из Prometheus
Распространённая ситуация: у вас есть несколько приложений, у одного из них пиковая нагрузка приходится на дневное время, а в другие часы к нему никто не обращается (либо обращаются, но редко); при этом другим приложениям мощности кластера могут пригодиться и в ночное время. В качестве примера таких приложений можно привести веб-сервисы, какие-нибудь обработчики данных.
Как обычно, ресурсов кластера на всех не хватает. Приходится что-то придумывать для оптимизации использования ресурсов, и Kubernetes отлично для этого подходит. В нём есть Horizontal Pod Autoscaler, который позволяет масштабировать приложения на основе метрик.
Метрики обычно поставляются метрик-сервером. Дальше я расскажу о замене метрик-сервера Prometheus«ом (потому что Prometheus реализует в себе данные, которые отдаются метрик-сервером и мы избавляемся от одного лишнего звена) и о том, как на основе метрик из Prometheus масштабировать свои приложения в Kubernetes.
Для начала установите Prometheus operator. Лично я пользуюсь готовыми манифестами. Вы можете воспользоваться чартом для Helm (но я не проверял его работоспособность). Также удалите метрик-сервер, если он у вас есть. После этого проверьте, всё ли работает как нужно.
# kubectl get --raw "/apis/metrics.k8s.io/v1beta1/" | jq
{
"kind": "APIResourceList",
"apiVersion": "v1",
"groupVersion": "metrics.k8s.io/v1beta1",
"resources": [
{
"name": "nodes",
"singularName": "",
"namespaced": false,
"kind": "NodeMetrics",
"verbs": [
"get",
"list"
]
},
{
"name": "pods",
"singularName": "",
"namespaced": true,
"kind": "PodMetrics",
"verbs": [
"get",
"list"
]
}
]
}
Затем примените манифесты из этой директории: https://github.com/coreos/prometheus-operator/tree/master/contrib/kube-prometheus/experimental/custom-metrics-api. Это установит вам Prometheus-adapter. Я нашел чарт, который содержит в себе эти манифесты, но не проверял его. После этого у вас должна корректно выполниться команда:
kubectl get --raw "/apis/custom.metrics.k8s.io/v1beta1" | jq
(там будет очень большой список, поэтому я не привожу его здесь)
Разобраться, что означают урлы metrics.k8s.io и custom.metrics.k8s.io вам может помочь документация.
Если что-то не работает, то смотрите, как обычно, в логи. Также можно поискать решение в issues.
Теперь настраиваем автомасштабирование.
У меня есть приложение, которое потребляет много ресурсов процессора и обслуживает очередь. Как только размер очереди превышает какой-то порог, я хочу увеличивать количество подов в replica set«е, чтобы быстрее обрабатывать очередь. Как только её размер станет меньше порогового, ресурсы кластера должны освобождаться.
Чтобы понять, как писать правила для Prometheus-adapter, необходимо вдумчиво прочитать этот документ и связанные с ним страницы. Вот как это выглядит у меня.
Запрос в Prometheus
wqueue_tube_total_size{tube="dmload-legacy"}
у меня возвращает:
wqueue_tube_total_size{endpoint="pprof-port",instance="10.116.2.237:8542",job="wqueue-pprof",namespace="default",pod="wqueue-b9fdd9455-66mwm",service="wqueue-pprof",tube="dmload-legacy"} 32
И я пишу следующее правило для Prometheus-adapter:
- seriesQuery: wqueue_tube_total_size{tube="dmload-legacy"}
resources:
overrides:
namespace:
resource: namespace
tube:
resource: service
name: {as: "wqueue_tube_total_size_dmload_legacy"}
metricsQuery: wqueue_tube_total_size{tube="dmload-legacy"}
Надо отметить, что мне приходится параметр tube
мапить в service
, чтобы потом использовать в описании hpa.
Конфигурация hpa:
---
kind: HorizontalPodAutoscaler
apiVersion: autoscaling/v2beta1
metadata:
name: dmload-v3-legacy
namespace: default
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: dmload-v3-legacy
minReplicas: 2
maxReplicas: 20
metrics:
- type: Object
object:
metricName: wqueue_tube_total_size_dmload_legacy
target:
apiVersion: v1
kind: Service
name: dmload-legacy
targetValue: 30
Здесь я указываю, что как только количество заданий в очереди wqueue_tube_total_size_dmload_legacy
превысит 30, надо добавлять поды, пока их не станет 20, а если targetValue
опустится ниже 30, то убавлять до 2.
Применяем и смотрим, что происходит. У меня система работает несколько дней и в данный момент как раз уменьшает количество подов:
# kubectl describe hpa dmload-v3-legacy
Name: dmload-v3-legacy
Namespace: default
Labels:
Annotations: kubectl.kubernetes.io/last-applied-configuration:
{"apiVersion":"autoscaling/v2beta1","kind":"HorizontalPodAutoscaler","metadata":{"annotations":{},"name":"dmload-v3-legacy","namespace":"d...
CreationTimestamp: Thu, 24 Jan 2019 16:16:43 +0300
Reference: Deployment/dmload-v3-legacy
Metrics: ( current / target )
"wqueue_tube_total_size_dmload_legacy" on Service/dmload-legacy: 14 / 30
Min replicas: 2
Max replicas: 20
Deployment pods: 15 current / 14 desired
Conditions:
Type Status Reason Message
---- ------ ------ -------
AbleToScale True SucceededRescale the HPA controller was able to update the target scale to 14
ScalingActive True ValidMetricFound the HPA was able to successfully calculate a replica count from Service metric wqueue_tube_total_size_dmload_legacy
ScalingLimited False DesiredWithinRange the desired count is within the acceptable range
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal SuccessfulRescale 59m (x14 over 40h) horizontal-pod-autoscaler New size: 13; reason: All metrics below target
Normal SuccessfulRescale 59m (x13 over 40h) horizontal-pod-autoscaler New size: 12; reason: All metrics below target
Normal SuccessfulRescale 57m (x14 over 40h) horizontal-pod-autoscaler New size: 11; reason: All metrics below target
Normal SuccessfulRescale 56m (x14 over 40h) horizontal-pod-autoscaler New size: 10; reason: All metrics below target
Normal SuccessfulRescale 56m (x11 over 38h) horizontal-pod-autoscaler New size: 8; reason: All metrics below target
Normal SuccessfulRescale 55m (x6 over 36h) horizontal-pod-autoscaler New size: 7; reason: All metrics below target
Normal SuccessfulRescale 47m (x103 over 40h) horizontal-pod-autoscaler (combined from similar events): New size: 20; reason: Service metric wqueue_tube_total_size_dmload_legacy above target
Normal SuccessfulRescale 3m38s (x19 over 41h) horizontal-pod-autoscaler New size: 17; reason: All metrics below target
Normal SuccessfulRescale 2m8s (x23 over 41h) horizontal-pod-autoscaler New size: 16; reason: All metrics below target
Normal SuccessfulRescale 98s (x20 over 40h) horizontal-pod-autoscaler New size: 15; reason: All metrics below target
Normal SuccessfulRescale 7s (x18 over 40h) horizontal-pod-autoscaler New size: 14; reason: All metrics below target
Всё описанное выполнялось на Kubernetes 1.13.2.
В этой короткой заметке я показал, как можно с помощью метрик из Prometheus автоматически масштабировать приложения в кластере Kubernetes.
Были настроены компоненты Prometheus-operator и созданы необходимые манифесты.
В итоге, на основе метрики из Prometheus о размере очереди получилось увеличивать или уменьшать количество подов, которые обрабатывают эту очередь.
(на графике видно как изменяется количество подов в зависимости от размера очереди).