Несколько окружений: values-dev, values-prod
Главный практический паттерн Helm: один чарт и компактные файлы значений на каждое окружение.
Идея проста: шаблон один, а различия окружений собраны в маленьких файлах
values-<env>.yaml. Это прямое решение «боли голых манифестов» из первого урока.
Зачем вообще разделять окружения
Окружения существуют, чтобы изменения проходили проверку до того, как доберутся до пользователей. Dev — место, где ломать не страшно: туда выкатывают каждый коммит, ресурсы экономят, логи делают подробными. Staging максимально похож на прод, чтобы поймать то, что воспроизводится только «как в бою»: реальные домены, настоящие интеграции, близкие к проду лимиты. Prod — то, что видят пользователи: с запасом по ресурсам, автоскейлингом, сдержанным уровнем логов и строгими гарантиями отката. Если описывать каждое из этих окружений отдельным набором YAML-манифестов, вы получаете три почти одинаковые копии, которые неизбежно разъезжаются: правку в одном забыли перенести в другой, и прод начинает вести себя не так, как протестированный staging. Паттерн «один чарт — много values» придуман ровно против этого расхождения.
Структура репозитория
webapp/ # сам чарт (шаблоны общие для всех окружений)
├── Chart.yaml
├── values.yaml # дефолты (как правило = dev-подобные)
└── templates/
deploy/
└── values/
├── base.yaml # общее для всех окружений
├── dev.yaml # отличия dev
├── staging.yaml # отличия staging
└── prod.yaml # отличия prod
Что кладут в файлы окружений
Только то, что отличается. Образ, секреты и общая логика — не здесь.
# values/dev.yaml — дёшево, удобно дебажить
replicaCount: 1
resources:
requests: { cpu: 50m, memory: 64Mi }
ingress:
enabled: true
host: app.dev.example.com
env:
LOG_LEVEL: debug
autoscaling:
enabled: false
# values/prod.yaml — надёжно, с запасом
replicaCount: 5
resources:
requests: { cpu: 500m, memory: 512Mi }
limits: { cpu: "2", memory: 1Gi }
ingress:
enabled: true
host: app.example.com
env:
LOG_LEVEL: warn
autoscaling:
enabled: true
minReplicas: 5
maxReplicas: 20
Команды деплоя по окружениям
# dev
helm upgrade --install web ./webapp -n dev --create-namespace -f deploy/values/base.yaml -f deploy/values/dev.yaml --set image.tag="$CI_SHA"
# prod
helm upgrade --install web ./webapp -n prod --create-namespace -f deploy/values/base.yaml -f deploy/values/prod.yaml --set image.tag="$RELEASE_TAG" --atomic --timeout 5m
Везде один и тот же чарт ./webapp. Различие — лишь файл окружения. Образ задаётся динамически из CI.
Обратите внимание на пары флагов, которые отличают прод от dev. --atomic в проде означает: если релиз не стал здоровым в отведённый --timeout, Helm сам откатит его к предыдущей рабочей ревизии — пользователи не увидят полусломанного состояния. В dev этим часто жертвуют ради скорости и наглядности: пусть упавший под висит, чтобы было что отлаживать. --create-namespace уместен на эфемерных стендах, где namespace может ещё не существовать. Так одни и те же два файла значений обслуживают разную операционную политику окружений, и эта политика тоже становится частью воспроизводимой команды деплоя, а не устной договорённости.
Слой base: что общее
В base.yaml выносят то, что одинаково везде, но отличается от дефолтов чарта: имя сервисного аккаунта, общие аннотации, метки команды, политика рестартов. Это убирает дублирование между dev/staging/prod.
Полезно держать в голове критерий, что считать «общим». Значение едет в base, если при изменении его захочется поменять сразу во всех окружениях — например, метку владельца команды или общий префикс имён. Если же значение по своей природе разное на каждом стенде (хост, число реплик, уровень логов), ему место в файле окружения, и тащить его в base не нужно, даже если сейчас оно случайно совпадает в двух средах. Ошибка в обе стороны вредна: слишком толстый base заставляет окружения переопределять его обратно (а это снова дублирование, только наизнанку), а слишком тонкий — размазывает по env-файлам то, что должно жить в одном месте.
А нужен ли base вообще
Для маленького проекта с двумя окружениями слой base может оказаться лишней церемонией: если общего почти нет, проще держать всё в самих env-файлах и в дефолтах чарта. base окупается, когда окружений становится три и больше или когда заметная часть настроек реально одинакова. Не вводите base «на всякий случай» — вводите, когда видите конкретное дублирование, которое он устранит.
Диаграмма наложения
values.yaml (дефолты чарта)
+ base.yaml (общее для окружений)
+ prod.yaml (специфика прода)
+ --set image.tag (динамика сборки)
= итоговые .Values для релиза в prod
Как это масштабируется под капотом
Поскольку Helm детерминированно сливает источники, добавление нового окружения — это просто новый маленький файл values/qa.yaml и новая строка деплоя; шаблоны не трогаются вовсе. Это и есть выигрыш над голыми манифестами: сложность окружений вынесена в данные, а не в копии YAML. Различия окружений становятся обозримыми — достаточно открыть два файла и сравнить. Когда файлов окружений много и хочется управлять ими как единым набором (несколько релизов, общий шаблон команды), на сцену выходит Helmfile — отдельный инструмент, которому посвящён урок дальше.
Обозримость различий — недооценённое преимущество. Когда вся разница между staging и prod умещается в diff двух коротких файлов, ревью релиза превращается в осмысленное чтение: видно, что прод отличается ровно бо́льшим числом реплик и другим хостом, и ничем больше. Сравните это с попыткой глазами сверить два набора полноразмерных манифестов на сотни строк — там критичное отличие легко проскользнёт незамеченным. Маленькие env-файлы делают саму систему аудируемой.
Один и тот же чарт во всех окружениях — это и есть гарантия
Главная причина не плодить «отдельный чарт для прода» в том, что именно одинаковость шаблонов даёт смысл тестированию на staging. Если staging и prod рендерятся из одного чарта и отличаются только значениями, то «прошло на staging» что-то значит: вы проверили ту же логику шаблонов, что поедет в прод. Как только для прода заводится свой чарт, эта гарантия рушится — вы тестируете один код, а выкатываете другой, и расхождение проявится в самый неподходящий момент. Дисциплина «чарт ровно один» — не эстетика, а условие, при котором конвейер dev → staging → prod вообще имеет доказательную силу.
Частые ошибки
- Дублировать общее в каждом файле окружения. Общее — в
base.yaml, в env-файлах только различия. - Хранить секреты в env-файлах под git. Прод-пароли — через защищённые механизмы, не в открытом values.
- Разные чарты для окружений. Соблазн «для прода свой чарт» возвращает копипасту; чарт должен быть один.
Итог
- Один чарт + компактные
values-<env>.yaml— каноничное решение мультиокружения. - В env-файлах только различия; общее — в
base.yaml; образ — динамически из CI. - Новое окружение = новый файл значений, без правки шаблонов.