Переопределение значений: -f и --set на практике
Два инструмента переопределения и чёткие правила, когда какой уместен.
-f файл.yaml— для устойчивой, версионируемой конфигурации окружения.--set ключ=значение— для разовых, динамических или секретных переопределений в момент запуска.
Когда -f, когда --set
| Случай | Инструмент |
| Конфиг окружения (prod/staging) | -f prod.yaml в git |
| Тег образа из CI-переменной | --set image.tag=$CI_SHA |
| Секрет из переменной пайплайна | --set (не в git!) |
| Много связанных настроек | -f (читаемо) |
| Одна-две правки поверх | --set |
Комбинируем слои
Типичный прод-вызов комбинирует общий базовый файл, файл окружения и динамику из CI:
helm upgrade --install web ./chart -n prod -f values/base.yaml -f values/prod.yaml --set image.tag="$CI_COMMIT_SHA" --atomic --timeout 5m
Логика читается сверху вниз: общие настройки → специфика прода → конкретная сборка. Тег образа меняется на каждый коммит, поэтому он динамический через --set, а не в файле.
Почему именно так разделяют «что в файл, а что в флаг»? Здравый критерий — спросить себя: «это значение известно заранее и живёт долго, или оно вычисляется в момент запуска?». Хост ingress, число реплик, лимиты ресурсов известны заранее и меняются редко — им место в версионируемом файле, где история правок видна в git и проходит code review. Тег образа, идентификатор сборки, значение из секрет-стора вычисляются в пайплайне здесь и сейчас — их естественно подать через --set. Это разделение заодно решает вопрос воспроизводимости: по файлам окружения можно восстановить, какой была конфигурация месяц назад, а эфемерные значения и не должны жить в истории.
Сколько -f можно складывать
Ограничения на число -f нет, но злоупотреблять стопкой из пяти-шести файлов не стоит: чем больше слоёв, тем труднее в уме проследить, откуда пришло конкретное значение. Здоровый предел на практике — два-три файла: общий base.yaml, файл окружения и, при необходимости, файл региона или кластера. Если слоёв становится больше, это обычно знак, что пора либо пересмотреть, что лежит в base, либо переходить к инструменту-обёртке вроде Helmfile, который описывает весь набор релизов декларативно и снимает с вас ручную сборку длинных команд.
Синтаксис --set детально
--set a.b.c=value # вложенность через точку
--set 'list={x,y,z}' # задать список целиком
--set 'arr[0].name=web' # элемент списка по индексу
--set 'a.b=c\,d' # экранировать запятую внутри значения
--set-string version=1.0 # форсировать строку
Запятая в --set — разделитель пар, поэтому в значениях её экранируют \,. Точка — разделитель уровней, в ключах её тоже экранируют. Из-за этих экранирований сложные значения чаще выносят в файл.
Отладка: всегда смотрите результат
Главная привычка: перед боевым запуском прогоните рендер и сравните с ожиданием.
# увидеть итоговые манифесты с вашими переопределениями
helm template web ./chart -f values/prod.yaml --set image.tag=abc123
# показать только итоговые значения (debug)
helm template web ./chart -f values/prod.yaml --set image.tag=abc123 --show-only templates/deployment.yaml
--show-only выводит лишь один манифест — удобно, когда чарт большой.
Есть и третий, самый прямой способ убедиться, что значение доехало: посмотреть итоговые .Values целиком. Это снимает класс ошибок «кажется, я переопределил, но не сработало», потому что вы видите не догадку, а реальную карту, с которой Helm пошёл рендерить.
# показать итоговые объединённые значения как YAML
helm template web ./chart -f values/prod.yaml --set image.tag=abc123 --debug 2>&1 | head -n 40
# для уже установленного релиза — что реально применено
helm get values web -n prod --all
Привычка «сначала template, потом upgrade» стоит секунд, а экономит часы: вы ловите опечатку в пути, неверный тип значения или забытый файл окружения до того, как это уедет в кластер. Особенно ценно это в связке с --atomic: template отлавливает ошибки рендера, а --atomic страхует от полуприменённого релиза, если что-то всё же пойдёт не так на стороне Kubernetes.
Антипаттерн: секреты в файле в git
Не кладите пароли и токены в values/prod.yaml под git. Для секретов: либо --set из защищённой CI-переменной, либо специализированные инструменты (helm-secrets/sops, внешние секрет-сторы) — об этом отдельный урок. Файл значений в git виден всем, у кого есть доступ к репозиторию.
Важно понимать, чем именно опасен секрет в git, кроме очевидного «его увидят коллеги». Git хранит всю историю: даже если вы потом удалите пароль коммитом сверху, он останется в прошлых ревизиях, и вычистить его — отдельная болезненная операция с переписыванием истории. Плюс репозитории попадают в зеркала, форки, кэши CI и резервные копии — однажды закоммиченный секрет нужно считать скомпрометированным и ротировать, а не просто «убрать». Поэтому правило жёсткое: секрет вообще не должен оказаться в файле под версионным контролем, даже на минуту.
У --set для секретов тоже есть нюанс: значение попадает в командную строку, а значит может засветиться в логах CI и в выводе ps на раннере. Защищённые переменные пайплайна обычно маскируются в логах, но это зависит от платформы. Когда секретов много или они чувствительные, чище подключать их через Kubernetes Secret (созданный отдельно или внешним контроллером вроде External Secrets), а в values держать лишь ссылку на имя секрета — тогда само значение нигде в цепочке деплоя не светится.
Как --set парсится под капотом
Строка a.b[0].c=val разбирается слева направо в дерево: точки создают вложенные карты, [i] — элементы списка, = отделяет значение. Тип значения определяется эвристикой: true/false → булев, число-похожее → число, остальное → строка. Затем это маленькое дерево сливается поверх остальных слоёв с наивысшим приоритетом. Именно из-за эвристики типов --set tag=1.0 превращается в число, и существует --set-string, отключающий угадывание. Понимание, что --set строит именно дерево, объясняет, почему опечатка в пути не вызывает ошибку — она просто создаёт новую неиспользуемую ветку в .Values.
Частые ошибки
- Секреты в git-файле values. Утечка через репозиторий; используйте CI-переменные или sops.
- Опечатка в пути
--set. Молча создаёт мёртвую ветку, шаблон её не читает — «значение не применилось». - Незаэкранированная запятая.
--set urls=a,bвоспримется как две пары; нужноa\,bили файл.
Итог
-f— для версионируемых конфигов окружений;--set— для динамики и секретов из CI.- Комбинируйте слоями (base → env → CI); проверяйте через
helm templateи--show-only. - Опечатка в пути
--setне ошибка, а мёртвая ветка — отсюда «не применилось».