По мере понимания рабочего процесса Helm и разработки своих чартов замечаешь, что у нас обычно есть несколько путей, чтобы добиться поставленной задачи.
Если у нас есть 5 вариантов решений, то новичку трудно понять, какой из них лучше.
Здесь я попробовал создать список общих указаний и рекомендаций, чтобы получить представление об оптимальных способах работы с helm-чартами.
Здесь будет 7 тем в 3-х постах, и в основном это есть в документации Helm по ссылке https://helm.sh/docs/chart_best_practices/
Начнем с названий чартов
Их имена должны содержать только строчные буквы и цифры. Кроме того, если название должно состоять из нескольких слов, разделяй их дефисами, как ты видишь здесь.
Хорошо
nginx
wordpress
wordpress-on-nginx
Нехорошо
Nginx
Wordpress
wordpressOnNginx
wordpress_on_nginx
Что касается номеров версий чарта, то Helm рекомендует нотацию SemVer2 или Семантическое Версионирование 2.0.0.
Тебе может быть не знакомо это название, то ты уже много раз с этим встречался.
Вкратце, номера версий имеют вид MAJOR.MINOR.PATCH.
Первое число представляет старший номер версии, второе — младший, третье — номер патча.
Допустим, вчера ты создал совершенно новое приложение и присвоил ему версию `0.1.0`.
Сегодня ты нашел нашел ошибку безопасности и исправил ее. Вместе с приложением изменится и его версия, она станет `0.1.1`.
Позже ты находишь другую ошибку и исправляешь ее. Версия вновь изменится и станет `0.1.2`.
Ок, дальше ты вносишь небольшие изменения в свое приложение, например, меняешь функцию, убирая лишние циклы, благодаря чему она начинает потреблять на 5% меньше памяти. Это может стать версией `0.2.0`.
Обрати внимание, что когда ты обновляешь минорный номер в версии, номер патча сбрасывается до 0.
Наконец, ты делаешь существенный рефакторинг, внося огромное обновление в свое приложение, добавляешь множество новых функций и меняешь некоторые существующие. Поскольку измененные функции сильно переработаны, то могут быть не полностью совместимы со старыми.
Вот в этом случае изменится мажорная версия и становится `1.0.0`.
Этот подход к версионированию справедлив и в проектировании своих helm-чартов.
Теперь давай поговорим о файле `values.yaml`
Все имена переменных в файле `values.yaml` должны начинаться со строчных букв.
Также тире и подчеркивания не поддерживаются.
Очень часто переменная должна содержать несколько слов, чтобы было понятно о чем идет речь.
Используй регистр `camelCase`, когда первое слово начинается со строчной буквы, а все последующие начинаются с заглавной.
Здесь я показал как верно и неправильно.
Хорошо
replicaCount: 3
wordpressSkipInstall: false
wordpressUsername: user
Нехорошо
ReplicaCount: 3
wordpress_skip_install: false
wordpress-username: user
При этом первые две неверные строки, те что с первой заглавной буквой и подчеркиваниями все же будут приняты, но с тире — совсем никак.
Что касается самой структуры переменных, у нас есть плоский и вложенный форматы.
Вложенный
image:
repository: nginx
pullPolicy: IfNotPresent
tag: "1.16.0"
Плоский
imageRepository: nginx
imagePullPolicy: IfNotPresent
imageTag: "1.16.0"
Как видишь, выше присутствует логическая группировка, а именно `image` включает в себя понятия репозитория образа, тега образа и политику скачивания. Поэтому эти поля являются дочерними по отношению к полю image.
Мы можем переработать это в плоский формат, как ты видишь ниже.
Ок, если возможно, нам следует предпочесть плоский формат.
Но если у нас несколько связанных переменных, которые логически могут быть вложены друг в друга, и мы уверены, что по крайней мере одна из них будет использоваться всегда, мы группируем их вложенным методом.
Если же переменные не связаны между собой, или связаны, но необязательны, скажем, у значений есть некоторые дефолтные величины, а переопределение бывает в очень редких случаях, то лучше делать в плоском режиме.
Теперь поговорим о самих значениях полей.
Вот такой булев параметр `enable: false` мы далее будем проверять в шаблоне с помощью блока if или with.
values.yaml
enable: "false"
startTS: 1670843898
templates/timer.yaml
{{- with .Values.enable }}
startTimeStamp: {{ $.Values.startTS }}
{{- end }}
release-name/templates/timer.yaml
…
startTimeStamp: 1.670843898e+09
…
Внизу результат рендеринга шаблона.
Так вот, значение `enable` будет ложным в том случае, если оно будет указано так:
— `false` маленькими буквами,
— `FALSE` большими,
— `False` с заглавной
— и в значении 0.
Если ты установишь `enable: FalSe` символами из разных регистров как видишь здесь, то цикл `with` по `.Values.enable` успешно выведет содержимое блока.
Что касается кавычек в значениях, то `enable: false` и `enable: “false”` присвоит переменной разные типы.
В первом случае присваивается логический булев тип. Во втором случае присваивается строковое значение, которое будет понято как истина.
Всегда заключай строковые значения между знаками двойных кавычек, если не уверен в них.
С целыми числами тоже есть особенности.
Скажем, у нас число epoch timestamp в поле `startTS`.
При парсинге файла шаблонов его значение будет преобразовано в экспоненциальное представление. В итоге получится дробное число со степенью.
При работе с большими числами ты обязательно столкнешься с этой проблемой.
Просто определи число как строку, добавив двойные кавычки, как видишь здесь.
После этого в файлах шаблонов, когда потребуется использовать эту переменную, добавь к ней префикс функции преобразования типа int для больших или int64 для очень больших чисел.
values.yaml
enable: "false"
startTS: "1670843898"
templates/timer.yaml
{{- with .Values.enable }}
startTimeStamp: {{ int $.Values.startTS }}
{{- end }}
release-name/templates/timer.yaml
…
startTimeStamp: 1670843898
…
Таким образом, строка `167 и т.д.` будет преобразована в число 167… и т.д., а не в его экспоненту.
Также, в современных версиях можно просто установить int без преобразования значения в строку, это уберет экспоненту.
Ок, хорошим тоном считается документирование файлов `values.yaml`.
Когда пользователь открывает файл значений, все, что он получает, — это длинный список переменных.
Разумеется, ему будет очень сложно понять, для чего используется каждая из них. Вот поэтому мы всегда должны документировать каждое поле, добавляя комментарий над ним. Комментарий начинается с символа решетки. Например как ты видишь тут.
values.yaml
…
## replicaCount Number of NGINX replicas to deploy
##
replicaCount: 1
## updateStrategy.type NGINX deployment strategy type
## updateStrategy.rollingUpdate NGINX deployment rolling update config
## ref: https://kubernetes.io/docs/concepts/workloads/controllers/deployment/
##
updateStrategy:
type: RollingUpdate
rollingUpdate: {}
## podLabels Additional labels for NGINX pods
## ref: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/
##
…
Обрати внимание, как мы начинаем комментарий. Мы пишем с фактического имени переменной. Это рекомендуемый подход, поскольку и упрощает поиск, и особенно помогает инструментам авто-документирования сопоставить наши примечания с параметрами, которые они описывают.
Прежде чем мы перейдем к шаблонам, у нас остаются файлы LICENSE и README.md.
Лицензия — это обычный текстовый файл, в нем мы пишем на каких услових поставляем чарт. Также тут могут быть лицензии для приложения, которое ставит чарт. Имей в виду, что твой чарт может содержать сабчарты, в которых содержится логика, на которую создатели могут налагать ограничения. Лучше рассказать об этом пользователям здесь.
Файл README представляет собой инструкцию формате Markdown и обычно содержит:
описание приложения в чарте
команды, как установить чарт
предварительные условия для запуска чарта
описания параметров файла values.yaml и значения по умолчанию
особенности установки, настройки и дебага чарта
На эту информацию ориентируется автоматика репозиториев, когда отображает данные о чартах, а также с ним работает команда `helm show readme`.
Ок, это все в этом посте, продолжим в следующем.