upgrade, rollback и uninstall

Релиз — живой объект: его меняют, откатывают и удаляют. Разбираем три глагола его жизни.

helm upgrade применяет новые значения или новую версию чарта к существующему релизу, создавая новую ревизию. helm rollback возвращает релиз на любую прошлую ревизию.

В прошлом уроке мы поставили релиз — это была ревизия 1. Реальная жизнь приложения — это поток изменений: подняли реплики, сменили образ, поправили лимиты. Каждое такое изменение в мире Helm — это upgrade.

Ключевая идея, которую стоит усвоить сразу: вы никогда не правите кластер «напрямую» под управлением Helm. Вместо этого вы меняете желаемое состояние — новые values или новую версию чарта — и просите Helm привести кластер к нему. Helm заново рендерит манифесты, сравнивает их с тем, что развернул в прошлый раз, и применяет разницу. Такой декларативный подход означает, что источником истины становится ваша конфигурация, а не накопившиеся вручную правки. Если относиться к релизу так, история остаётся чистой и предсказуемой, а откат — безопасным.

upgrade: изменяем релиз

# увеличим число реплик у уже установленного релиза
helm upgrade my-web bitnami/nginx -n demo   --set replicaCount=3 --reuse-values

Флаг --reuse-values важен: он берёт значения из текущей ревизии и накладывает поверх только новые. Без него Helm сбросит все ваши прошлые переопределения к дефолтам чарта — классическая ловушка, из-за которой «после апгрейда всё откатилось к стандартным настройкам».

Здесь есть развилка из двух стратегий, и важно осознанно выбрать одну. Первый путь — императивный: каждый раз дополнять текущие values маленькими --set и полагаться на --reuse-values, чтобы не потерять накопленное. Он удобен для разовых ручных правок, но коварен: реальная конфигурация релиза постепенно «расползается» по истории команд, и восстановить её целиком можно лишь через helm get values. Второй путь — декларативный: держать полный файл values.yaml в git и при каждом апгрейде передавать его через -f без --reuse-values. Тогда файл — единственный источник истины, а diff в pull request честно показывает, что именно меняется. Для продакшена почти всегда выбирают второй путь; --reuse-values остаётся инструментом для быстрых ручных вмешательств. Существует и родственный флаг --reset-values, который явно сбрасывает values к дефолтам чарта — иногда это именно то, что нужно, чтобы «начать с чистого листа».

После upgrade появляется ревизия 2:

helm list -n demo

Вывод:

NAME  	NAMESPACE	REVISION	STATUS  	CHART
my-web	demo     	2       	deployed	nginx-15.4.2

install-or-upgrade одним флагом

В CI удобно не проверять, существует ли релиз. Флаг --install у upgrade создаёт релиз, если его нет, иначе обновляет:

helm upgrade --install my-web bitnami/nginx -n demo   -f values.yaml --version 15.4.2

Это самая частая команда в пайплайнах: идемпотентна и не падает на «релиз уже существует» / «релиз не найден».

Атомарность: --atomic

Что если апгрейд сломался на полпути (новый образ не стартует)? По умолчанию релиз застрянет в статусе failed. Флаг --atomic заставляет Helm автоматически откатиться к предыдущей рабочей ревизии при неудаче, а --timeout ограничивает ожидание готовности:

helm upgrade --install my-web bitnami/nginx -n demo   -f values.yaml --atomic --timeout 5m

Стоит понимать, что атомарность Helm — это не транзакция базы данных. Kubernetes применяет ресурсы по очереди, и «откат» при сбое — это, по сути, ещё один rollback на прошлую ревизию, который Helm выполняет за вас. Если предыдущая ревизия была рабочей, всё закончится хорошо. Но если новый релиз успел, например, выполнить необратимую миграцию схемы базы данных через хук, откат манифестов не отменит изменения в данных. Поэтому --atomic отлично защищает от «не стартующего пода», но не освобождает от обязанности делать миграции совместимыми вперёд и назад. Связанный флаг --wait заставляет Helm дождаться, пока все ресурсы перейдут в готовое состояние, прежде чем объявить апгрейд успешным; --atomic включает его автоматически.

rollback: откат на прошлую ревизию

helm history my-web -n demo          # посмотреть ревизии
helm rollback my-web 1 -n demo       # вернуться на ревизию 1

Откат — это тоже новое изменение: rollback на ревизию 1 создаёт ревизию 3, содержимое которой повторяет ревизию 1. История не переписывается, она только растёт. Это важно: вы всегда можете «откатить откат».

Эта модель «история только растёт» — сознательное проектное решение, и она радикально отличается от привычного kubectl apply, который не хранит никакой ленты прошлых состояний. Благодаря ей откат предсказуем: Helm не пытается «вычислить обратную операцию», он просто берёт уже сохранённый снимок целевой ревизии и применяет его как новый. Если вы откатились на ревизию 1, а потом поняли, что зря, — никакой паники: ревизии 2 и 3 на месте, и helm rollback my-web 2 вернёт вас обратно. Единственное, что нужно держать в голове, — номера ревизий монотонно растут и никогда не переиспользуются, поэтому сверяйтесь с helm history, а не с памятью.

helm history my-web -n demo

Вывод:

REVISION	STATUS    	DESCRIPTION
1       	superseded	Install complete
2       	superseded	Upgrade complete
3       	deployed  	Rollback to 1

uninstall: удаление релиза

helm uninstall my-web -n demo
# сохранить историю на случай «передумал»:
helm uninstall my-web -n demo --keep-history

По умолчанию uninstall удаляет и все созданные ресурсы, и историю релиза. С --keep-history запись о релизе остаётся в статусе uninstalled, и его можно откатить обратно.

Как хранится история под капотом

Каждая ревизия релиза сохраняется как Secret типа helm.sh/release.v1 в namespace релиза. Имя выглядит как sh.helm.release.v1.my-web.v2. Внутри — сжатый gzip+base64 снимок отрендеренных манифестов и значений. Именно поэтому rollback работает offline: Helm не пересобирает чарт, а достаёт готовый снимок прошлой ревизии и применяет его. Удалите эти Secret вручную — потеряете историю.

Частые ошибки

  • upgrade без --reuse-values при переопределении через --set сбрасывает прошлые кастомные значения к дефолтам.
  • Ручное kubectl edit ресурсов релиза. Helm про это не знает; следующий upgrade перетрёт ваши правки. Меняйте только через Helm.
  • Забыть -n namespace. Команды по умолчанию работают в namespace из контекста, а релиз может жить в другом.

Итог

  • upgrade создаёт новую ревизию; --install делает команду идемпотентной для CI, --atomic откатывает при сбое.
  • rollback N возвращает на ревизию N, добавляя новую ревизию; историю можно «откатить обратно».
  • uninstall удаляет релиз; --keep-history сохраняет возможность отката.
Проверьте себя
1. Что делает helm upgrade --install ... ?
AТолько создаёт релиз
BСоздаёт релиз, если его нет, иначе обновляет — идемпотентно
CУдаляет и пересоздаёт
DОткатывает релиз
2. Зачем нужен --reuse-values при upgrade?
AУскоряет апгрейд
BСохраняет ранее заданные кастомные значения, накладывая новые поверх
CШифрует values
DУдаляет старые ревизии
3. Что произойдёт при helm rollback на ревизию 1?
AИстория перезапишется и останется одна ревизия
BСоздастся новая ревизия, повторяющая содержимое ревизии 1
CРелиз удалится
DЧарт пересоберётся заново