Почему jenkins webhook победил, а pollSCM устаревает
Исторически Jenkins умел узнавать о новых коммитах одним способом - опросом. Это режим pollSCM: Jenkins по таймеру лезет в репозиторий и спрашивает "ну что, изменилось что-нибудь?". Если изменилось - запускает сборку, если нет - ждёт следующего тика. Работает, но представь сотню джоб, каждая дёргает git раз в минуту. Это лишний трафик, лишняя нагрузка на контроллер и на сам git-сервер, и при этом задержка: запушил в 10:00:10, а опрос был в 10:00:00, значит ждёшь почти минуту до старта.
Современный подход переворачивает логику. Не Jenkins спрашивает GitHub, а GitHub сам стучится в Jenkins, как только произошёл push. Это и есть jenkins webhook: GitHub отправляет HTTP POST на специальный URL твоего Jenkins, тот понимает, какой репозиторий обновился, и запускает связанные джобы. Никакого опроса, никакой задержки, нулевой холостой трафик. Сборка стартует через секунду после пуша.
В декларативном конвейере оба способа задаются в блоке triggers. Вот как выглядит современный jenkins trigger по пушу из GitHub:Правило 2026: webhook - выбор по умолчанию для всех проектов, которые видят твой Jenkins из интернета или из внутренней сети с доступом до контроллера. pollSCM оставляй только там, где webhook физически не настроить - например, Jenkins за NAT без публичного адреса и без прокси.
Код: Выделить всё
pipeline {
agent any
triggers {
// Запуск по webhook от GitHub: GitHub сам уведомляет Jenkins
githubPush()
}
stages {
stage('Build') {
steps {
sh 'make build'
}
}
stage('Test') {
steps {
sh 'make test'
}
}
}
}
Код: Выделить всё
pipeline {
agent any
triggers {
// Устаревающий способ: Jenkins сам опрашивает репозиторий
pollSCM('H/5 * * * *')
}
stages {
stage('Build') {
steps { sh 'make build' }
}
}
}

Настройка github webhook: со стороны GitHub и со стороны Jenkins
Чтобы jenkins github webhook заработал, нужно свести две стороны. Начнём с GitHub. Заходишь в репозиторий, Settings -> Webhooks -> Add webhook. Заполняешь:
- Payload URL - адрес твоего Jenkins с хвостом /github-webhook/. Например http://jenkins.cyberlake.ru/github-webhook/. Слэш на конце обязателен, без него прилетит 404.
- Content type - выбирай application/json.
- Secret - произвольная секретная строка. GitHub подпишет ей запрос, а Jenkins проверит подпись и отбросит чужие POST-ы. Не пропускай этот шаг на проде.
- Which events - для большинства задач хватает "Just the push event". Если нужны сборки по pull request, добавь соответствующие события.
Если у тебя GitLab, логика та же самая, меняется только плагин (GitLab Plugin) и директива триггера - gitlabPush() или generic webhook. Суть одна: внешняя система пушит событие, Jenkins ловит.
В духе 2026 эти настройки удобно держать не кликами в UI, а в коде через Configuration as Code (JCasC). Тогда новый Jenkins поднимается с уже прописанными кредами и эндпоинтами. Кусок jenkins.yaml для GitHub-сервера выглядит так:
Код: Выделить всё
unclassified:
gitHubPluginConfig:
configs:
- name: "cyberlake-github"
apiUrl: "https://api.github.com"
manageHooks: true
credentialsId: "github-token"
Не всё запускается по пушу. Ночные прогоны тяжёлых тестов, еженедельная пересборка образов, регулярная очистка - это работа по расписанию. Jenkins использует cron-синтаксис из пяти полей: минута, час, день месяца, месяц, день недели.
Код: Выделить всё
pipeline {
agent any
triggers {
// Каждую ночь между 2:00 и 2:59 - точную минуту выберет Jenkins
cron('H 2 * * *')
}
stages {
stage('Nightly') {
steps { sh './run-nightly-suite.sh' }
}
}
}
Отдельный класс - сборка после других проектов. Если проект B должен собираться только после успешной сборки проекта A (upstream/downstream), это задаётся триггером upstream:
Код: Выделить всё
triggers {
// Запуск после успешного завершения сборки проекта A
upstream(upstreamProjects: 'project-a', threshold: hudson.model.Result.SUCCESS)
}
И ещё два инструмента. Первый - запуск по удалённому вызову. В настройках джобы включаешь "Trigger builds remotely" и задаёшь токен. После этого сборку дёргает простой curl, что удобно для интеграции со сторонними системами:
Код: Выделить всё
curl -X POST "https://jenkins.cyberlake.ru/job/my-job/build?token=MY_SECRET_TOKEN"
Код: Выделить всё
pipeline {
agent any
options {
quietPeriod(30) // ждать 30 секунд после триггера
}
triggers { githubPush() }
stages {
stage('Build') { steps { sh 'make' } }
}
}
Типичные грабли
- githubPush() не срабатывает, а джоба ни разу не запускалась руками. Запусти один раз вручную, чтобы Jenkins прочитал блок triggers.
- Забыл слэш в Payload URL. Нужно ровно /github-webhook/, иначе GitHub получает 404. Проверь во вкладке Recent Deliveries на стороне GitHub - там виден код ответа.
- Jenkins за NAT, GitHub не достучаться. Либо публичный адрес/реверс-прокси, либо как временное решение - ngrok для теста, либо честно остаёшься на pollSCM.
- Все ночные джобы в 0 минут. Меняй на H - размажешь пик нагрузки.
- Поставил и webhook, и pollSCM "на всякий случай". Не надо: получишь двойные сборки и лишний опрос. Выбери один способ.
- Создай Pipeline-джобу из своего GitHub-репозитория с githubPush() в Jenkinsfile и запусти её один раз руками.
- Настрой webhook на стороне GitHub (Payload URL с /github-webhook/, secret, push event). Сделай коммит и убедись, что сборка стартовала сама.
- Открой Recent Deliveries на GitHub и посмотри код ответа на доставку хука.
- Добавь вторую джобу с cron('H 3 * * *') и сравни, на какую минуту Jenkins её поставил.
- Свяжи две джобы через upstream и проверь, что вторая стартует после первой.
- Чем webhook принципиально отличается от pollSCM и почему первый предпочтительнее в 2026?
- Что нужно указать в Payload URL на стороне GitHub и почему важен слэш на конце?
- Зачем нужен символ H в cron-строке и чем он лучше явной минуты?
- Что делает quiet period и в какой ситуации он экономит сборки?
Автоматический запуск - это сердце CI. Запомни главное: webhook от GitHub или GitLab толкает сборку мгновенно по пушу и не грузит систему холостым опросом - это стандарт по умолчанию. pollSCM остаётся аварийным вариантом для сетей, где webhook не настроить. Cron с символом H закрывает регулярные задачи без пиков нагрузки, upstream строит цепочки джоб, токен даёт внешний запуск, а quiet period склеивает пачку пушей в одну сборку. Настрой это один раз правильно - и забудешь про кнопку "Build Now" навсегда.