company_banner

Масштабирование приложения в 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"
          ]
        }
      ]
    }

    Затем примените манифесты из этой директории. Это установит вам 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:                                                             <none>
    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 о размере очереди получилось увеличивать или уменьшать количество подов, которые обрабатывают эту очередь.


    (на графике видно как изменяется количество подов в зависимости от размера очереди)

    Спасибо за внимание!
    Mail.ru Group
    Строим Интернет

    Комментарии 8

      +1
      Весь смысл статьи в том, чтобы описать базовые вещи из документации. Особенно огорчает:
      но я не проверял его работоспособность
      и
      который содержит в себе эти манифесты, но не проверял его

      У вас не заработает custom.metrics.k8s.io без aggregation-layer, не вводите в заблуждение.
      Еще не плохо было бы заметить, что если вы удаляете из кластера heapster то у вас перестанут показываться графики на kubernetes-dashboard.
        0
        heapster же уже давно деприкейтнут, путь описанный здесь вроде как единственный тру
          0
          Да, с heapster все просто-ясно, но пока не закроют эту issue — будет боль для тех кто любит kubernetes-dashboard.
          0
          Смысл статьи — описать как настроить связку Prometheus и HPA.
          Я не проверял работоспособность работы helm чартов, но проверял работоспособность манифестов.
          Про aggregation-layer да, я позабыл об этом написать, спасибо.
            0
            То что такие статьи появляются на Русском языке — это безусловно плюс.
            Но проверить работоспособность helm charts (они к слову замечательно работают) — не займет много времени.
          0
          Почему бы просто не использовать service mesh (Istio, Linkerd, Consul), где это уже реализовано?
            0
            А поподробнее? Что-то не помню там автоскейла и метрик кроме service mesh.
              0
              Кажется вы все перепутали :)

            Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

            Самое читаемое