Logo Craft Homelab Docs Нейросети Хостинг Обучение Контакты
Переезд 400 Helm-релизов между Kubernetes-кластерами с сохранением rollback Трендовые github проекты в нашем телеграм канале. Подпишись →
8 ноября 2026 г.

Подмена секрета Helm: как перевезти 400 сервисов и оставить рабочий helm rollback

Команда платформы ядра банка получила уведомление от провайдера внутреннего Kubernetes-as-a-Service: текущие кластеры устарели, нужно мигрировать на новые. До дедлайна оставалось около четырёх месяцев. Переезд прода запланировали через три, чтобы был запас на случай проблем.

Масштаб выглядел так:

  • около 400 сервисов, развёрнутых через Helm общим пайплайном, часть из них — больше года назад;
  • больше 25 неймспейсов;
  • 5 кластеров: один test, два preview, два prod.

Раскатать всё в новых кластерах с нуля мешали четыре обстоятельства:

  1. В новых кластерах действуют более строгие политики безопасности, и манифесты нужно дополнить недостающими блоками.
  2. Часть манифестов когда-то правили вручную — как правило, это были учётные данные. Эти изменения нельзя потерять.
  3. Не все приложения умеют работать в нескольких инстансах одновременно, поэтому старая и новая копия не могут жить параллельно.
  4. Число подключений к базам данных ограничено: если поднять сервис в новом кластере, не погасив в старом, коннектов может не хватить.

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

Подготовка до выбора инструмента

Первым делом собрали все внешние зависимости сервисов и заказали сетевые доступы из новых кластеров. Заявки на сеть выполняются долго, поэтому их запустили раньше всего остального.

Пока заявки шли, сервисы отсортировали и определили порядок переезда. Скейлинг планировали с учётом двух вещей: сколько подключений к БД держит каждый сервис и какие сервисы зависят друг от друга. Здесь пригодились существующие архитектурные схемы.

Почему отпали готовые инструменты

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

GitLab CI-пайплайн. Пайплайн был обкатан и надёжен, но для переезда пришлось бы прожать примерно 400 × 2 запусков на два прод-кластера и следить за каждым Helm-релизом в раннере. Постепенный переезд силами команд добавлял координацию, split-brain между кластерами и расхождения версий и конфигов.

Velero. Действия описываются через custom resources, что удобно. Но манифесты нужно было патчить по дороге, а возможностей для изменения ресурсов на лету оказалось мало.

Argo CD. GitOps гарантирует соответствие кластера репозиторию, но внедрять его пришлось бы с нуля: разобрать corner case каждой команды (все деплоятся по-разному) и не сломать существующий процесс разработки. Менять подход к доставке одновременно с миграцией кластеров сочли плохой идеей.

kube-dump. По сути набор обёрток над kubectl. Требует прав администратора кластера, которых в исходном кластере не было, и тоже не умеет патчить манифесты при переносе.

Свой скрипт. Каждое готовое решение закрывало часть задачи, но ни одно не укладывалось во все ограничения сразу. Остановились на нём.

Что именно переносить

Все приложения были развёрнуты через Helm, поэтому переносили только Helm-релизы. Такой фильтр сразу отсекает мусорные манифесты, которые накопились в кластере вне релизов, и упрощает отбор ресурсов по имени приложения.

Ключевой приём связан с тем, как Helm хранит состояние. Для каждой ревизии релиза Helm создаёт в неймспейсе секрет с описанием того, что он развернул. Идея была в том, чтобы отредактировать этот секрет и положить его в новый кластер так, чтобы Helm не заметил подмены. В итоге в новом кластере оказывается тот же стабильный релиз, что работал в старом, но уже с настройками нового окружения. Если сразу после переезда кто-то неудачно выкатит свежую версию, helm rollback отработает штатно, как будто релиз с самого начала жил в новом кластере.

Алгоритм скрипта

Скрипт выполнял восемь шагов:

  1. Выгрузить из Kubernetes API секреты Helm-релизов.
  2. Выгрузить live-манифесты из кластера.
  3. Если отдельные ресурсы правились вручную, наложить live-версии поверх манифестов из релиза. Так сохраняются ручные изменения вроде учётных данных.
  4. Заменить все упоминания имени старого кластера.
  5. Добавить в манифесты блоки, которых требуют политики безопасности нового кластера.
  6. Заново собрать секрет Helm-релиза, чтобы после переноса оставался рабочий rollback.
  7. Сохранить манифесты локально.
  8. Сгенерировать команды для применения в новом кластере и записать их в отдельный файл.

Остановку и запуск приложений автоматизировать не стали. Это было возможно, но комбайн на все случаи не помещался в спринты, поэтому решение осталось полуручным.

На выходе для переноса из my-cluster в new-cluster с неймспейсами ns-1 (приложения app-11, app-12) и ns-2 (app-21, app-22) получалась такая структура:

commands.sh
ns-1/
├── app-11.yaml
└── app-12.yaml
ns-2/
├── app-21.yaml
└── app-22.yaml

commands.sh переключает контекст на new-cluster и применяет содержимое каждой директории в одноимённый неймспейс. В app-XX.yaml собраны все ресурсы приложения: Deployment, Service, Ingress, ConfigMap и остальные.

Перед началом работ на ноутбуке лежит полный слепок того, что должно оказаться в целевом кластере. Его можно просмотреть до применения.

Ночь переезда

Применять всё одной командой не стали. Установку разбили на этапы, и после каждого решали, чинить, откатывать или идти дальше.

Перед продом процесс отладили на нон-прод окружениях: test и preview переехали заранее. Работы на проде назначили на 4:00, коллег предупредили за месяц, за неделю и за день.

Первыми переносили платформенные сервисы — прослойки между ядром и остальным банком, от которых зависят другие системы. По ходу следили в Grafana за подключениями к БД и нагрузкой на хосты. Где-то не хватало коннектов, и часть сервисов гасили в старом кластере, чтобы освободить подключения.

Когда переехали две трети сервисов, в очередном неймспейсе не стартовало приложение, а следом ушли в бутлуп ещё два. В логах были таймауты подключения к одной из БД. Причина: кластер БД состоял из трёх нод, а сетевой доступ из нового кластера открыли только до первой.

Этим трём сервисам повезло с архитектурой: все их взаимодействия асинхронные, и они спокойно работают без соседей в кластере. Их оставили в старом кластере с пометкой «перенести позже» и продолжили. Второй прод-кластер переехал без сюрпризов. После этого остатки в старом кластере погасили, а общий пайплайн и синхронный трафик переключили на новые кластеры.

Что из этого стоит забрать себе

  • Сетевые доступы заказывайте до всего остального и проверяйте до каждой ноды. Единственная авария за ночь случилась из-за доступа, открытого к одному хосту из трёх в кластере БД. Проверка связности со всеми нодами каждой внешней зависимости из нового кластера закрывает этот класс ошибок.
  • Переносите Helm-релиз целиком вместе с его секретом. Пересобранный секрет сохраняет историю ревизий, и helm rollback в новом кластере работает так же, как в старом.
  • Накладывайте live-состояние поверх манифестов релиза. Ручные правки в кластере — норма для сервисов, которые живут больше года. Если переносить только то, что записано в релизе, они потеряются.
  • Планируйте скейлинг по лимитам подключений к БД. Сервисы, которые не умеют работать в нескольких инстансах или держат много коннектов, гасите в старом кластере до подъёма в новом.
  • Автоматизируйте только перенос манифестов. Остановку и запуск приложений на проде оставили человеку с дашбордами, и именно это позволило по ходу решить, что делать с тремя сервисами без доступа к БД.

Скрипт получился достаточно универсальным, и его потом использовали ещё для нескольких переездов.