2000+ развертываний в день: как мы строили DevOps-конвейер для 300 микросервисов и куда идем дальше

от автора

Когда у вас более 100 команд, более 200 активных проектов и более 300 разрабатываемых приложений, ручной CI/CD умирает быстро и некрасиво. Мы в Диасофт несколько лет назад начали строить Digital Q.DevOps — внутренний конвейер сборки, тестирования, доставки и развёртывания, — и сейчас через него проходит больше 2000 развёртываний в сутки. На прошлой неделе мы собрали внутренний митап с разработчиками, тестировщиками и DevOps-инженерами, чтобы честно разобрать, что в продукте получилось, что до сих пор болит, и куда мы движемся.

В разборе мы говорили об архитектуре, использовании Helmchart, а также о том, почему мы до сих пор не можем единообразно выпускать релизы, и у нас в репозитории для клиентов хранится всего 10 последних образов микросервиса (и почему это проблема).

Зачем понадобился свой конвейер

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

  • ИТ-компонент — атомарная единица инфраструктуры: кластер Kubernetes, сервер приложений, СУБД, брокер сообщений. Описывается один раз, с типом и набором атрибутов «из коробки» (для Kubernetes, Kafka, БД и так далее), а дальше переиспользуется без повторного конфигурирования.

  • Инсталляция — конкретный экземпляр продуктовой конфигурации, развёрнутый на определённом наборе ИТ-компонентов.

  • Стенд — логическое объединение нескольких инсталляций в рабочий контур: разработка, автотестирование, демо, препрод, прод и так далее.

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

Все это живёт в Q.CMDB — модуле управления конфигурациями, который как раз отвечает за то, чтобы DevOps-инженеру не нужно было каждый раз вручную прописывать, куда какой сервис ставить и с какими параметрами.

Сами по себе эти сущности — способ типизировать инфраструктуру. Ценности здесь пока нет. Ценность появляется тогда, когда накатывается автоматический pipeline: команда один раз описала стенд и инсталляцию, а дальше при каждом коммите конвейер сам находит нужную конфигурацию, разворачивает изменения и прогоняет тесты — без ручного указания путей, параметров и связей. Вот что это даёт в цифрах.

Что получилось автоматизировать

Цифры, с которых мы начали этот разбор, и с которых обычно начинаются все презентации (больше 2000 развёртываний в день, нагрузка от 100+ команд в 200+ проектах, 300+ активно разрабатываемых приложений) неплохо описывают масштаб задачи.

Механика конвейера на каждый коммит выглядит так:

  • Сборка — компиляция штатным компилятором языка, упаковка в архив или Docker-образ.

  • Тестирование — автоматический запуск unit-тестов, статического анализа (SonarQube), API-тестов и регрессии.

  • Развёртывание — параметризация под конкретный стенд, разворачивание целостного приложения из нескольких сервисов и образов.

  • Доставка — обновление сервисов и структуры БД на целевом стенде без участия человека.

Отдельно стоит сказать про автотесты: мы генерируем их с помощью LLM. Модель получает Swagger-описание контрактов сервиса и сценарий, выбирает релевантные API и события, генерирует тест, запускает его на стенде и, если тест падает, сама предлагает исправление и перезапускает — в среднем такой цикл занимает 3–4 итерации до зелёного результата.

Helm-чарты и Helmfile: что добавили только что

Раньше для развёртывания нам нужно было точечно собирать конфигурацию под каждое окружение. Сейчас Digital Q.DevOps умеет автоматически формировать не только Helm-чарты для развёртывания в Kubernetes, но и Helmfile — файлы оркестрации, управляющие сразу несколькими чартами.

Зачем отдельный Helmfile, если есть Helm? Потому что при сотнях микросервисов в составе одной поставки upstream-вариант с одним большим umbrella chart на всё перестаёт работать: версии у сервисов разные, зависимости разные, условия развёртывания разные. Helmfile позволяет деплоить каждый компонент независимо, не теряя централизованного управления комплектом.

Пользователь выбирает в интерфейсе нужные продукты, версии компонентов и целевую среду — система автоматически собирает комплект Helm-чартов и Helmfile, который дальше можно встроить в любой существующий CI/CD-пайплайн, включая чужой Jenkins или GitLab CI, без необходимости менять привычные инструменты заказчика. Технически конфигурации собираются в набор артефактов с управляющим мастер-чартом, который можно установить напрямую через Kubernetes API любым менеджером пакетов Helm — даже без нашего конвейера на стороне получателя.

Для менее мощных окружений то же самое работает и через Docker Compose — можно автоматически сгенерировать скрипты и развернуть продукт локально, без кластера Kubernetes. Это направление мы тоже продолжаем докручивать, чтобы порог входа в использование микросервисных продуктов был ниже.

Три проблемы, о которых говорили на митапе

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

Монолит экосистемы против легковесного захода к клиенту

Понятно, что развивая продукт внутри «Диасофт» и под свои собственные задачи, мы изначально не планировали продвигать его на внешний рынок. Это наш инструмент разработки в составе экосистемы Digital Q для оптимизации наших процессов. Но с развитием экосистемы для разработчиков мы начали поставлять свой DevOps вместе с экосистемой партнерам, в том числе технологическим, то есть командам, которые берут нашу платформу как инструмент для разработки собственных приложений. Вторым сегментом наших потребителей стали крупные заказчики сегмента enterprise, в которых мы ведем внедрения больших комплексных проектов. И вот когда мы вышли к внешнему заказчику, стало очевидно, что ему далеко не всегда нужен весь объём: GitLab, Jenkins, Nexus, SonarQube, агенты сканирования — весь зоопарк инфраструктурных компонентов. У заказчика может уже быть свой GitLab со своими пайплайнами, и дублировать его рядом — просто трата ресурсов с обеих сторон.

Сейчас мы прицельно работаем над тем, чтобы выделить минимально достаточный pipeline — компиляция, получение бинарных артефактов, упаковка в контейнер, публикация — и дать возможность подключать остальной функционал (тестирование, кодогенерацию, расширенные проверки) модулями, по потребности, а не «всё включено». Технически это означает декомпозицию текущего pipeline на более независимые шаги, которые можно собирать в произвольный набор — что-то вроде BPM-блоков, каждый со своим минимальным бэкенд-агентом, из которых можно конструировать собственный pipeline под конкретную инфраструктуру заказчика.

Прямого решения «уже сегодня» нет — задача архитектурно непростая, потому что текущая реализация плотно завязана на внутренние инструменты разработки и наши же архитектурные базы. Но это то, что мы положили себе в бэклог и уже начали работу над первой коробочной версией, которая появится в течение ближайших двух кварталов.

Релизный цикл: upstream против стабильных версий

Что еще подлежит переосмыслению. Внутри компании мы долго жили на upstream-сборках: непрерывный поток ежедневных изменений без выделенных релизов. Для внутренних команд это нормально — быстрая итерация важнее стабильности. Но для тиражирования внешним клиентам это создаёт реальную проблему: в репозитории для клиентов хранится ограниченное количество последних образов на микросервис, и если по одному сервису за день прилетает 10+ изменений, старые версии быстро вытесняются новыми. Найти конкретную более старую версию для повторной установки становится сложно.

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

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

Безопасность по умолчанию — это компромисс, а не данность

Самое прямое признание с митапа: сейчас критические уязвимости (CVE с высоким баллом) не блокируют сборку и выпуск по умолчанию. Проверки (SonarQube, сканирование образов) есть, результаты видны командам в pipeline, но являются информативными — конкретный продукт или проект может настроить более жёсткий режим, если для него это критично, но по умолчанию это так не работает.

Почему так? Остановка сборки на каждом найденном крите при текущем темпе разработки рискует остановить производство как таковое — базы уязвимостей обновляются ежедневно, и угнаться за всеми невозможно физически. Решение сейчас регулируется в первую очередь целесообразностью конкретных проектов: для заказчиков с высоким порогом входного контроля (банковский сектор, инфраструктура с жёсткими комплаенс-требованиями) выставляется жёсткий режим — критичная уязвимость блокирует поставку. Для остальных порог мягче.

Стоит отметить еще одну общую тенденцию, которая не делает задачу легче: находить уязвимости сейчас ощутимо проще, чем их закрывать. Сканеры и базы CVE обновляются ежедневно, эксплоит для могут собрать за дни, а вот фикс — особенно если он тянет за собой пересборку базового образа и всего, что на нём стоит, — занимает длительные временные интервалы. Этот разрыв со временем не сокращается, а растёт, и это значит, что чисто «догоняющая» стратегия (нашли — поправили) со временем работает всё хуже.

Что обсуждали как направление: переход к подходу shift-left — сдвигать проверки безопасности максимально близко к началу pipeline, чтобы находки попадали в спринт сразу, а не копились в техдолге. Конкретный механизм пока не зафиксирован, но прозвучала идея автоматического заведения задач в трекер при обнаружении уязвимости выше определённого уровня — с привязкой к спринту команды, а не просто переноса задачи в беклог с решением её «когда-нибудь».

Здесь та же механика, что и в истории со стабильными релизами выше: исправление CVE в базовом образе — это не точечный патч, а пересборка всего, что от этого образа зависит. Раз стабильный релиз фиксирует версии на квартал, любая найденная за это время уязвимость в базовом слое автоматически становится отложенной — закрыть её раньше следующего среза архитектурно тяжело. То есть проблема безопасности по умолчанию и проблема релизного цикла — не два отдельных пункта, а одно и то же узкое место, развёрнутое с разных сторон.

Куда движемся

Из roadmap на первое полугодие 2026:

  • Автоматизация управления доставкой обновлений в канареечном режиме (progressive delivery) — постепенный, контролируемый по этапам деплой с критериями качества на каждом шаге, настраиваемый через бизнес-процесс, а не жёстко закодированный.

  • Расширение каталога ИТ-компонентов на тип «Система хранения данных» — Nexus, GitLab, NextCloud, файловые шары и аналоги, чтобы они становились управляемыми сущностями конфигурации так же, как сейчас управляются Kubernetes-кластеры и СУБД.

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

  • Продолжение работы над безопасностью по умолчанию — без точной даты, но с прозрачным признанием, что текущая модель «по запросу» должна сдвигаться к более строгой по умолчанию.

Что в итоге

Конвейер на 2000+ развёртываний в день и сотни команд — это проверенная история, а не просто цифра. Но честный технический разбор всегда выявляет места, где красивая архитектура сталкивается с реальностью: релизный цикл стоит ресурсов, безопасность стоит ресурсов, развязка монолита под разных заказчиков стоит ресурсов. Сейчас мы в процессе балансировки этих компромиссов.

Если у вас есть похожий опыт построения внутреннего DevOps-конвейера на таком масштабе — будет интересно обсудить в комментариях.

ссылка на оригинал статьи https://habr.com/ru/articles/1056910/