Jenkins добре послужив. Але 22 репозиторії з 22 унікальними пайплайнами? Це не CI/CD. Це хаос із зеленою іконкою.

Намалюю картину. Двадцять два репозиторії. У кожного свій Jenkins-пайплайн. Кожен написаний іншим розробником в іншому році з іншим розумінням слова "деплоймент." В одних були тести. В інших були... наміри тестів. В одному був коментар "TODO: add tests" від 2021 року.

Кожен пайплайн — унікальна сніжинка. Красива в ізоляції. Кошмар у масштабі.

Коли патерн деплою треба змінити — скажімо, додати health check після деплою — хтось мав торкнути 22 файли. В 22 репозиторіях. З 22 трохи різними синтаксисами. І сподіватися, що розробник, який написав пайплайн #7 три роки тому, залишив достатньо коментарів.

Не залишив.

Чому Jenkins мав піти

Я не хейтер Jenkins. Jenkins — робоча конячка. Він запускав білди, коли половина індустрії не знала, що таке CI. Але Jenkins у 2025 році для команди, що мігрує на GitLab — це як їхати на коні автобаном. Технічно можливо. Практично болісно.

Реальні проблеми:

  • Немає нативної Git-інтеграції. Jenkins вважає код вхідними даними. GitLab вважає код контекстом. Пайплайни на merge request, деплоймент по гілках, трекінг environments — все нативно в GitLab, все плагіни в Jenkins.
  • Plugin hell. Кожна можливість Jenkins вимагає плагін. У кожного плагіна свій цикл оновлень, security advisory і матриця сумісності. Я бачив інстанси Jenkins з 80+ плагінами, де ніхто не знав, які реально потрібні.
  • Пайплайни-сніжинки. Без системи спільних шаблонів кожна команда будує пайплайн з нуля. Ті самі патерни, різні реалізації. Помножити на 22 репозиторії.

Архітектура шаблону

Я не писав 22 GitLab CI пайплайни. Я написав один.

Один enterprise-grade шаблон, який підключає кожен репозиторій. Одне джерело правди про те, як працюють білди, тести і деплої. Одне місце для фіксу бага — і всі 22 репозиторії отримують виправлення миттєво.

Шаблон обробляє:

Build stage: .NET, Node, Java — автовизначення за структурою проєкту. Один білд, артефакт скрізь. Той самий бінарник, що пройшов тести в DEV — іде в продакшн. Жодних "у мене працює."

Test stage: Юніт-тести з обов'язковим контролем покриття. Не "в нас є тести." А "якщо покриття впало нижче порогу, пайплайн помирає." Бо опціональні тести — це ніякі тести.

Security gates: Сканування залежностей, виявлення секретів, SAST. Зашито в шаблон, не opt-in. Ти не обираєш, чи сканується твій код. Він сканується.

Deployment stage: Мультисередовищна прогресія — DEV, UAT, PROD — з обов'язковою валідацією на кожному гейті. Пропустити в продакшн не можна. Фізично не можна. Пайплайн примушує DEV → UAT → PROD. Завжди.

Zero-downtime slots: Продакшн-деплої використовують deployment slots Azure App Service. Деплой у staging slot, валідація, свап. Якщо щось ламається — свап назад. Без даунтайму. Без молитов.

Патерн міграції

Мігрувати 22 репозиторії — це не "скопіювати Jenkinsfile в .gitlab-ci.yml." Це системний процес:

  1. Аудит Jenkins-пайплайну кожного репозиторію. Зрозуміти, що він реально робить, а не що хтось думає. Часто це різні речі.

  2. Маппінг Jenkins-стадій на GitLab-стадії. Більшість транслюються напряму. Деякі розкривають, що Jenkins робив те, про що ніхто не знав. А деякі — що нічого корисного не робив взагалі.

  3. Заміна репо-специфічної логіки на include шаблону. .gitlab-ci.yml репозиторію стає 15 рядків: підключи шаблон, задай змінні, готово.

  4. Валідація — запуск обох пайплайнів паралельно на спринт. Порівняння результатів. Фікс розбіжностей.

  5. Переключення. Вимкнути Jenkins. Без поступового заходу. Чистий розрив.

Результат: 22 репозиторії, кожен з .gitlab-ci.yml коротшим за цей абзац. Усі вказують на один спільний шаблон. Усі деплояться однаково. Усі тестуються однаково. Усі захищаються однаково.

Аргумент про покриття

"Ми додамо тести потім."

Ні. Не додасте. "Потім" у розробці означає "ніколи." Я бачив це достатньо разів, щоб знати.

Шаблон примушує покриття тестами з першого дня. Не 100% — це vanity metric. Але осмислений поріг, що ловить регресії. Якщо merge request роняє покриття — він не мерджиться. Кінець дискусії.

Ось тут розробники чинять опір. "Але мій сервіс інший." "Але ми поспішаємо." "Але тести flaky."

Твій сервіс слідує тому ж патерну деплою, що й 21 інший. Ти завжди поспішаєш. А flaky тести — це баг, а не відмазка.

Shared Scripts через Package Registry

Ось трюк, що зекономив тижні: PowerShell-скрипти деплою, збережені в GitLab Package Registry.

Замість копіювання скриптів у кожен репозиторій, шаблон забирає останню версію з реджістрі в рантаймі. Оновив скрипт один раз, опублікував — і кожен пайплайн підхопить при наступному запуску.

Фіксація версій доступна для команд, яким потрібна стабільність. Але дефолт — завжди "latest." Бо спільні скрипти мають розвиватися з платформою, а не стагнувати в чийомусь форку.

Що змінилося

До: 22 сніжинки. Без стандарту. Без примусу. "Деплоймент" означав різне в кожному репозиторії.

Після: Один шаблон. Обов'язкове тестування. Обов'язкове сканування безпеки. Обов'язкова прогресія середовищ. Zero-downtime продакшн-деплої.

Команди чинили опір спочатку. Зміни — це некомфортно. Але після першого продакшн-деплою без жодного ручного кроку — білд, тест, скан, деплой DEV, валідація, деплой UAT, валідація, ручний апрув, деплой PROD, валідація — все в одному запуску пайплайну... опір випарувався.

Бо ніхто не сумує за Jenkins, коли нова система просто працює.

22 репозиторії. Один пайплайн. Нуль сніжинок. 100% контроль покриття.

Це не міграція. Це апгрейд.