Всем привет! Меня зовут Юрий Шахов, и я DevOps-инженер компании «Флант». В этой статье я расскажу путь, который мы проделали с коллегами для запуска community-чарта Sentry в Kubernetes-кластере. Я поделюсь нюансами, с которыми пришлось столкнуться, а ещё покажу параметры, которые понадобилось добавить для улучшения отказоустойчивости приложения.

Для начала небольшое предисловие. Несмотря на то, что мы часто устанавливаем и поддерживаем Sentry для наших клиентов (и для себя тоже), в основном мы не используем общедоступные чарты в исходном виде. На их основе у нас есть собственные, которые видоизменены исходя из выработанных нами best practices и потребностей клиента. У этого подхода есть свои преимущества и нюансы, которые мы раскроем дальше.

Официальной инструкции по установке Sentry в Kubernetes нет, есть только установка с использованием Docker Compose. Но для того, чтобы скейлить ресурсы и получать прочие преимущества Kubernetes, существует несколько чартов. Самый популярный для использования — это Sentry Helm charts. Далее под community-чартом будет подразумеваться именно он.

Так почему же было решено внедрить Sentry именно на community-чарте? Дело в том, что к нам пришёл клиент и попросил обновить Sentry так, чтобы в дальнейшем им было удобнее ориентироваться в Helm-чарте и проще самостоятельно вносить правки. Вторая цель — упростить обновления, то есть минимизировать действия по изменению чарта. На основе этого было решено взять community-чарт в исходном виде и добавить в него только values-файл. Что из этого вышло? Сейчас расскажу!

Наш опыт использования community-чартов

В нашей команде мы нечасто используем какие-либо готовые Helm-чарты абсолютно без изменений. Причина этого простая — обычно эти чарты не могут полностью покрыть все наши потребности, поэтому мы их модифицируем. Преимущества данного подхода заключаются в следующем:

  • Чарт становится более гибко настраиваемым, поскольку все манифесты находятся в нашем репозитории. Можно без проблем добавить или удалить компоненты, в то время как для внесения изменений в готовый Helm-чарт потребуется скачать его и модифицировать. Это приведёт к кастомизации, от который мы и стремились уйти. 

  • Улучшается читаемость, поскольку убираем из манифестов лишнюю часть, в которой нет необходимости.

  • Наши изменения позволяют обеспечивать бóльшую отказоустойчивость и стабильную работоспособность приложений. Например, если в чарте подобное не предусмотрено, мы добавляем Pod Disruption Budget, ограничивая количество подов для одновременного перезапуска, или явно проставляем ресурсы приложениям, что помогает избегать перегрузок и гарантировать необходимое количество CPU и RAM.

Теперь давайте перейдём к опыту, который мы получили, когда внедряли community-чарт для Sentry.

Внедрение community-чарта

Что вы ждёте от готового чарта — надо всего лишь скачать, задеплоить и можно работать? Сначала мы тоже так подумали, но всё оказалось куда интереснее.

Попытка обновления

Изначально мы планировали установить новую версию Sentry из community-чарта, после чего мигрировать все данные из текущей версии. В процессе стало понятно, что и-за сильного расхождения по версиям сделать это не получится. Поэтому мы решили засетапить новую Sentry той же версии, что и текущая, мигрировать данные и затем обновить.

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

Доработки

Процесс деплоя

Деплоим мы с помощью инструмента werf, у которого «под капотом» находится Helm, а нужные команды можно применять, добавляя в начало слово werf. Например, helm repo update превратится werf helm repo update.

Есть часть ресурсов, которые нужно выкатывать из репозитория, но их нет в community-чарте. Поэтому будет несколько команд: для деплоя «наших» ресурсов и для деплоя community-чарта. 

Процесс деплоя будет выглядеть следующим образом:

  1. Развёртывание ресурсов, которых нет в community-чарте, — сертификата для домена и DexClient для реализации SSO.

  2. Добавление репозитория Sentry и деплой чарта в кластер с нужной версией.

Ниже пример из GitLab CI:

# Применение ресурсов
- werf converge --namespace infra-sentry --values .helm/values.yaml --secret-values .helm/secret-values.yaml

# Деплой чарта
- werf helm repo add sentry https://sentry-kubernetes.github.io/charts
- werf helm repo update
- werf helm upgrade --install sentry sentry/sentry --version ${SENTRY_CHART_VERSION} --namespace infra-sentry --values .helm/values.yaml --secret-values .helm/secret-values.yaml --wait --timeout=1000s

Что пришлось доделать, чтобы Sentry начала работать

Первый деплой прошёл успешно, но при внесении изменений и повторной попытке выкатить Sentry пайплайн падал. Оказалось, что если не указывать пароль для PostgreSQL в values, то каждый раз в секрете будет заново генерироваться случайное значение, из-за чего новое задание (Job) db-init падает с ошибкой подключения к БД. Так что первым изменением стало добавление в values следующего значения:

postgresql:
  auth:
    password: superpass

Что пришлось доделать, чтобы улучшить работу

  1. Добавить --wait --timeout=1000s в команду установки чарта, поскольку 300 секунд по умолчанию не хватает (эта информация есть в README чарта).

  2. Перенести все чувствительные переменные в secret-values.yaml, где они хранятся в шифрованном виде (подробнее про секретные параметры — в документации werf).

  3. Проставить нужный retention для ZooKeeper от ClickHouse и для Kafka исходя из потребностей и объёма поступающих данных. Указанный по умолчанию retention в самой Kafka и ZooKeeper оказался для нас слишком большим, в результате чего место на диске заполнялось довольно быстро. Альтернативой уменьшению retention может являться увеличение диска.

  4. Установить лимиты и реквесты всем сущностям в чарте — это позволит гарантировать, что поды получат нужное количество ресурсов и не будут воздействовать и мешать друг другу или сторонним сервисам. По теме ресурсов для подов советую ознакомиться с видео про автомасштабирование и управление ресурсами в Kubernetes.

  5. Установить конкретную версию всех компонентов и пересобрать все образы в собственный container registry. Изначально в чарте стоит тег latest, что чревато последствиями. Для пересборки образов я использовал werf и добавил кастомный тег к имени образа с помощью werf build --add-custom-tag "%image%". После чего в файлах values можно было описать их:

images:
  sentry:
    repository: registry.awesome.ru/infra/sentry
    tag: sentry
    pullPolicy: Always
    imagePullSecrets:
    - name: registrysecret
 relay:
    repository: registry.awesome.ru/infra/sentry
    tag: relay
    pullPolicy: Always
    imagePullSecrets:
    - name: registrysecret
  1. Выставить podAntiAffinity для однотипных подов, например для всех подов sentry-web, чтобы они не скапливались на одном узле. Это позволит повысить отказоустойчивость, исключив полную недоступность компонента при выходе из строя одного узла.

  2. Для работы под нагрузкой также понадобилось увеличить количество sentry-workers и включить для них HPA. Правда, здесь пришлось завязаться на метрику CPU в HPA, так как по-другому в community-чарте это не изменить. В своём чарте использовалась кастомная метрика, которая отслеживала количество сообщений в очереди RabbitMQ.

Некритичные нюансы, которые нужно учитывать

Помимо необходимых изменений, хочется рассказать про нюансы, которые нужно учитывать в дальнейшем:

  1. В values для Kafka есть значение kafka.provisioning.enabled, которое при значении true добавляло для каждого деплоя около 10 минут в нашем случае. Причём это происходит, например, даже если мы решим изменить память для пода sentry-web. Как итог, было решено выключить это задание и запускать только при необходимости.

  2. Следующее значение, на которое нужно обратить внимание, — asHook: true. Оно необходимо только при первой установке, а далее его рекомендуется выключать, о чём явно написано в values.yaml.

  3. Ещё один нюанс возникает из-за использования установки, аналогичной той, что применяется в Helm. Если релиз не завершился успешно, то при выкате нового может возникать ошибка:

Error: UPGRADE FAILED: another operation (install/upgrade/rollback) is in progress

Решение этой проблемы заключается в удалении секрета с предыдущим Helm-релизом.

Но обычно мы не сталкиваемся с этой проблемой при применении werf converge. В том числе поэтому лично от себя рекомендую использовать werf как инструмент доставки чартов в кластер.

Что в итоге

Подводя итог, можно сказать, что процесс установки community-чарта Sentry оказался более сложным, чем казалось на первый взгляд. Понадобилось внести определённые изменения, чтобы можно было обеспечивать достаточный уровень отказоустойчивости. Однако благодаря использованию этого чарта получилось добиться большей прозрачности для стороннего наблюдателя. 

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

P. S.

Читайте также в нашем блоге:

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