/
/
Платформа ресторанной сети

Стабилизация и перенос цифровой платформы ресторанной сети в новую инфраструктуру

О клиенте

Клиент — ресторанная сеть, которая использует сайт и мобильное приложение для взаимодействия с гостями. Оба клиентских приложения работают через единый бэкенд, связанный с базой данных, системой лояльности, платежными сервисами, CRM и другими внешними интеграциями.

Инфраструктура была размещена в облаке и построена на базе Kubernetes, управляемой PostgreSQL и объектного хранилища. Инженерная поддержка потребовалась из-за периодических падений бэкенда и недостаточного качества эксплуатации со стороны предыдущего подрядчика.

Исходная ситуация

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

Единого представления о состоянии проекта не было. Разработчики и специалисты по инфраструктуре давали противоречивые оценки: часть проблем считалась устраненной, хотя приложение продолжало падать. Доступы к CI/CD и отдельным компонентам инфраструктуры также были ограничены, поэтому диагностику пришлось начинать с восстановления технической картины проекта.

Аудит показал, что отказы связаны не с одной неисправностью. В инфраструктуре одновременно присутствовали ошибки управления ресурсами, проблемы в логике запуска приложения, устаревшие компоненты, небезопасные способы доступа и недостаточная наблюдаемость.

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

Какие проблемы мы обнаружили

Kubernetes не управлял ресурсами приложения
Для подов не были заданы запросы и ограничения по процессору и памяти. Kubernetes относил такую нагрузку к классу BestEffort и не располагал данными, необходимыми для корректного планирования ресурсов и работы автоскейлера.

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

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

Инфраструктура при этом не позволяла надежно отделить превышение заданного лимита от других ошибок: лимиты отсутствовали, а предыдущие логи контейнеров сохранялись не полностью. Это усложняло диагностику и позволяло сбоям повторяться без точного технического объяснения.
Миграции базы данных выполнялись при запуске каждой реплики
При анализе логов и сценариев запуска выяснилось, что каждый новый экземпляр бэкенда автоматически выполнял миграции и заполнение базы данных.

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

Механизм, который должен был автоматически поднимать приложение, сам создавал риск его отказа и неконтролируемых изменений базы данных.
Инфраструктура содержала уязвимые и устаревшие компоненты
Версия Kubernetes устарела и больше не поддерживалась. API кластера был доступен через публичный адрес.

Инструмент администрирования базы данных также был опубликован во внешней сети и подключался к PostgreSQL с избыточными полномочиями. В инфраструктуре использовались устаревшие версии ingress-компонентов с известными критическими уязвимостями.

Секреты приложений хранились преимущественно в переменных CI/CD. Управление ими зависело от старой системы сборки и доступов предыдущего подрядчика.
Среды и инфраструктурные компоненты не были достаточно разделены
Системные сервисы, производственная нагрузка и тестовое окружение работали без четкого разграничения по группам узлов. Это повышало вероятность того, что сбой или рост нагрузки одного компонента повлияет на остальные.

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

Некоторые публичные хранилища использовались без версионирования, ограничений объема и правил жизненного цикла. Доступ к ним сохранялся у сотрудников предыдущего подрядчика.
Эксплуатация зависела от закрытых знаний старой команды
У клиента не было полного контроля над CI/CD, инфраструктурным кодом и частью переменных окружения. Перенести старую систему целиком было невозможно, поэтому конфигурацию приложений, пайплайны и правила деплоя пришлось восстанавливать по существующей реализации.

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

Что было сделано

1
Провели аудит приложения и инфраструктуры
Мы восстановили архитектуру проекта, сопоставили состояние Kubernetes, логи приложений, графики потребления ресурсов и сценарии запуска контейнеров.

Вместо предположения о том, что приложению просто не хватает вычислительных ресурсов, были выделены несколько связанных причин: отсутствие requests и limits, рост потребления памяти, небезопасная логика миграций и недостатки конфигурации кластера.

Одновременно был проведен аудит безопасности, доступов, хранилищ, CI/CD и вспомогательных виртуальных машин. Это позволило сформировать план не только устранения текущих падений, но и приема проекта на поддержку.
2
Спроектировали новую инфраструктуру
Новая инфраструктура была описана с помощью Terraform и Terragrunt. В нее вошли:
  • управляемый кластер Kubernetes;
  • отдельные группы узлов для production, non-production и инфраструктурных компонентов;
  • управляемые PostgreSQL и Redis;
  • балансировщики нагрузки;
  • отдельные серверы для GitLab, GitLab Runner, VPN и служебных систем;
  • объектные хранилища для резервных копий и пользовательских данных;
  • централизованные системы мониторинга, логирования и отслеживания ошибок.

групп узлов с помощью меток и taints позволило изолировать системную нагрузку от приложений и тестовых сред. Производственные узлы были распределены по разным зонам доступности.
3
Пересобрали контур разработки и доставки
Поскольку получить полную копию старого GitLab было невозможно, репозитории переносились отдельно. Необходимые переменные и параметры CI/CD восстанавливались и проверялись вручную.

Для приложений были подготовлены новые пайплайны сборки и деплоя. Развертывание в Kubernetes перевели на декларативную модель с GitOps-инструментами.

Секреты вынесли в зашифрованные конфигурационные файлы. История их изменений стала храниться вместе с кодом, при этом значения не оставались в открытом виде в репозитории.
Для разработчиков подготовили отдельное тестовое окружение внутри нового кластера и отдельные базы данных. Это заменило прежнюю схему, при которой тестовая среда разворачивалась через SSH и Docker Compose на отдельном сервере.
4
Развернули наблюдаемость и аварийные сценарии
В новой инфраструктуре были настроены сбор метрик, логирование приложений и инфраструктуры, дашборды и алерты.

Контроль охватил:
  • состояние Kubernetes и его рабочих узлов;
  • готовность подов и успешность обновлений;
  • потребление ресурсов;
  • работу PostgreSQL и Redis;
  • доступность приложения;
  • задержки ответов бэкенда;
  • ошибки внешних платежных и интеграционных сервисов;
  • состояние сертификатов и публичных маршрутов;
  • синхронизацию приложений с декларативной конфигурацией.

Алерты по внешним интеграциям строились на реальных метриках приложения, а не только на прямых запросах к сторонним API. Это снизило риск ложных срабатываний и лишнего расходования лимитов внешних сервисов.

Для известных аварий были подготовлены инструкции, контакты ответственных и правила эскалации.
5
Подготовили production и провели переключение
До переноса приложений были развернуты и проверены производственные группы узлов, инфраструктурные сервисы, управляемый Redis, внешний балансировщик, сертификаты, маршрутизация и подключение к базе данных.

Существующие редиректы, которые использовались в том числе в QR-кодах и печатных материалах, перенесли в новую инфраструктуру. Для них настроили отдельные проверки доступности.

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

До переключения были обнаружены и исправлены отсутствующие переменные окружения, ошибка подключения фоновых задач к Redis и проблема подстановки конфигурации во фронтенд.

После этого команда выполнила производственный деплой. Все реплики приложений и фоновые обработчики запустились без рестартов, логирование и мониторинг продолжили работать. Команде разработки передали возможность самостоятельно выполнять последующие релизы через новый CI/CD.
6
Документировали эксплуатацию
В проектной базе знаний были описаны:
  • устройство инфраструктуры;
  • порядок работы с зашифрованными секретами;
  • процессы CI/CD;
  • инструкции для разработчиков;
  • известные неисправности;
  • сценарии действий при авариях;
  • контакты и правила эскалации.

Документация дополнялась по результатам первых производственных релизов и реальных срабатываний мониторинга.

Результат

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

производственная, тестовая и инфраструктурная нагрузки разделены
компоненты распределены по нескольким зонам доступности
инфраструктура описана как код и может быть воспроизведена
CI/CD перенесен под контроль клиента и новой команды поддержки
секреты переведены в управляемое зашифрованное хранение
настроены централизованные мониторинг, логирование и алерты
создан отдельный управляемый Redis для production
восстановлены сертификаты, маршруты и необходимые редиректы
производственные приложения запущены в новом кластере без рестартов после релиза
команда разработки получила возможность самостоятельно выполнять последующие деплои
для дежурных инженеров подготовлены инструкции и сценарии реагирования
снизилась зависимость проекта от
 закрытых знаний и доступов предыдущего подрядчика

Вывод

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

Проект потребовал не точечного ремонта старого кластера, а пересборки инженерного контура: от инфраструктуры и CI/CD до мониторинга и аварийных инструкций. В результате клиент получил систему, состояние которой можно наблюдать, изменения — воспроизводить, а эксплуатацию — передавать между инженерами без потери критичных знаний.

Смотрите другие
кейсы по Bitrix

    Error get alias

    Хотите передать
    свою инфраструктуру в надежные руки?

    Будем рады проконсультировать вас и обсудить проект.