Приветствую всех Хабровчан. Сегодня говорим про Helm и то, как мы у себя в Nixys пришли к универсальному чарту, который стали использовать в своей работе как стандартный инструмент и почему это сделало нашу работу эффективнее.

Немного теории

Для начала вспомним, что это вообще такое. Helm - это пакетный менеджер, который позволяет вам работать с приложениями в K8s так-же просто и удобно, как с привычным пакетным менеджером, например apt или yum, помогает доставлять одно и то же приложение в разные окружения с различными параметрами и позволяет легко и удобно управлять жизненным циклом приложения. На практике является одним из самых распространённых и простых способов релиза приложений в куб.

Для получения манифестов k8s в Helm используется go-templates. Это мощный и удобный инструмент, позволяющий реализовывать очень много интересных вещей и обладающий гибкой логикой.

Для работы с чартами используются артефакт хабы. Осуществлять поиск и установку нужной версии очень легко. Если публичные чарты вам не подходят, вы можете использовать свой собственный регистри хаб или чей то ещё. Некоторые дистрибутивы k8s (OS, OKD, Rancher) вообще предоставляют для данного функционала GUI из коробки, позволяя работать с Helm максимально удобным способом.

При установке приложения через Helm создаётся релиз. Релиз Helm - это полноценное состояние приложения, включая его конфигурации и переменные окружения (если они хранятся в k8s). Переключаясь между релизами Helm, например, откатывая релиз, вы также получаете именно те параметры, с которыми было запущено приложение, в отличие, например, от переключения между версиями репликасетов в деплойменте.

В Helm есть хуки. Это очень удобный инструмент, который позволяет вам выполнить какой-либо джоб до того, как будет выполнено обновление других манифестов k8s. Например, если у вас приложение состоит из деплоймента и кронджобов, а миграция БД выполняется в init-контейнере, вы не застрахованы от ситуации, когда миграция ещё не завершилась, а кроны с новым кодом уже падают, из-за того, что версия БД еще старая. Хук в данном случае решает задачу.

Удобно реализована работа с зависимостями. Параметры запуска зависимости настраиваются точно так же, как и само приложение: всё что вам нужно - добавить зависимость в описание чарта, а её параметры - в файл values.

У Helm большое комьюнити, и практически все open-source проекты имеют свой собственный чарт. Вам ничто не помешает скачать любой чарт, и локально поменять в нём всё что угодно.

Если для деплоя вы используете манифесты k8s без шаблонизации, то вам потребуется поработать с существенно бОльшим объёмом данных, чтобы настроить ваше приложение в нескольких окружениях. Например, из values файла объемом 4 кб генерируются манифесты объемом 48 кб.

Список недостатков:

  • При использовании публичных чартов есть шанс столкнуться с багами

  • Тяжело реализуется сложная логика, есть ограничения

  • Для создания минималистичного values файла чарт должен быть заточен под приложение

Как обычно происходит работа с чартами в IT компаниях?

Типичный сценарий создания чартов под новый проект - скопировать с одного из старых проектов.

У такого подхода есть свои преимущества. Например, до 90% работы уже выполнено, нужно только адаптировать чарт под ваши задачи, поменять названия, лейблы, выкинуть лишнее и добавить чего не хватает. Кроме того, можно сделать чарт, заточенный под приложение, вытащив в values необходимые проекту параметры и передавать минимум аргументов для настройки окружений.

Разумеется, у такого подхода есть недостатки:

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

  • Хорошие решения не тиражируются по проектам, старые проекты очень редко получают обновления.

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

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

Как мы сделали свой универсальный чарт.

У себя в Nixys мы регулярно сталкивались с необходимостью создания практически идентичных чартов.

На одном из проектов с 14 идентичными микросервисами мы пришли к формату чарта, который по сути стал прототипом. Чарт решал задачи развёртывания каждого микросервиса по отдельности, при этом, учитывал особенности каждого. Так мы получили прототип и обкатали на практике концепцию "универсального" чарта.

Позже, у другого заказчика нам потребовалось подготовить CI/CD для 60 практически идентичных проектов. Здесь концепция универсального чарта оказалась актуальна как никогда раньше. Так, благодаря использованию универсального чарта, мы сократили время подготовки к релизу с 6 часов до 1. 

В конце концов мы пришли к выводу, что концепция "универсального" чарта работает. Он объединяет накопленный опыт и хорошие решения, при этом позволяет добавлять то, чего не хватает каждому конкретному проекту.

Ключевые особенности

Здесь стоит остановиться на каждой особенности поподробней.

Уменьшение времени на подготовку деплоя

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

Генерация любых манифестов, которые могут вам понадобиться

Чарт позволяет создавать любое количество деплойментов, джобов и крон-джобов, конфигмапов и секретов, позволяет создать любые другие дополнительные манифесты, необходимые для запуска приложения. У вас есть возможность добавить в текущий чарт необходимые вам шаблоны через секцию extraDeploy, например, networkPolicy.

extraDeploy:
- |
  apiVersion: networking.k8s.io/v1
  kind: NetworkPolicy
  metadata:
    name: {{ include "helpers.app.fullname" (dict "name" "nw-policy" "context" $) }}
    namespace: {{ .Release.Namespace | quote }}
  spec:
    podSelector:
      matchLabels:
        role: db
    policyTypes:
    - Ingress
    - Egress
    ingress:
    - from:
      - ipBlock:
          cidr: 172.17.0.0/16
          except:
          - 172.17.1.0/24
      - namespaceSelector:
          matchLabels:
            project: myproject
      - podSelector:
          matchLabels:
            role: frontend
      ports:
      - protocol: TCP
        port: 6379
    egress:
    - to:
      - ipBlock:
          cidr: 10.0.0.0/24
      ports:
      - protocol: TCP
        port: 5978

Также вы можете использовать go-templates в качестве значений ваших values, например, чтобы добавить аннотацию пода с чек-суммой конфигурации приложения.

deployments:
  api:
    podAnnotations:      
      checksum/api-key: '{{ include "helpers.workload.checksum" (index $.Values.secrets "api-key") }}'

Совместимость с разными версиями k8s

Благодаря встроенным в чарт механизмам проверки версий k8s обеспечивается использование совместимых версий api манифестов. Определение версии k8s происходит автоматически, на этапе генерации манифестов, но так-же может быть указано вручную в values.

kubeVersion: v1.22.3

Таким образом, вы можете деплоить ваше приложение в любую версию k8s. Не переживая, правильная ли версия api используется в манифесте.

Пара слов о минусах

К сожалению, у такой классной штуки тоже есть свои недостатки:

  • Если вам потребуется внести изменения, от вас потребуется высокий уровень навыков работы с  Helm. 

  • Есть ограничения, связанные с использованием go-templates в values. В частности, есть ограничения на длину строки и некоторые символы.

Вместо эпилога

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

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

Исходный код чарта опубликован на GitHub. Если у читателей этой статьи есть новые идеи и предложения к улучшению универсального Helm-чарта, будем рады услышать .

Кстати, присоединяйтесь к нашему телеграм-каналу, где мы публикуем новости о DevOps (и не только) - DevOps FM.

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


  1. n_bogdanov
    25.03.2022 10:21
    +3

    Хочу попросить прощения у автора - статью прочитал и пропустил ссылку на github. В итоге минуснул статью.

    Так как нет возможности переголосовать - плюсанул карму напрямую. Впредь буду внимательнее.

    По самой статье - хороший чарт. А вы не рассматривали вариант создания библиотечного чарта?


    1. r_andreev Автор
      25.03.2022 11:52
      +1

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


  1. igor_alt
    25.03.2022 13:20

    GPL?


    1. r_andreev Автор
      25.03.2022 15:57

      Да


  1. evg_krsk
    26.03.2022 18:38
    +3

    Спасибо, интересно. Идеи для улучшения: pdb, hpa, prometheusrule.


    1. r_andreev Автор
      28.03.2022 05:59

      Благодарю за предложения, мысли верные))

      Мы уже попробовали внедрить prometheusrule для джобов, которые выполняются дольше заданного времени, но данный кейс мы широко практикуем в клиентских проектах. Для других, частных случаев часто требуется определённая логика, которая учитывает особенности конкретного проекта. Именно для этого реализован механизм extraDeploy, чтобы можно было добавить необходимые манифесты или шаблоны Helm, включая prometheusrule и hpa, networkpolicy и пр.

      В некоторых случаях решение реализованное на отдельном проекте может оказаться удобным в использовании и тогда оно может быть включено в состав чарта "из коробки".

      Вы можете предложить свои варианты реализации, вполне может оказаться, что это будет отличное и удобное решение, которое войдёт в состав чарта))