Как Helm работает с Kubernetes namespace

Одной из наиболее полезных функций helm является способность хранить состояние, что позволяет не только разворачивать чарты, но и аккуратно их удалять, зачищая после себя все следы их присутствия. Однако не лишним будет разобраться в том, как именно helm хранит состояние, чем и займемся в статье.

Как Helm работает с Kubernetes namespace

TL;DR: если лень читать и вы знакомы с helm, переходите сразу к выводам в самом конце статье, там коротко собрана выжимка из рассуждений ниже.

Вопрос

Изначально мне было просто интересно узнать как helm хранит состояние. Разобраться в этом вопросе не сложно и все доступно в документации. С версии helm 3 состояние по умолчанию хранится в секретах. Но сразу возникают вопросы – в секретах какого неймспейса? Как управлять этим поведением? Какой подход более предпочтителен?

Примечание: хранить состояние также можно по-старому в configmap, но вы должны быть более внимательными к сохранности паролей, приватных ключей и других уязвимых данных, ведь по умолчанию ограничения RBAC для configmap гораздо слабее. Не стоит также забывать и о бекэнде в виде базы данных. Это особенно актуально, когда состояние превышает максимальный объем секрета по умолчанию (1MiB, см. Kubernetes Secrets).

Короткий ответ

Helm 3 хранит состояние в секретах неймспейса по умолчанию. Если не установлено иначе, то это будет неймспейс default. Переопределить пространство имен можно с помощью опции ‐‐namespace или переменной окружения HELM_NAMESPACE:

Примечание: увидеть все доступные переменные окружения можно с помощью команды helm env.

Вот так выглядит сам секрет:

Но дьявол кроется в деталях, что только подтверждается количеством реакций на сообщения в задаче Best Practices/Docs Question – Specify Namespace in Chart?. А теперь обо всем подробнее.

Подробное объяснение

Для начала рассмотрим варианты управления пространствами имен Kubernetes в контексте хельма. Начнем с самых очевидных, но ошибочных сценариев.

Определять пространство имен явно

Namespace в Kubernetes это ключевой инструмент для изоляции объектов кластера. Установить его для объекта (например пода) можно следующим образом:

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

Можно пойти чуть дальше и определить неймспейс как переменную в файле values.yaml:

А вот так вызывать внутри шаблона объекта:

Такая модель является антипаттерном, потому что потенциально вы получите ситуацию, когда состояние и объекты чарта могут храниться в разных неймспейсах (и вероятно будут храниться). Helm сохранит состояние в неймспейсе default, если вы конечно не выполните команду helm install с ключом ‐‐namespace. Значение ключа должно совпадать со значением переменной в файле values.yaml.

В этом принципиальное отличие от kubectl. В случае с kubectl, если ваши объекты будут иметь namespace с именем X, а самому kubectl вы передадите опцию ‐‐namespace с именем Y, то kubectl свалится с ошибкой:

Kubectl не позволяет двоякую трактовку конфигурации, а helm – позволяет.

Не определять пространство имен вообще

Можно пойти иным путем и не определять неймспейс вообще ни для какого объекта чарта, то есть просто игнорировать ключ namespace. В таком случае helm все положит в неймспейс default – и объекты, и секрет с состоянием. Если же вы выставите опции ‐‐namespace <name> и ‐‐create-namespace, то helm создаст требуемый неймспейс и разместит всё там (объекты и секрет). Удобно и даже нет никаких проблем с “расщеплением” конфигурации, когда объекты и состояние лежат в разных неймспейсах. Именно этот подход и рекомендован официально – неймспейсы не должны определяться нигде в явном виде.

Однако остаются непонятные моменты. Предположим вы последовательно выполняете две следующие команды:

Примечание: не обращайте внимания на параметры test и helm-test, это просто имя чарта и сам чарт, в данном контексте они не важны.

Helm сделает рендер всех объектов чарта и выдаст его в output консоли. Только нюанс в том, что в обоих случаях вывод будет полностью одинаков. То есть helm просто проигнорирует опцию namespace. Мне бы как минимум хотелось видеть кастомный namespace в том случае, если я его задаю явно (вторая команда), а в идеале – в обоих случаях.

Использовать встроенную переменную

На уровне чарта есть ряд встроенных переменных, доступных глобально. Среди них есть и переменная, которая хранит имя неймспейса релиза, это Release.Namespace (см. Helm – Built-in Objects). Использовать её можно следующим образом:

Эта переменная будет хранить имя неймспейса, которое вы передадите хельму с помощью ключа ‐‐namespace. Либо отдаст имя пространства имен по умолчанию – default. В данном случае выполнение двух команд helm template из предыдущей главы даст разные результаты. Это именно то поведение, которое лично я ожидаю от простейшего templating engine, коим и является Helm.

Вывод

Выставление опции ‐‐namespace для helm install/upgrade никоим образом не управляет соответствующим параметром namespace в метаданных объектов Kubernetes. Более того, если ваши объекты уже содержат параметр namespace: <name_1> (в качестве примера), то helm создаст объекты именно в неймспейсе <name_1>, даже если ему будет явно выставлена опция ‐‐namespace <name_2>. А вот секрет с состоянием он положит в неймспейс <name_2>.

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

Разработчики helm рекомендуют НЕ устанавливать пространства имен для объектов Kubernetes в явном виде, а довериться опциям ‐‐namespace и ‐‐create-namespace. Я же считаю, что корректнее выставлять namespace: {{ .Release.Namespace }} для всех объектов Kubernetes, для которых параметр пространства имен вообще применим. Это как минимум даст вам понятную логику работы команды helm template, а как максимум – убережет от возможных расщеплений конфигураций.

На этом все. Если вдруг будут вопросы о работе с Helm, вы всегда можете написать мне.

Яндекс.Метрика