Шаблонизируй это
Насколько я понимаю в Гугле 200M+ строчек кода написано на Borgcfg/GCL. Нечто похожее, но может быть в меньших масштабах происходит в любой крупной компании.
Архитекторы Borg и K8s что управление конфигурациями это одна из ключевых проблем.
Из всех проблем, с которыми мы сталкивались, наибольшее количество умственных усилий, чернил и кода было потрачено на управление конфигурациями — набором значений, предоставляемых приложениям, а не жестко встроенных в них. По правде говоря, мы могли бы посвятить этой теме всю статью и всё равно не исчерпать её. Ниже приведены несколько ключевых моментов.
Во-первых, конфигурация приложения становится универсальным местом для реализации всего, что (пока) не делает система управления контейнерами. За всю историю Borg это включало:
• Сокращение шаблонного кода (например, установка политик перезапуска задач по умолчанию, подходящих для типа нагрузки, такой как сервисные или пакетные задания).
• Настройка и проверка параметров приложения и флагов командной строки.
• Реализация обходных решений для отсутствующих API-абстракций, таких как управление пакетами (образами).
• Библиотеки шаблонов конфигураций для приложений.
• Инструменты управления выпусками.
• Указание версий образов
Запомнили все требования, которые предъявляли архитекторы k8s к инструментам управления конфигурациями? Ни один инструмент ее до сих пор до конца так и не решил.
Jsonnet, Dhall, Cue, Helm, ytt & kapp, kustomize — вот лишь не полный список языков и инструментов которые призваны были решить эти задачи. Список этот продолжает расширятся, но все равное медленнее чем гигабайты YAML генерируемые Kubernetes.
Хотя на самом деле эта проблема была решена 40 лет назад Unix хакерами из Bell Labs.
На самом деле чем меньше различий и несоответствий между разработкой для Kubernetes и разработкой для других платформ, тем меньше создается тех долга, который придется разгребать будущим поколениям.
Давайте посмотрим как можно использовать GNU make для работы с манифестами k8s.
Структура
https://github.com/avkcode/vault
В данном случае мы рассматриваем работу с Hashicrop Vault — потому что один их ключевых компонентов инфраструктуры, но при этом ничего специфичного для Vault здесь нет.
Dockerfile README.md docker-compose.yml keys.json
LICENSE unseal.py
Makefile dev.param global.param
В корне репозитория Makefile в котором описаны и манифесты и основные операции для работы с образами и развертыванием приложения Kubernetes. Документация тоже встроена в Makefile. В каком-то смысле это и есть «Грамотное программирование» по Кнуту.
Если запустить make без аргументов то появится help:
Available targets:
template - Generate Kubernetes manifests from templates
apply - Apply generated manifests to the Kubernetes cluster
delete - Delete Kubernetes resources defined in the manifests
validate-% - Validate a specific manifest using yq, e.g. make validate-rbac
print-% - Print the value of a specific variable
get-vault-ui - Fetch the Vault UI Node IP and NodePort
build-vault-image - Build the Vault Docker image
exec - Execute a shell in the vault pod
logs - Stream logs from the vault pod
switch-namespace - Switch the current Kubernetes namespace
archive - Create a git archive
bundle - Create a git bundle
clean - Clean up generated files
release - Create a Git tag and release on GitHub
get-vault-keys - Initialize Vault and retrieve unseal and root keys
show-params - Show contents of the parameter file for the current environment
interactive - Start an interactive session
create-release - Create a Kubernetes secret with VERSION set to Git commit SHA
remove-release - Remove the dynamically created Kubernetes secret
dump-manifests - Dump manifests in both YAML and JSON formats to the current directory
convert-to-json - Convert manifests to JSON format
validate-server - Validate JSON manifests against the Kubernetes API (server-side)
validate-client - Validate JSON manifests against the Kubernetes API (client-side)
list-vars - List all non-built-in variables, their origins, and values.
package - Create a tar.gz archive of the entire directory
help - Display this help message
Открываем makefile.
Создаем мультистроковые переменные с помощью define:

Создаем массив строк:

С помощью функции foreach проходим по массиву строк:

Мы можем обработать массив так как нам необходимо или сохранить манифесты kubernetes на диск:

Parameters
В файлах *.param задаются переменные для разных окружений

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

Validation
С помощью встроенных в k8s возможностей валидируем манифесты.

Команда validate-% проверяет отдельные манифесты (в данном случае мультистроковые переменные) на наличие ошибок с помощью утилиты yq/jq:

Проверяем configmap:

Constraints
Гибкость make позволяет нам проверять значения параметров «in situ». В данном случае мы проверяем что значение MEMORY_REQUEST находится в пределах допустимых значений.

Release
Ни что не останавливает нас от того, чтобы реализовать такой же функционал:

В отличии от Helm мы ни чем не ограничены и можем вместо номера релиза использовать например GIT_COMMIT, а сохранять эти данные можно в любое внешнее хранилище, к примеру в Clickhouse.
PS.
Для небольших организаций, когда из интернета выкачиваются готовые операторы K8s например Strimzi и Helm чарты из Bitnami. И потом это с небольшими правками разворачивается на прод, то что я показал может быть слишком сложным.
Данные метод работы с манифестами скорее предназначен для организаций с сотнями и тысячами команд, где есть особые требования к безопасности (istio).
Данный пример был призван показать насколько просто заменить тот же Helm используя лишь стандартный инструментарий Unix. Это говорит о том, что назрела необходимость создания средств автоматизации «умнее» чем Helm.