Чеклист миграции Jenkins на GitHub Actions или GitLab CI
Используйте этот чеклист миграции Jenkins, чтобы провести аудит задач, убрать плагинную задолженность, привести в порядок секреты, выбрать целевой CI и отслеживать результаты после переключения.

Почему Jenkins становится трудно поддерживать
Jenkins обычно портится не сразу, а понемногу. Команда добавляет ещё одну задачу, ещё один плагин, ещё один общий агент, и сначала кажется, что всё в порядке. Потом одно небольшое изменение ломает сборку, которую никто не помнит, кто создал, и никто не знает, кто за неё отвечает.
Потеря владельца — это часто первая серьёзная проблема. Старые задачи остаются, когда продукты меняются, команды переносятся или люди уходят. Некоторые всё ещё запускаются каждый день. Другие просыпаются только во время релиза или после перезагрузки сервера. Когда вы просматриваете их позже, видите имена вроде «build-test-2» или «release-old» и нет ясного ответа, нужны они ещё или нет.
Общие агенты усугубляют ситуацию. Задача может проходить только потому, что на машине уже установлена нужная версия Java, остался пакет или в какой-то папке лежит кастомный скрипт. Jenkins прячет эти зависимости в агенте вместо того, чтобы описать их в файле пайплайна. При переносе в GitHub Actions или GitLab CI сборка падает, потому что реальная настройка никогда не была записана.
Плагины добавляют ещё одну проблему. Jenkins умеет почти всё, но многие настройки зависят от цепочки плагинов, добавленных за годы. Один перестал получать обновления. Другой стал вести себя иначе после апгрейда. Третий конфликтует с остальными. Задолженность по плагинам Jenkins — это не просто беспорядок. Она создаёт случайные на вид ошибки и отнимает часы работы.
Секреты тоже распространяются тихо. Учётные данные оказываются в глобальных настройках, в настройках задач, в конфигах нод, в shell-скриптах и в скопированных переменных окружения. Некоторые остаются активными задолго после того, как сервисный аккаунт должен был быть удалён. Очистка этого позже занимает время, и легко пропустить токен с доступом в продакшен.
Именно при миграции всё это всплывает одновременно. Команды хотят сравнить старый пайплайн с новым, но у Jenkins часто нет чистой отправной точки. Время сборки, частота сбоев, флаки-тесты и результаты деплоя могут храниться в разных местах или вовсе нигде. Без этого чеклист миграции превращается в гадание.
Начните с реального инвентаря
Чеклист миграции Jenkins развалится, если пропустить инвентарь. Нужен полный список того, что ещё запускается, кто от этого зависит и что сломается, если это исчезнет.
Начните с одной строки на пайплайн в таблице или простом документе. Включите и старые задачи. Некоторые выглядят неактивными, но всё ещё срабатывают в 2:00 по расписанию или их запускают вручную во время релиза.
Для каждой задачи зафиксируйте базовое: что её запускает, что на входе, что на выходе, кто владелец и как она ведёт себя. Это значит триггер, входы (ветки или секреты), выходы (артефакты или деплои), именованный владелец, среднее время выполнения, время в очереди и недавняя частота ошибок.
Этот шаг обычно открывает настоящий беспорядок. Один пайплайн может собрать приложение, опубликовать артефакт, отправить сообщение в Slack и перезапустить сервер через три плагина, которых никто не помнит. Другой может существовать только потому, что год назад один клиент попросил кастомный экспорт.
Пишите зависимости простым языком. Если задача тянет из другого репозитория, вызывает скрипт на билд-агенте или полагается на общую библиотеку — запишите это сейчас. Эти скрытые связи создают большинство задержек при миграции, потому что Jenkins делает их легко пропускаемыми.
Владение важно сильнее, чем команды ожидают. Если никто не может ответить «Нужно ли это ещё?» — задача уже риск. Пометьте такие пайплайны явно. Их часто лучше отправить в архив, чем мигрировать.
Числа помогают рассортировать работу. Пайплайн, который запускается 40 раз в день с 15% отказов, должен идти раньше, чем ежемесячная архивная задача, которая занимает три минуты. Время в очереди тоже важно. Если задачи ждут 20 минут агента, новая система должна решить эту проблему.
Простой пример делает инвентарь полезнее. Если ваш релиз-пайплайн каждую пятницу собирает Docker-образ, пушит его в реестр и деплоит в продакшен, запишите все три результата, триггер, владельца и обычное время выполнения. Одна такая строка скажет гораздо больше, чем имя задачи.
Выбирайте целевой CI, опираясь на репозитории и approvals
Исходите из того, где хранится код, а не из таблицы возможностей. Если основной код уже в GitHub, GitHub Actions обычно означает меньше работы, потому что триггеры, pull request'ы и права уже рядом с кодом. Если команда использует GitLab для репозиториев, merge request'ов и релизов, GitLab CI часто будет более естественным выбором.
Раннеры важнее, чем думают многие. Хост-раннеры подходят для многих сборок и тестов, но у многих Jenkins-команд сборка Docker-образов, доступ в приватные сети или зависимость от кастомных инструментов. В таком случае рано проверьте self-hosted раннеры. Решите, где они будут работать, кто их будет патчить, как они будут кэшировать зависимости и как безопасно добираться до внутренних систем.
Поток approvals может решить выбор инструмента до остального. Посмотрите на защиту веток, правила слияний, обязательные ревью и подтверждения для деплоя. Система CI должна соответствовать процессу, который команда уже использует. Пересобирать всё это в ходе миграции рискованнее, чем многие думают.
Секреты требуют такого же пристального взгляда. Jenkins часто хранит годы старых токенов, общих паролей и учётных записей, до которых никто не хочет прикасаться. И GitHub Actions, и GitLab CI умеют управлять секретами, но модели разные. GitHub использует секреты на уровне репозитория, организации и окружения. GitLab — на уровнях проекта, группы и инстанса. Выберите модель, которая соответствует тому, как команды уже делятся доступом.
Быстрая оценка помогает. Сравните варианты по вашей ежедневной реальности: где лежит код, сколько задач нуждаются в доступе в приватную сеть, как работают approvals деплоя и кто будет владеть раннерами и общими секретами.
Команда, которая держит код в GitHub, ревьюит pull request'ы там и деплоит веб‑приложение с несколькими Docker-сервисами, обычно быстрее добьётся результата с GitHub Actions. Команда, которая держит GitLab у себя на серверах, использует approvals в merge request'ах и запускает сборки внутри приватной сети, скорее найдёт GitLab CI более естественным.
Не разбивайте первую волну миграции на оба инструмента. Выберите одну цель, перенесите небольшой набор репрезентативных задач и учитесь на реальных запусках. Смешанная цель выглядит гибко, но удваивает настройку раннеров, шаблонов, обучение и поддержку.
Сопоставьте каждую Jenkins‑задачу с видимым пайплайном
Выберите сервис, падение которого не разрушит рабочую неделю команды. Малое API, внутренний инструмент или приложение только для staging — лучшая первая цель, чем основной продукт.
Прежде чем писать YAML, перепишите Jenkins‑задачу простыми словами. На время забудьте термины Jenkins и опишите, что задача реально делает: забирает код, устанавливает зависимости, запускает unit-тесты, собирает Docker-образ, пушит в реестр, деплоит в staging и отсылает уведомление, если деплой не удался.
Это простое переписывание обнажает скрытые шаги. Многие Jenkins-задачи в UI выглядят короткими, но реальная работа лежит в shell-скриптах, общих библиотеках, настройках плагинов и старых post-build actions.
Разбейте поток на явные стадии. Большинству команд нужны как минимум build, test и deploy как отдельные блоки. Когда одна стадия падает, вы должны быстро это увидеть. И вы должны иметь возможность повторно запустить только упавшую часть, когда новая CI-платформа это позволяет.
Чистое сопоставление отвечает на четыре вопроса:
- Что запускает пайплайн
- Что нужно каждой стадии
- Что производит каждая стадия
- Как выглядит успех
Заменяйте функции, завязанные только на Jenkins, по очереди. Если плагин инжектит номера версий — вынесите логику в скрипт. Если плагин шлёт уведомления в чат — используйте нативную интеграцию в GitHub Actions или GitLab CI. Если общая библиотека скрывает половину логики деплоя — сначала вынесите её в видимый скрипт. Скрытое поведение обычно ломает миграцию.
Определите, что такое успешный запуск, прежде чем сравнивать старое и новое. Будьте конкретны. Пайплайн должен успешно завершаться в основной ветке, результаты тестов должны совпадать с Jenkins, digest образа должен публиковаться, staging должен деплоиться, а команда должна читать логи без перехода через пять экранов.
Сделайте это один раз для низкорискового сервиса — следующие десять задач пойдут легче.
Срежьте плагинную задолженность до переноса
Начните с экспорта полного списка плагинов из Jenkins. Рассматривайте плагины как риск, а не как фон. Многие команды думают, что у них 20 плагинов, а находят 80 и только несколько из них кто-то может объяснить.
Поставьте этот список рядом с инвентарём задач и отметьте, какие именно задачи зависят от каждого плагина. Делайте это по имени, а не по памяти. Если плагин влияет только на одну nightly‑задачу и ни на что другое — это важно. Если пять человек дают пять разных ответов о том, что делает плагин — считайте это тревожным знаком.
Достаточно простой системы меток: активно используется, используется только устаревшими задачами, неясен владелец или назначение, и, вероятно, можно удалить после тестирования.
Обычно самая большая группа — «грязная середина». Старые установки Jenkins собирают плагины для уведомлений в чат, копирования артефактов, Git‑тегирования, форм параметров, Docker‑шагов, обработки секретов и форматирования отчётов. Спустя годы никто не помнит, какой плагин решал реальную проблему, а какой был одноразовым решением.
Удаляйте плагины, которые никто не может объяснить. Звучит резко, но загадочные зависимости хуже. Если у плагина нет владельца, нет активных задач и нет понятной причины для существования — удалите его в тестовой среде и посмотрите, что сломается. Часто ничего важного.
Мелкие задачи плагинов обычно превращаются в проще читаемый код пайплайна. Обёртка, которая переименовывала артефакты, шлёт вебхук или копирует файлы между папками, может стать коротким скриптом или нативным шагом CI. Это делает новый пайплайн легче читать и проще переносить снова, если нужно будет сменить систему.
Не копируйте привычки Jenkins в GitHub Actions или GitLab CI. Если в Jenkins нужно было три плагина и freestyle‑job для запуска тестов — это не значит, что новую систему нужно имитировать. Используйте новую систему так, как она задумана.
Хороший результат — проще: меньше движущихся частей, меньше сюрпризов и пайплайн, который новый инженер сможет прочитать, не заглядывая сначала в менеджер плагинов.
Приведите в порядок учётные данные и доступы
Старые CI‑системы собирают секреты так же, как гараж собирает запасные кабели. Jenkins может хранить их в глобальном хранилище, настройках папок, конфигурациях нод, shell‑скриптах и даже в коде в старых репозиториях.
Рассматривайте этот шаг как очистку, а не копирование. Если перенести каждый токен и пароль как есть, вы перетянете старые риски в новую систему.
Начните с единой таблицы инвентаря. Включите каждый API‑токен, SSH‑ключ, пароль, сертификат подписи и креды для деплоя. Для каждого запишите, где он сейчас, какая задача его использует, кто владелец, к чему даёт доступ и когда его последний раз использовали.
Это обычно открывает много мусора. Можно найти три Docker‑токена для одного и того же приложения, облачный ключ, которым пользуются пять задач, или production SSH‑ключ, который никто не хочет признавать автором.
Группируйте секреты по принадлежности, а не по Jenkins‑задаче, которая случайно их использовала. На практике это означает организовать их вокруг имени приложения или сервиса, окружения (dev/prod), назначения секрета и человека‑ответственного.
Такая структура упрощает перенос в GitHub Actions или GitLab CI. Вы сможете поместить секреты на уровне репозитория, проекта, группы или окружения, вместо того чтобы сваливать всё в один общий бакет.
Удаляйте всё, что привязано к выведенным из использования задачам, до миграции. Самый лёгкий секрет для управления — тот, которого у вас больше нет.
При воссоздании секретов в новой системе ужесточьте доступ. Токен для staging не должен иметь доступ в продакшен. Билд‑задача не должна получать полный облачный админ‑доступ только потому, что в Jenkins использовали один широкий учет.
После cutover первым делом поменяйте критичные креды: облачные ключи, реестры пакетов, ключи подписи и токены деплоя в продакшен. Затем убедитесь, что старые Jenkins‑секреты больше не работают. Если они всё ещё действуют — очистка не завершена.
Запустите пилот параллельно
Начните с одного сервиса, который делает реальную работу каждый день. Выберите то, что собирается, запускает тесты и деплоит в staging, но оставьте продакшен пока в стороне. Малое API или веб‑приложение обычно лучше пилота, чем большой монолит или крошевый cron.
Сначала перенесите шаги сборки и тестов. Их легче сравнивать, и они быстро выявляют проблемы. Если новый пайплайн не может собрать приложение так же, как Jenkins, добавление шагов деплоя только скроет реальную проблему.
Простой пилот работает так: собрать приложение, запустить unit‑тесты, упаковать артефакт и деплоить в staging. Держите staging‑деплой узким. Вам нужен достаточный охват, чтобы поймать различия в раннерах, кэшах, секретах и артефактах, но без риска для клиентов.
Запускайте новый пайплайн параллельно с Jenkins несколько дней. По возможности триггерьте оба с одних и тех же коммитов. Затем сравните, что делает каждая система, а не только финальный статус «успех».
Проверяйте одни и те же вещи каждый день: время сборки, общее время пайплайна, результаты тестов, флаки‑сбои, качество логов, выход артефактов, поведение staging‑деплоя и как работают повторы после упавшего шага.
Держите продакшен в Jenkins, пока пилот не станет стабильным. Обычно нужно несколько дней нормальных коммитов, без загадочных сбоев и без ручного вмешательства после каждого запуска. Если команде приходится присматривать за новым пайплайном — он ещё не готов.
Завершите пилот явным решением «проход/непроход». Задайте простые правила. Новый пайплайн должен совпадать с Jenkins по выходу сборки, держать частоту ошибок близкой и укладываться в приемлемый диапазон по времени. Если Jenkins заканчивает за 12 минут, а новый пайплайн 40 — это разрыв, который нужно изучить до переноса следующего сервиса.
Хороший пилот становится шаблоном. Вторая миграция должна идти быстрее, а не казаться стартом с нуля.
Ошибки, которые замедляют миграцию
Самый быстрый способ затянуть перенос Jenkins — относиться к нему как к задаче «скопировать и вставить». Команды часто конвертируют каждый пайплайн в новый синтаксис и надеются, что новая система будет вести себя лучше. Обычно нет.
Перенос всего одновременно создаёт шум, а не прогресс. Если 40 задач падают в новой платформе, никто не поймёт, какие ошибки связаны с миграцией, а какие уже были в Jenkins. Меньшая партия даёт более чистую обратную связь.
Ещё одна распространённая ошибка — копировать сломанные шаги в новый YAML. Jenkins‑задачи часто несут годы shell‑команд, старых костылей и половинчатых флагов. Если шаг теста флакирует три раза в неделю сейчас, он будет флакировать и после миграции. Используйте перенос, чтобы убрать мёртвые ветви, а не сохранить их.
Команды также замедляют себя, когда прячут слишком много логики в общих скриптах. Немного повторного использования помогает. Слишком много превращает каждый пайплайн в головоломку, где одно изменение в центральном скрипте ломает десять проектов. Делайте общие части маленькими и очевидными. Проект‑специфичную логику держите там, где её легко прочесть.
Затраты упускают чаще, чем команды признаются. Минуты раннеров, обслуживание self-hosted раннеров, размер кэша, артефакты и хранение в контейнерных реестрах быстро складываются. Пайплайн, который в Jenkins казался дешёвым, потому что его никто не измерял, может обойтись в реальные деньги в GitHub Actions или GitLab CI.
Очистка учётных данных — ещё одно место, где команды идут по-ленивому. Они переносят секреты в новую систему, но старые Jenkins‑учётки остаются активными месяцами. Это создаёт две проблемы: больше мест для защиты и больше шансов, что старый токен забудут.
Простое правило помогает: мигрируйте одну группу задач, наблюдайте неделю‑две, затем переходите к следующей. Отслеживайте время сборки, частоту ошибок, время в очереди и месячные затраты. Если числа не улучшаются — остановитесь и поправьте дизайн до дальнейшего переноса.
Именно на этом этапе внешний взгляд часто экономит время. Тот, кто уже резал плагинную задолженность, уменьшал спред инфраструктуры и перестраивал CI вокруг простых правил, обычно заметит слабые места раньше, чем они превратятся в грязный cutover.
Проверки перед cutover
Cutoverы обычно падают по простым причинам. Рабочий процесс использует не тот секрет, никто не владеет сломанной задачей или логи слишком туманные, чтобы показать, что реально сломалось.
Сделайте короткий обзор для каждой мигрированной задачи. Будьте конкретными. Если кто‑то в команде не может ответить, кто владеет workflow, где живут его секреты и как откатить — вы ещё не готовы переключаться.
Возьмём release‑пайплайн как пример. Если он собирает приложение, прогоняет тесты, тегирует версию и деплоит в staging, то один инженер должен быть владельцем, один утверждённый стор должен хранить все токены, и одна заметка по откату должна объяснять, как вернуть релиз обратно в Jenkins, если новый запуск неудачен.
Короткий пред‑cutover чеклист обычно достаточен:
- У каждой мигрированной задачи есть именованный владелец.
- Каждый секрет хранится в одном утверждённом месте.
- Шаги отката умещаются на одной странице и сказано, кто принимает решение.
- Логи показывают упавший шаг, текст ошибки и длительность задачи.
- Команда знает, кто смотрит за первым cutover и сколько времени.
Логирование важнее, чем команды ожидают. Если новый пайплайн просто пишет «failed» без указания, пришла ли ошибка при checkout, настройке тестов, сборке пакетов или деплое, вы теряете время сразу.
Также проверьте время. Пайплайн, который работает, но занимает вдвое дольше, чем задача Jenkins, вызовет тихое сопротивление команды.
Держите первый cutover достаточно маленьким, чтобы люди могли за ним следить. Поставьте одного человека на пайплайн, одного на приложение или сервис и одного на утверждение отката. Никто не должен гадать, кто наблюдает.
Измеряйте результаты перед следующей волной
Миграция считается успешной, только если новый пайплайн спокойнее и проще в управлении, чем Jenkins. Сравнивайте пилот с старой системой по одному и тому же набору задач, а не по счастливой неделе. Если старая задача падала 12% времени, а новая 4% — это реальный выигрыш. Если сборки стали быстрее, но люди всё ещё правят деплой вручную, перенос не завершён.
Что отслеживать
Отслеживайте небольшой набор показателей, которые команда может просматривать каждую неделю: процент неудач до и после переноса, среднее полное время пайплайна, время в очереди до старта, как часто нужен ручной фикс или повторный запуск, и сколько вопросов поддержки создаёт новый workflow.
Держите заметки простыми. Достаточна короткая таблица: что упало, кто исправил и сколько это заняло. Через две‑три недели паттерны обычно очевидны. Многие команды обнаруживают, что сам пайплайн в порядке, но секреты окружения или флаки‑данные тестов ещё создают большую часть шума.
Когда пилот стабилен, сразу чистите Jenkins. Выключайте неиспользуемые агенты, архивируйте ненужные задачи и убирайте старые расписания, которые ещё запускают работу в фоне. Это быстро снижает расходы и путаницу. Также уменьшается шанс, что кто‑то будет продолжать деплоить из старой системы по привычке.
Не спешите со второй волной после первого зелёного запуска. Подождите, пока пилот выдержит обычный трафик команды, срочные фиксы и хотя бы один цикл релиза. Стабильность в течение дня — мало что значит. Стабильность в течение нескольких недель — сигнал, что шаблон можно повторять с меньшим количеством сюрпризов.
Если числа смешанные — приостанавливайте и пересматривайте план. Иногда короткий внешний аудит достаточно, чтобы заметить плохую настройку раннеров, запутанную модель доступа или дорогостоящую конструкцию пайплайна до того, как эти проблемы распространятся. Oleg Sotnikov at oleg.is занимается такими задачами по очистке CI и инфраструктуры в рамках Fractional CTO и стартап‑консалтинга, так что второе мнение может быть дешевле, чем миграция тех же ошибок дважды.
Часто задаваемые вопросы
Как понять, стоит ли мигрировать Jenkins-задачу или просто удалить её?
Уберите задачу, если никто не назовет владельца, не объяснит, зачем она всё ещё запускается, или не покажет, что сломается при её отключении. Мигрируйте, если задача продолжает собирать, тестировать, пакетировать или деплоить то, чем команда активно пользуется.
Что нужно положить в реестр Jenkins-задач?
Зафиксируйте триггер, входы, выходы, владельца, среднее время выполнения, время в очереди, недавние ошибки и все внешние зависимости. Укажите скрипты на агентах, общие библиотеки, реестры, уведомления в чат и цели деплоя, чтобы не обнаруживать их в середине миграции.
С чего начать: GitHub Actions или GitLab CI?
Выберите инструмент, который соответствует тому, где лежит код и где идут approvals. Если команда каждый день работает в GitHub, GitHub Actions обычно даёт меньше трения. Если репозитории, проверки слияний и раннеры уже в GitLab — GitLab CI будет естественнее.
Почему общие агенты Jenkins так часто приводят к неожиданностям?
Shared-агенты скрывают настройки, которые не попали в код. Задача может проходить только потому, что на машине стоит нужная версия Java, оставшийся пакет или кастомный скрипт в папке. Перенесите эти настройки в видимые шаги пайплайна или скрипты до миграции.
Что делать со старыми плагинами Jenkins до миграции?
Экспортируйте список плагинов и сопоставьте каждый плагин с задачами, которые его используют. Удаляйте плагины без владельца и явной цели сначала в тестовой среде, затем заменяйте мелкие задачи плагинов скриптами или нативными возможностями CI.
Как обращаться с учётными данными при миграции?
Не переносите секреты без ревью. Составьте один реестр всех токенов, SSH-ключей, паролей и сертификатов, сгруппируйте их по приложению и окружению, удалите те, что относятся к устаревшим задачам, и создайте заново только нужные с более строгими правами.
Можно ли переводить деплои в продакшен в первый же день?
Нет — начните со сборки и тестов, затем добавьте деплой в staging. Оставляйте продакшен в Jenkins, пока новый пайплайн стабильно не отрабатывает несколько дней, не совпадает по результату и не перестанет требовать ручных починок после каждого запуска.
Каким должен быть первый пилотный пайплайн?
Выберите сервис, который делает реальную работу, но не испортит неделю при сбое. Хороший пилот собирает приложение, выполняет тесты, создаёт артефакт и деплоит в staging — этого достаточно, чтобы сравнить скорость, логи, секреты, кэши и поведение при повторах с Jenkins.
Как измерить, стал ли новый CI действительно лучше?
Отслеживайте процент неудач, полное время пайплайна, время в очереди, количество ручных фиксов и результат деплоев в течение нескольких недель. Если в новом CI меньше сбоев, всё стартует быстрее и требуется меньше ухода — это реальное улучшение.
Когда имеет смысл просить помощи у внешнего эксперта?
Привлекайте внешних специалистов, когда реестр показывает рост плагинов, загадочные задачи, запутанные секреты или медленные self-hosted раннеры. Короткий аудит часто выявляет слабые места в дизайне раннеров, доступах и дорогих решениях ещё до того, как вы повторите ошибки на всех репозиториях.