Задача
Helm мощный и гибкий инструмент управления ресурсами в Kubernetes.
А что если одним Helm Chart пользуются несколько команд для развертывания своих приложений в Kubernetes? Как гарантировать, что Helm Chart как минимум рендериться после внесения изменений, прежде чем публиковать Helm Chart в репозиторий артефактов? Как гарантировать, что новая версия Helm Chart не "сломает" установку приложения в Kubernetes в критический момент(например во время релиза целевого продукта)?
Этими вопросами задался и я при разработке подобного Helm Chart.
Дополнительные требования к задаче
Надо отметить, что в моем случае, в качестве хранилища артефактов используется JFrog Artifactory внутри организации.
Для репозиториев есть явное деление на группы, в которые разрешено публиковать артефакты. В большинстве случаев под группой понимается groupId
из pom.xml файла проекта/модуля.
Аналогичное правило работает и для репозиториев хранения Helm Charts.
Выбор инструмента
В моих проектах используется Apache Maven как инструмент сборки, запуска тестов, упаковки и публикации артефактов.
Под артефактом понимается все то, что создается при сборке проекта: JAR/WAR/EAR-файлы, Docker образы, сопутствующие файлы конфигурации, и тп.
Ок, я умею в Maven.
Ок, я умею в Helm Charts.
Почему бы не совместить эти два инструмента?
Что предлагает сообщество, с точки зрения плагинов для Apache Maven, которые можно использовать для работы с таким зверем как Helm Charts?
Сообщество предлагает два плагина:
Первый позволяет:
довольно гибко настроить подготовку Helm Chart как артефакта
позволяет сделать как минимум прогнать Helm Chart через встроенный в Helm линтер
позволяет опубликовать Helm Chart в репозиторий таким образом, что Helm Chart будет использоваться только лишь в том случае, если при выполнении
helm upgrade
добавить аргумент--devel
, в данном случае будет использоваться пред-релизная(или developement) версия Helm Chart
Второй - не удовлетворял некоторым моим требованиям, поэтому решил идти в бой с первым!
Настройка
Создадим простой проект типа maven, со следующей структурой каталогов/файлов:
./pom.xml
./src/helm/Chart.yaml
./src/helm/templates/config-map.yaml
Содержимое ./src/helm/Chart.yaml
:
apiVersion: v2
name: sample-helm-chart
version: 0.0.0
Тут важно отметить значения поля
version
- в исходном коде оно всегда будет равно0.0.0
Содержимое ./src/helm/templates/config-map.yaml
:
apiVersion: v1
kind: ConfigMap
metadata:
name: sample-config-map
data:
foo: bar
То есть Helm Chart создает объект типа ConfigMap с одним ключом foo и значением bar
А теперь самое интересное, содержимое pom.xml
:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.example</groupId>
<artifactId>sample-helm-chart</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>helm</packaging>
<build>
<plugins>
<plugin>
<groupId>io.kokuwa.maven</groupId>
<artifactId>helm-maven-plugin</artifactId>
<version>6.3.0</version>
<extensions>true</extensions>
<configuration>
<chartDirectory>${project.basedir}/src/helm</chartDirectory>
<chartVersion>${project.version}</chartVersion>
<timestampOnSnapshot>true</timestampOnSnapshot>
<addDefaultRepo>false</addDefaultRepo>
<uploadRepoStable>
<name>central</name>
<url>https://example.org/artfactory/hlm-all</url>
<type>ARTIFACTORY</type>
<useGroupId>true</useGroupId>
</uploadRepoStable>
</configuration>
</plugin>
</plugins>
</build>
</project>
Давайте пройдемся по конфигурации плагина в секции <build>
:
chartDirectory
- указывает на корневой каталог, содержащий код Helm ChartchartVersion
- связываем версию Helm Chart и версию проекта/модуляtimestampOnSnapshot
- в случае, если при сборке версия проекта/модуля имеет суффикс-SNAPSHOT
- то суффикс будет заменен на текущее время в форматеyyyyMMddHHmmss
(формат по умолчанию)addDefaultRepo
- нам не нужен репозиторий по умолчанию, так как Helm Chart будет публиковаться в хранилище артефактов внутри организации.uploadRepoStable/name
- имя/идентификатор сервера изsettings.xml
. Необходимо в том числе для аутентификации в хранилище артефактов. Вsettings.xml
должны быть заданы значения полейusername
иpassword
для сервера указанного в данном поле.uploadRepoStable/url
- Адрес хранилища артефактов и базовый путь публикации артефакта.uploadRepoStable/type
- Тип репозитория. Плагин поддерживает три типа репозиториев.uploadRepoStable/usegGroudId
- согласно дополнительным требованиям к задаче, необходимо публиковать артефакты в свои группы. В случае еслиusegGroudId
равенtrue
, тогда, после публикации нашего Helm Chart в хранилище артефактов, Helm Chart из нашего примера можно будет скачать по адресуhttps://example.org/artfactory/hlm-all/org/example/0.0.1-SNAPSHOT/sample-helm-chart-0.0.1-20220701142516.tgz
Используя дополнительные плагины для Apache Maven, можно настроить автоматический инкремент версии, чтобы можно было выпускать релизные версии Helm Chart.
Пожалуй, самый важный параметр timestampOnSnapshot
- зачем он нужен и как он помогает отделить мух от ... в достижении цели?
Как было описано в описании параметров конфигурации плагина:
в случае, если при сборке версия проекта/модуля имеет суффикс
-SNAPSHOT
- то суффикс будет заменен на текущее время в форматеyyyyMMddHHmmss
(формат по умолчанию)
Что это дает?
Обратимся к справке по SemVer2:
A pre-release version MAY be denoted by appending a hyphen and a series of dot separated identifiers immediately following the patch version. Identifiers MUST comprise only ASCII alphanumerics and hyphens [0-9A-Za-z-]. Identifiers MUST NOT be empty. Numeric identifiers MUST NOT include leading zeroes. Pre-release versions have a lower precedence than the associated normal version. A pre-release version indicates that the version is unstable and might not satisfy the intended compatibility requirements as denoted by its associated normal version. Examples: 1.0.0-alpha, 1.0.0-alpha.1, 1.0.0-0.3.7, 1.0.0-x.7.z.92, 1.0.0-x-y-z.–.
То есть, если в значении версии, помимо главных атрибутов <MAJOR>.<MINOR>.<PATCH>
, есть некий суффикс(в нашем случае текущее время), то это считается пред-релизной версией, или с точки зрения Helm - development версией, а значит, когда выполняется команда helm upgrade
будет использоваться только релизная версия Helm Chart, если таковая имеется в репозитории.
Если есть необходимость использовать пред-релизную(или development) версию Helm Chart - надо явно "сказать" Helm'у с помощью аргумента: helm upgrade --devel
.
Заключение
Перед тем как имплементировать решение внутри организации, используемый плагин не поддерживал ряд функциональности, которая вытекала из Дополнительных требований к задаче, а так как у меня есть небольшой опыт написания плагинов для Apache Maven - я добавил недостающую функциональность в плагин.
Но самое сложное было то, что плагин давно не выпускался и пришлось не мало "побегать" за владельцами плагина. Благо ребята оказались отзывчивые и мы дружно вдохнули новую жизнь в плагин!
Как вы считаете нужен ли релизный цикл для таких вещей как Helm Charts?