В этом уроке разберём, как настроить и подключить shared library: глобальная регистрация через Manage Jenkins, аннотация @Library, неявная (implicit) и динамическая загрузка, версионирование для стабильности и разница между доверенными и недоверенными библиотеками. По состоянию на 2026 год это базовый навык: актуальная Jenkins LTS - линейка 2.541.x (Java 17 как минимум, а weekly-ветка уже требует Java 21), и shared library остаётся штатным способом не дублировать код пайплайна между проектами.
Как устроена jenkins library внутри
Общая библиотека - это просто Git-репозиторий с тремя каталогами, и Jenkins ожидает именно такую структуру:
Код: Выделить всё
(корень репозитория)
vars/
deployApp.groovy # глобальная переменная-шаг: deployApp(...)
notifySlack.groovy
src/
org/cyberlake/Build.groovy # обычные Groovy-классы, как Java
resources/
org/cyberlake/deploy.yaml # статические файлы, libraryResource
Код: Выделить всё
// vars/notifySlack.groovy
def call(String message, String color = 'good') {
echo "Slack [${color}]: ${message}"
// тут реальная отправка через slackSend или curl
}

Глобальная настройка: jenkins global library из Git
Чтобы пайплайны видели библиотеку, её надо зарегистрировать. Идёшь в Manage Jenkins -> System и ищешь раздел Global Trusted Pipeline Libraries (в старых сборках он назывался Global Pipeline Libraries). Тут jenkins global library привязывается к источнику:
- Name - имя, по которому будешь звать: например cyberlake-pipeline
- Default version - ветка, тег или коммит по умолчанию: main, v2.3.0 или хеш
- Load implicitly - подгружать ли библиотеку во все пайплайны автоматически
- Allow default version to be overridden - можно ли в Jenkinsfile попросить другую версию
- Retrieval method - Modern SCM, источник Git с URL и credentials
Код: Выделить всё
unclassified:
globalLibraries:
libraries:
- name: "cyberlake-pipeline"
defaultVersion: "main"
implicit: false
allowVersionOverride: true
retriever:
modernSCM:
scm:
git:
remote: "https://git.cyberlake.ru/devops/jenkins-lib.git"
credentialsId: "git-readonly"
jenkins @library: подключение в Jenkinsfile
Самый частый способ - аннотация. Тут важная тонкость: jenkins @library стоит ДО строки с pipeline и обязательно сопровождается импортом (хотя бы фиктивным _), иначе Groovy выкинет аннотацию как мусор.
Код: Выделить всё
@Library('cyberlake-pipeline@v2.3.0') _
pipeline {
agent any
stages {
stage('Notify') {
steps {
notifySlack('Сборка стартовала')
}
}
stage('Deploy') {
steps {
script {
def b = new org.cyberlake.Build(this)
b.deploy('staging')
}
}
}
}
}
- @cyberlake-pipeline@main - ветка. Живёт и меняется, удобно для разработки, опасно для прода
- @cyberlake-pipeline@v2.3.0 - тег. Иммутабельный, рекомендованный для продакшена
- @cyberlake-pipeline@a1b2c3d - конкретный коммит. Максимальная фиксация, но неудобно читать
Динамическая загрузка через шаг library
Аннотация резолвится ДО запуска пайплайна, поэтому имя и версию в ней нельзя вычислить на лету. Когда версия зависит от параметров сборки или ветки, используют шаг library - это и есть jenkins загрузка библиотеки в рантайме:
Код: Выделить всё
pipeline {
agent any
parameters {
string(name: 'LIB_VERSION', defaultValue: 'main', description: 'Версия библиотеки')
}
stages {
stage('Load & run') {
steps {
script {
def lib = library("cyberlake-pipeline@${params.LIB_VERSION}")
// классы из src доступны через возвращённый объект
lib.org.cyberlake.Build.new(this).deploy('prod')
// а шаги из vars - просто по имени
notifySlack('Deploy завершён')
}
}
}
}
}
Отдельный приём - подтянуть код из произвольного SCM, не регистрируя библиотеку глобально. Полезно для разовых экспериментов:
Код: Выделить всё
library identifier: 'adhoc@main', retriever: modernSCM([
$class: 'GitSCMSource',
remote: 'https://git.cyberlake.ru/devops/jenkins-lib.git',
credentialsId: 'git-readonly'
])
Тут кроется главная путаница новичков. Библиотека, объявленная глобально в Manage Jenkins (Global Trusted Pipeline Libraries), - доверенная. Её код выполняется БЕЗ песочницы Groovy, ему можно всё: лезть в Jenkins API, в файловую систему контроллера, дёргать любые методы Java. Поэтому право менять её репозиторий надо держать в узких руках - это фактически root-доступ к контроллеру.
А вот библиотеки, заданные на уровне папки (Folder-level, в настройках конкретного folder), - всегда недоверенные. Их код крутится в Groovy Sandbox: разрешён только белый список безопасных методов, и любой шаг в сторону требует ручного approval администратора через In-process Script Approval. Это сделано специально: команды могут подключать свои библиотеки, не получая ключи от всего сервера.
Запомни правило: доверяй коду ровно настолько, насколько контролируешь, кто его меняет. Если в проде завязан implicit на ветку main доверенной библиотеки - один кривой коммит может сломать или скомпрометировать весь Jenkins.
Кстати, в GitLab CI и GitHub Actions та же задача переиспользования решается иначе: include в .gitlab-ci.yml и reusable workflows плюс composite actions в Marketplace. Идея общая - не копировать пайплайны, но shared library даёт полноценный Groovy-код, а не только декларативные включения.
Типичные грабли
- Забыл символ _ или import после @Library - аннотация молча игнорируется, шаги "не находятся". Лечится подчёркиванием в конце строки.
- Подключил библиотеку по ветке main и удивляешься, почему прод-сборки разные. Прибивай к тегу.
- Файл в vars назвал DeployApp.groovy, а зовёшь deployApp - имя шага чувствительно к регистру и совпадает с именем файла.
- Меняешь src-класс и не видишь эффекта - Jenkins кеширует, помогает чистый чекаут или смена версии. На общих переменных vars кеш мягче.
- Сложил секреты в resources - libraryResource их спокойно отдаст в лог. Секреты только через credentials.
Повтори руками:
- Создай Git-репозиторий с файлом vars/hello.groovy и методом call(String name), который пишет echo.
- Зарегистрируй его в Manage Jenkins -> System как jenkins global library с именем lab-lib и default version main, implicit выключен.
- Сделай пайплайн с @Library('lab-lib@main') _ и вызови hello('cyberlake').
- Поставь тег v1.0 в репозитории, переключи Jenkinsfile на @lab-lib@v1.0 и убедись, что изменения в main больше не влияют на сборку.
- Перепиши подключение через шаг library() в script-блоке с версией из параметра сборки.
- Чем отличается каталог vars от src в структуре общей библиотеки и как из них вызывать код?
- Почему после @Library нужен символ _ или import, и что будет, если его не поставить?
- В каком случае выбирают шаг library вместо аннотации @Library?
- Почему folder-level библиотеки всегда недоверенные, а глобальные - доверенные, и чем это грозит?
Shared library убирает копипаст из пайплайнов: общий код живёт в одном Git-репозитории, а проекты подключают его строкой @Library с прибитой версией. Глобальную библиотеку регистрируют в Manage Jenkins (лучше через JCasC), для статики версии хватает аннотации, для динамики - шага library. И помни про безопасность: глобальные библиотеки доверенные и всесильные, folder-level - в песочнице. Всегда фиксируй версию по тегу, и прод-сборки станут предсказуемыми.