Миллионы разработчиков пишут запросы PromQL и создают пользовательские дашборды Grafana для Kubernetes. И все используют одинаковые метрики из node-exporter, kubelet и kube-state-metrics. К сожалению, не все знают, как при работе с метриками обойти некоторые подводные камни.‍

Команда VK Cloud перевела статью, в которой автор разбирает ошибки в одном простом с виду запросе Prometheus для Kubernetes. Он должен возвращать сведения об использовании памяти пода:

container_memory_working_set_bytes{pod="agency-dashboard-api-89b7f557c-xd4l7"}

К сожалению, это неверный запрос. Давайте разбираться, что с ним не так и как избежать аналогичных ошибок в других запросах.

Ошибка №1: повторяющиеся временные ряды

Чтобы исправить запрос PromQL, нужно убедиться, что у вас в ожидаемых результатах указано точное число временных рядов. Поскольку в фильтре я указываю один под, то ожидаю, что и результат будет один.

Вместо этого я получаю два результата (я отредактировал несколько меток с конфиденциальными данными или поменял их значения):

container_memory_working_set_bytes{__replica__="replica-0", cluster="dev-cluster", container="agency-dashboard-api", endpoint="https-metrics", id="/kubepods/burstable/pod66a2c312-6066-42e9-99f8-6e045b863e9d/d24d2a7b79f4fac2f51ab2d9126b9be9a58bd122b18c6928faac463882df7ef0", instance="10.128.0.79:10250", job="cadvisor", metrics_path="/metrics/cadvisor", name="d24d2a7b79f4fac2f51ab2d9126b9be9a58bd122b18c6928faac463882df7ef0", namespace="default", node="gke-dev-cluster-lg-workloads-addf1-44", pod="agency-dashboard-api-89b7f557c-xd4l7", project="dev-k8s", service="kubelet"}

container_memory_working_set_bytes{__replica__="replica-0", cluster="dev-cluster", endpoint="https-metrics", id="/kubepods/burstable/pod66a2c312-6066-42e9-99f8-6e045b863e9d/d24d2a7b79f4fac2f51ab2d9126b9be9a58bd122b18c6928faac463882df7ef0", instance="10.128.0.79:10250", job="cadvisor", metrics_path="/metrics/cadvisor", name="d24d2a7b79f4fac2f51ab2d9126b9be9a58bd122b18c6928faac463882df7ef0", namespace="default", node="gke-dev-cluster-lg-workloads-addf1-44", pod="agency-dashboard-api-89b7f557c-xd4l7", project="dev-k8s", service="kubelet"}

Изначально я подозревал, что проблема в настройках мониторинга: может быть, несколько заданий извлекают одни и те же данные. Чтобы правильно построить графики, в Prometheus нужно использовать верные метки в запросе. (Prometheus добавляет в запрос несколько меток, в частности job и instance.) Я решил выяснить: может быть, одни и те же данные извлекают несколько заданий или выдают разные инстансы. Ведь если одинаковые данные поступают из разных мест, запрос выдает непонятные или неверные результаты. (Подробнее об этом в видео на YouTube об ошибках мониторинга в Prometheus.)

Я добавил метку задания:

container_memory_working_set_bytes{pod="agency-dashboard-api-89b7f557c-xd4l7", job="kubelet"}

Но запрос все равно выдавал два временных ряда для одного пода. Это значит, что только одно задание извлекало данные, так что у меня правильные настройки. Но запрос все равно был неверный.

Проблема №2: Ошибки группирования/суммирования

Поскольку запрос возвращал два почти одинаковых временных ряда, мой внутренний гений решил суммировать метрики и разделить результат на два.

sum(container_memory_working_set_bytes{pod=”my-pod-123”, job=”kubelet”}) by (pod) / 2

Но когда я перепроверил результаты этого запроса по данным у себя в консоли GKE, выяснилось, что запрос выдавал результаты, разнящиеся по времени. Это отчасти объяснялось тем, как метрики рассчитываются в GKE: GKE учитывает только Non-evictable memory.

Какой урок из этого можно извлечь? Не надо делать дедупликацию метрик, выводя их среднеарифметическое — по крайней мере, пока вы не разберетесь в подробностях, как они рассчитываются и почему вообще появились дубликаты.

Проблема №3: неожиданное количество элементов множества

Давайте вернемся к нашим дублированным временным рядам и рассмотрим их подробнее. Чем один временной ряд отличается от другого?

Ответ нам подскажет метка container. Эта метка есть у одного временного ряда и отсутствует у другого.

Чтобы понять почему, нужно пойти в обход и выяснить, что такое контейнер pause. Из документации Kubernetes:

«В поде Kubernetes для размещения контейнера сначала создается так называемый инфраструктурный, или Pause-контейнер. В Linux для поддержания существования cgroups и пространств имен, входящих в под, нужен процесс — он называется Pause-процесс. У контейнеров, относящихся к одному поду, включая инфраструктурные и рабочие контейнеры, общая конечная точка сети (один и тот же IPv4 и/или Ipv6-адрес, одни и те же пространства сетевого порта). В Kubernetes Pause-контейнеры нужны, чтобы при сбое и перезапуске рабочих контейнеров сохранялись их сетевые настройки».

Когда создается под в Kubernetes, число контейнеров, созданных на ноде, всегда больше, чем число подов, указанных в манифесте пода. Чтобы это проверить, выполните SSH на ноде и запустите docker ps. У Pause-контейнера имеются все сетевые настройки пода. При удалении Pause-контейнера удаляется также и контейнер приложения, а под перезапускается.

Теперь в дублирующихся временных рядах появляется смысл: у нас по одному временному ряду на контейнер, включая пустой Pause-контейнер. 

После этого я подправил запрос и наконец получил верные метрики.

container_memory_working_set_bytes{pod=”agency-dashboard-api-89b7f557c-xd4l7”, job=”kubelet”, container!=”}

Какой урок из этого можно извлечь? Всегда проверяйте метки. Обязательно разберитесь, какие метки можно менять, какие жестко заданы, а какие факультативные. В большинстве случаев из-за ошибок с метками или количеством элементов множества вы получите неверные метрики.

Заключение

Надеюсь, что этот пример простого, но неправильного запроса PromQL поможет вам избежать аналогичных ошибок с собственными метриками. Простота PromQL обманчива. Нужно понимать, что именно вы измеряете в каждом запросе. Лишние данные могут пробраться незаметно и исказить агрегаты данных.

Присоединяйтесь к телеграм-каналу «Вокруг Kubernetes», чтобы быть в курсе новостей из мира K8s!

Регулярные дайджесты, полезные статьи, а также анонсы конференций и вебинаров.

Комментарии (2)


  1. trabl
    11.10.2024 04:53

    Скуповато для статьи на хабре, не?


    1. Rim13
      11.10.2024 04:53

      Согласен. Как бы, и примеры алертов, и готовые дашборды, уже настроены на такие особенности. Ожидал из названия что то более глубокое по теме. Мб как организовать корректный показа статус подов и контейнеров на state timeline или другом виде графика. Или что то такое не ординарное.

      Но за пояснения про pause контейнер спасибо.