Всем привет, в этом посте я покажу вам обходной путь для решения проблемы в старой версии Operator SDK (если быть точным, v0.18.2).

Мы пишем собственных операторов для множества платформенных проектов. Когда мы начинаем писать операторы, есть версия v0.18.2. И в этой версии мы разработали несколько операторов.

Проблема возникает при парсинге метрик оператора, если оператор запускает более одного модуля.

Ваши показатели выглядят так:

Похоже, что 2 наших модуля не могут обслуживать метрики, и это приводит к появлению ошибок «в соединении отказано» на prometheus.

Описание проблемы - ошибка метрики

Когда вы запускаете оператор, созданный Operator SDK (v0.18.2), есть некоторые автоматически сгенерированные ресурсы для сбора показателей от нашего оператора.

Эти ресурсы:

  • ServiceMonitor (очистка Прометея)
  • Услуга

Давайте проверим эти ресурсы. Имя нашего оператора - «платформа-оператор».

Как видите, ресурс ServiceMonitor находит операторов, использующих службу с меткой «name: platform-operator».

В ресурсе Service мы видим, что он выбирает поды с помощью селектора name: platform-operator.

Это означает, что наш скребок prometheus отправляет запросы любому модулю, имеющему метку «name: platform-operator».

Я сказал, что ошибка возникает, когда вы запускаете оператор более чем на одном модуле. Но почему?

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

Когда вы запускаете оператор с более чем одним модулем (скажем, 3), он выбирает один модуль в качестве ведущего. А другие поды работают в состоянии ожидания (чтобы стать лидером).

Оператор создает ConfigMap, чтобы зафиксировать лидерство. Таким образом, это гарантирует, что только один модуль будет работать в качестве лидера.

А другие модули (не являющиеся лидерами) печатают эти журналы:

Все идет нормально. Мы понимаем, что 2 пода работают в состоянии ожидания. Но это не объясняет ошибку «в соединении отказано». Это здоровые стручки, и они успешно бегают.

Итак, давайте попробуем отправить запрос на конечную точку метрик внутри этих модулей.

Сначала мы отправляем запрос на лидерный блок:

kubectl exec -it -n platform platform-operator-6c2b12hh3 -- curl localhost:8383/metrics

Мы успешно получили метрики.

Во-вторых, давайте попробуем отправить тот же запрос другим модулям операторов:

Хорошо, мы столкнулись с той же ошибкой, что и в Prometheus.

Но почему? Почему эти капсулы отказываются подключаться?

Давайте посмотрим на исходный код нашего оператора.

В автоматически сгенерированном файле cmd/manager/main.go есть часть кода:

Мы видим, что оператор пытается стать лидером, а затем запускает код addMetrics(ctx, cfg). Не забываем, что наш оператор начинает работать после строки err = leader.Become(ctx, "platform-operator-lock").

Функция addMetrics отвечает за создание ресурсов Service и ServiceMonitor:

Мы знаем, что 2 модуля непрерывно печатают журнал «Не лидер. Ожидающий".

Итак, давайте заглянем внутрь функции leader.Become.

В этой функции мы видим цикл, который постоянно пытается выбрать лидера, и здесь мы видим наш журнал «Не лидер. Жду ».

Это объясняет, почему другие модули отказываются от соединений. Они не запускаются! Они все еще ждут, чтобы стать лидером. Они находятся в цикле на строке err = leader.Become(ctx, "platform-operator-lock").

Решение

В версии Operator SDK v0.18.2 нет обходного пути. Таким образом, вы можете рассмотреть возможность обновления вашего оператора до более новой версии. Но, как и в нашем случае, если невозможно обновить его в ближайшее время, вы можете реализовать обходной путь, который мы сделали.

Мы подумали, что если для запросов метрик может обслуживаться только лидерный модуль, мы каким-то образом сможем перенаправить весь запрос метрики в лидерский модуль.

С этой точки зрения мы решили добавить дополнительную метку к группе лидеров. Также мы помещаем эту метку в селектор ресурса Service.

Чтобы решить указанную проблему, мы реализовали следующую логику:

После метода addMetrics мы получаем модуль лидера и маркируем его словом «leader = true», затем обновляем модуль.

После этого мы обновляем Сервис, добавляя метку «leader = true» в поле селектора.

Таким образом, мы гарантируем, что запросы метрики будут поступать только к ведущему модулю.

Спасибо, что дочитали до сих пор.

Вы можете найти реализацию кода обхода в этом репозитории: