Jenkins — автоматизация сборки и деплоя
Jenkins — самый известный инструмент непрерывной интеграции (CI): он автоматически собирает проект, прогоняет тесты и разворачивает приложение после каждого изменения кода. В этом уроке ты создашь свои первые сборки, pipelines и настроишь автоматический запуск по коммитам.
1. Что такое CI/CD и зачем Jenkins
CI (Continuous Integration) — практика, при которой каждый коммит в общий репозиторий автоматически собирается и проверяется тестами. CD (Continuous Delivery/Deployment) — доведение проверенного кода до продакшена. Руками делать это каждый раз невозможно, поэтому процесс автоматизируют.
Jenkins — сервер автоматизации на Java, который выполняет джобы (jobs): скрипты, привязанные к репозиторию или расписанию. У него тысячи плагинов: интеграции с Git, Docker, JUnit, Slack, SSH и многими другими инструментами.
git push origin main
# -> Jenkins получает уведомление
# -> клонирует код, собирает проект, запускает тесты
# -> публикует отчёт и артефакты
# -> опционально деплоит на сервер| Практика | Что автоматизирует | Как часто |
|---|---|---|
| CI (интеграция) | сборка и тесты после каждого коммита | при каждом изменении |
| CD (доставка) | подготовка релиза, артефакты, репозитории | по готовности |
| CD (деплой) | выкатка кода в продакшен | автоматически или по кнопке |
2. Установка Jenkins
Jenkins запускается как Java-приложение. На Ubuntu установка состоит из двух шагов: Java и сам Jenkins из официального репозитория.
sudo apt update
sudo apt install -y openjdk-17-jre
sudo wget -O /etc/apt/keyrings/jenkins-keyring.asc \
https://pkg.jenkins.io/debian-stable/jenkins.io-2023.key
echo "deb [signed-by=/etc/apt/keyrings/jenkins-keyring.asc] \
https://pkg.jenkins.io/debian-stable binary/" | \
sudo tee /etc/apt/sources.list.d/jenkins.list
sudo apt update
sudo apt install -y jenkins
sudo systemctl enable --now jenkinsПроверь статус и получи первоначальный пароль администратора:
sudo systemctl status jenkins
sudo cat /var/lib/jenkins/secrets/initialAdminPasswordОткрой http://localhost:8080, введи пароль и следуй мастеру установки плагинов.
3. Первый job
Самый простой вид джобы — Freestyle project: веб-форма, где указываются шаги сборки. Создадим джобу, которая печатает приветствие и показывает переменные окружения.
# New Item -> Freestyle project -> имя hello-job
# Build Steps -> Execute shell:
echo "Hello from Jenkins"
echo "Workspace: $WORKSPACE"
env | sort | head -5Нажми Build Now и открой номер запуска (например, #1) — там будут лог консоли и статус. Плавающий синий квадрат означает успех, красный — падение сборки.
| Тип джобы | Когда использовать |
|---|---|
| Freestyle project | простые задания, настройка через веб-интерфейс |
| Pipeline | сложные процессы, код в Jenkinsfile (описано далее) |
| Multibranch Pipeline | сборка каждой ветки репозитория автоматически |
| Folder | группировка многих джоб проекта |
$WORKSPACE. После запуска проверь «Workspace» в джобе — там лежит то, что собрал скрипт.4. Pipelines и Jenkinsfile
Pipeline описывает весь процесс сборки кодом — это называется pipeline-as-code. Такой скрипт лежит в репозитории рядом с проектом и версионируется вместе с ним.
Файл Jenkinsfile в корне репозитория:
pipeline {
agent any
stages {
stage('Сборка') {
steps {
echo 'Собираем проект...'
sh 'python -m pip install -r requirements.txt'
}
}
stage('Тесты') {
steps {
echo 'Запускаем тесты...'
sh 'pytest tests/'
}
}
stage('Деплой') {
steps {
echo 'Деплоим на staging...'
}
}
}
}Эта декларативная форма состоит из трёх частей: agent (где выполнять), stages (этапы) и steps (шаги каждого этапа).
| Блок | Назначение |
|---|---|
| agent any | использовать любой доступный агент |
| agent { docker {...} } | запускать этапы в Docker-контейнере |
| stage | логически отдельный этап процесса |
| steps | шаги внутри этапа: sh, echo, git и другие |
| post | действия после всех этапов (always, success, failure) |
sh для shell-команд. Синтаксис Groovy чувствителен к кавычкам: одинарные кавычки не подставляют переменные, а двойные интерполируют ${...}.node { ... }) гибче, но сложнее — начинай с декларативного.5. Триггеры запуска
Сборка может запускаться автоматически: по расписанию, по изменению кода или по вебхуку из Git-платформы. В декларативном pipeline для этого есть блок triggers.
pipeline {
agent any
triggers {
pollSCM('H/5 * * * *')
cron('H 2 * * *')
}
stages {
stage('Тесты') {
steps { sh 'pytest tests/' }
}
}
}pollSCM— проверять репозиторий каждые 5 минут и запускать сборку на новых коммитах;cron— запуск по расписанию, например ночные тесты в 02:00;webhook— мгновенный запуск при push, настроенный на стороне Git.
| Поле cron | Значение | Смысл |
|---|---|---|
| минуты | H/5 | каждые 5 минут |
| часы | H 2 | в 2 часа ночи |
| дни месяца | * | каждый день |
| месяц | * | каждый месяц |
| день недели | 1-5 | будни |
H заменяет число хэшем, чтобы не запускать все джобы одновременно. Используй его в полях cron.pollSCM не нужен.6. Окружение и креденшелы
Пароли, токены и ключи SSH нельзя хранить в конфигурации и в репозитории. Jenkins хранит их в защищённом хранилище Credentials и подставляет в сборку по идентификатору.
Сначала добавь секрет: Dashboard → Manage Jenkins → Credentials → Add, тип Secret text, например идентификатор deploy-token. Использование внутри pipeline:
pipeline {
agent any
environment {
APP_ENV = 'staging'
}
stages {
stage('Публикация') {
steps {
withCredentials([string(credentialsId: 'deploy-token',
variable: 'TOKEN')]) {
sh 'docker login -u deployer --password-stdin <<< "$TOKEN"'
}
}
}
}
}| Тип креденшела | Что хранит |
|---|---|
| Username with password | логин и пароль |
| Secret text | одиночный токен или пароль |
| Secret file | целый файл (например, service-account) |
| SSH Username with private key | ключ для подключения по SSH |
withCredentials — обязательное условие. Без него переменная попадёт в общий процесс сборки, а её значение — в лог консоли.environment задаёт переменные для всего pipeline, а ключевое слово env. даёт доступ к встроенным переменным Jenkins.7. Интеграция с Git
Jenkins умеет клонировать репозиторий и запускать сборку для определённой ветки. Для этого нужен плагин Git и указание URL репозитория.
pipeline {
agent any
triggers { pollSCM('H/5 * * * *') }
options { skipDefaultCheckout() }
stages {
stage('Клонирование') {
steps {
git branch: 'main',
url: 'https://github.com/yourname/myapp.git',
credentialsId: 'github-ssh'
}
}
stage('Тесты') {
steps { sh 'pytest tests/' }
}
}
}Шаг git скачивает код с ветки main по SSH-креденшелу github-ssh. Если репозиторий публичный, креденшелы не нужны.
| Параметр | Назначение |
|---|---|
| url | адрес репозитория (HTTPS или SSH) |
| branch | ветка для сборки |
| credentialsId | креденшел с доступом к приватному репозиторию |
| changelog | показывать в сборке список коммитов |
8. Отчётность о тестах
Просто запустить тесты мало — нужно собрать результаты и показать их команде. Многие тестовые фреймворки умеют писать отчёты в формате JUnit XML, и Jenkins превращает их в наглядные графики и тренды.
pipeline {
agent any
stages {
stage('Тесты') {
steps {
sh 'pytest --junitxml=reports/pytest.xml tests/'
}
}
}
post {
always {
junit 'reports/pytest.xml'
publishHTML(target: [
allowMissing: false,
alwaysLinkToLastBuild: true,
reportDir: 'htmlcov',
reportFiles: 'index.html',
reportName: 'Покрытие кода'
])
}
}
}Директива junit разбирает XML-файл, а publishHTML показывает сгенерированный отчёт (например, покрытие pytest-cov) прямо на странице джобы.
| Инструмент | Файл отчёта | Что видно в Jenkins |
|---|---|---|
| pytest | reports/pytest.xml | количество пройденных и упавших тестов |
| JUnit | target/surefire-reports/*.xml | графики истории и длительность |
| pytest-cov | htmlcov/index.html | HTML-отчёт о покрытии |
| Allure | allure-results/ | красивый веб-отчёт со сценариями |
post { always { ... } }.9. Артефакты
Артефакты — результаты сборки: собранные бинарники, dist/ и *.whl, Docker-образы. Jenkins умеет сохранять их после каждой сборки и архивировать.
pipeline {
agent any
stages {
stage('Сборка') {
steps { sh 'python -m build' }
}
}
post {
success {
archiveArtifacts artifacts: 'dist/**',
fingerprint: true,
allowEmptyArchive: false
stash name: 'release', includes: 'dist/**'
}
}
}archiveArtifacts— сохранить файлы в Jenkins после сборки;fingerprint— запомнить контрольные суммы, чтобы отследить, в какую сборку попал файл;stash— передать файлы между этапами без сохранения в архиве.
| Шаг | Назначение | Где посмотреть |
|---|---|---|
| archiveArtifacts | долгое хранение в Jenkins | страница запуска → Artifacts |
| stash / unstash | передача между stages | прямо в pipeline |
| сторонний репозиторий | версионированные артефакты | Nexus, Artifactory |
options { buildDiscarder(logRotator(numToKeepStr: '20')) }.10. Лучшие практики
Чтобы Jenkins не превратился в источник головной боли, придерживайся нескольких правил.
- Pipeline-as-code — весь процесс сборки хранится в Jenkinsfile в репозитории.
- Не храни секреты — только креденшелы Jenkins, никогда strings и env в скрипте.
- Запускай в контейнерах — чистые окружения вместо «захаренного» агента.
- Один pipeline — одна джоба, а не легион копий с разными параметрами.
- Ограничивай хранилище логами, артефактами и числом сборок.
Агент на Docker получает изолированное окружение для каждой сборки:
pipeline {
agent {
docker { image 'python:3.12-slim' }
}
stages {
stage('Тесты') {
steps {
sh 'pip install -r requirements.txt'
sh 'pytest tests/'
}
}
}
options {
buildDiscarder(logRotator(numToKeepStr: '20'))
timeout(time: 15, unit: 'MINUTES')
}
}| Категория | Рекомендация |
|---|---|
| Код | Jenkinsfile декларативный и находится в репозитории |
| Безопасность | секреты только через Credentials, права по ролям |
| Окружение | агент в Docker, неизменяемые зависимости |
| Производительность | таймауты, limit конкурентости, чистка артефактов |
| Мониторинг | уведомления в Slack, статус в коде репозитория |
11. Параметризованные сборки
Не каждая сборка одинакова: иногда нужно указать ветку, окружение или версию релиза. Параметры делают джобу интерактивной и позволяют запускать одну и ту же логику с разными значениями.
pipeline {
agent any
parameters {
choice(name: 'ENV', choices: ['staging', 'prod'], description: 'Куда деплоим')
string(name: 'BRANCH', defaultValue: 'main', description: 'Ветка для сборки')
booleanParam(name: 'RUN_TESTS', defaultValue: true)
}
stages {
stage('Тесты') {
when { expression { params.RUN_TESTS } }
steps { sh 'pytest tests/' }
}
stage('Деплой') {
steps {
sh "deploy.sh ${params.ENV} ${params.BRANCH}"
}
}
}
}- статические параметры задаются в блоке
parameters; - динамические списки даёт плагин Active Choices;
- внутри пайплайна значения доступны как
params.Имя.
when: тесты или тяжёлый деплой запускаются строго по условию.12. Мастер и агенты
В большой команде сборки перестают помещаться на одном Jenkins: контроллер (мастер) координирует, а агенты выполняют работу. Каждая сборка направляется на агента по меткам и доступности.
pipeline {
agent { label 'linux && docker' }
stages {
stage('Сборка') {
steps { sh 'docker build -t app .' }
}
}
}| Роль | Задача |
|---|---|
| Контроллер | веб-интерфейс, планирование, хранение конфигурации |
| Агент (node) | выполняет stages в своём окружении |
| Метка (label) | группа агентов с общим свойством |
- метки дают гибкость:
'linux && docker'выбирает подходящий узел; - агенты на Docker создаются динамически плагином docker;
- параллельные джобы распределяются по агентам автоматически.
13. Shared Libraries: общий код пайплайнов
Когда одинаковые шаги (обёртки docker, уведомления) повторяются в десятках джоб, их выносят в общую библиотеку. Shared Library — репозиторий с кодом на Groovy, подключённый к Jenkins.
// vars/deployApp.groovy (в репозитории библиотеки)
def call(String env) {
echo "Деплой в ${env}"
}
// Jenkinsfile
library 'devops-lib'
pipeline {
agent any
stages {
stage('Деплой') {
steps { deployApp('staging') }
}
}
}- файл
vars/имя.groovyстановится функцией шага; - версия библиотеки указывается тегом в Git;
- общие шаги меньше дублируются и чинятся в одном месте.
14. Безопасность и обслуживание Jenkins
Jenkins — сервер в вашей инфраструктуре, к нему применимы обычные правила: регулярные обновления, ограниченные права, резервные копии и мониторинг диска.
- обновляйте Jenkins и плагины: старые версии — известные уязвимости;
- настройте матрицу прав через плагин Role-based Strategy;
- резервная копия — каталог
$JENKINS_HOMEс конфигурацией; - следите за местом на диске: логи и артефакты растут быстро.
# быстрая проверка диска и перезапуск после обновления
df -h /var/lib/jenkins
sudo systemctl restart jenkins
journalctl -u jenkins -f # живые логи| Практика | Как часто |
|---|---|
| Обновление Jenkins и плагинов | раз в месяц |
| Бэкап $JENKINS_HOME | ежедневно |
| Проверка свободного места | еженедельно |
| Аудит прав пользователей | перед крупными релизами |
15. Docker-агенты: сборка в контейнерах
Сборки в изолированных контейнерах защищают мастер от «мусора» зависимостей: каждый job стартует с чистого образа, а результат — артефакт, а не замараная машина.
pipeline {
agent {
docker { image 'maven:3.9-eclipse-temurin-17' }
}
stages {
stage('Build') { steps { sh 'mvn package' } }
}
}- агент Docker использует плагин docker или dockerPipeline — образ тянется по имени;
- для node-проектов — образ Node, для Go — golang, для Python — python;
- каталог workspace монтируется в контейнер, поэтому
workspaceобщий.
maven-cache:/root/.m2 — это ускоряет первые сборки в 3–5 раз.16. Палитры сборок: parallel, matrix и when
Одна пайплайна может собирать проект под разные ОС/версии без дублирования кода — директивы matrix и parallel.
pipeline {
agent any
stages {
stage('Matrix Build') {
matrix {
axes {
axis { name 'VERSION'; values '8u422', '17', '21' }
axis { name 'OS'; values 'linux', 'windows' }
}
stages {
stage('Test') { steps { ... } }
}
}
}
}
}matrixпараллельно прогоняет все комбинации осей;parallel { … }запускает ветки одновременно с ограничением на агентов;- директива
whenвключает/выключает стадию по условиям (branch, tag, env).
17. Продвинутые техники: Shared pipeline, когда и повтор
Скрапаторы решают три частые задачи: переиспользовать логику, управлять условиями и аккуратно обрабатывать сбои.
// повтор при flaky-тестах
stage('Test') {
steps {
retry(2) { sh 'mvn test' }
timeout(time: 10, unit: 'MINUTES') { sh '...' }
}
}retry()стоит только на «шумных» шагах (сеть, нагрузки) — не маскируйте стабильные баги;timeout()защищает сборку от зависшего навсегда шага;- общие шаблоны пайплайнов выносите в Shared Library (раздел 13).
post {
always { junit 'target/surefire-reports/*.xml' }
failure { slackSend color: 'danger', message: "Сборка ${env.JOB_NAME}" }
success { archiveArtifacts artifacts: 'target/*.jar' }
}18. Инструменты аналитики: отчёты, качество, метрики
Jenkins умеет показывать не только «зелёное/красное», но и цифры: покрытие, дефекты, время сборки, уязвимости — через плагины.
| Плагин | Что даёт |
|---|---|
| JUnit/TestNG | таблица тестов и результаты во времени |
| Warnings NG | предупреждения компилятора, линтеров |
| JaCoCo | покрытие кода по репозиторию |
| OWASP Dependency-Check | уязвимости в зависимостях |
pipeline {
stages {
stage('Analyze') {
steps {
recordCoverage(tools: [[parser: 'JACOCO', pattern: 'target/jacoco.exec']])
}
}
}
}19. Blue Ocean: визуализация и удобство пайплайнов
Классический интерфейс Jenkins перегружен. Blue Ocean — современный UI для пайплайнов: запуски видны ветками, этапы — карточками, а падения подсвечиваются сразу.
# установить плагин Blue Ocean
# Jenkins → Manage → Plugins → Blue Ocean
2026-09-19 10:00:42 [Pipeline] Start of Pipeline
stage «Build» — green # шаг выполнен
stage «Test» — red # fail, открыть фрагмент лога- разбивка на шаги видна «из коробки» — нет ручной навигации по логам;
- визуальный редактор собирает Jenkinsfile без запоминания синтаксиса;
- Blue Ocean ставится плагином поверх базового Jenkins.
20. Job DSL: джобы как код
Сотня фристайл-джобов, настроенных руками, не поддерживается. Плагин Job DSL описывает джобы скриптом на Groovy — и генерирует их автоматически при изменении кода.
// jobdsl.groovy
job('build-app') {
scm { git('https://github.com/org/app.git') }
steps { shell('npm ci && npm run build') }
triggers { cron('H/15 * * * *') }
}
// после прогона джоба появляется в Jenkins- джобы «как код» версионируются в git и проходят code review;
- Seed-джоба пересоздаёт конфигурации из репозитория при коммите;
- генерация с параметрами убирает ручные правки в интерфейсе.
21. Уведомления о сборках: Telegram, Slack и email
Пайплайны молчат, пока всё зелёное, — но красную сборку команда должна увидеть за минуты. Плагины уведомлений решают это без «лишних совещаний».
| Канал | Плагин | Типичный кейс |
|---|---|---|
| Telegram | telegram-notifications | результат сборки боту |
| Slack | Slack Notification | канал команды с деталями |
| Mailer | полные отчёты |
post {
failure {
telegramSend(text: "Сборка упала: ${env.BUILD_URL}")
}
success {
slackSend(channel: '#ci', message: 'OK')
}
}22. Отказоустойчивость: бэкапы и горячий мастер
Jenkins хранит историю сборок, джобы, секреты и плагины в $JENKINS_HOME. Потерять её — потерять всю конфигурацию. Плановый бэкап — правило №1 администрирования.
# бэкап конфигурации
tar czf /backup/jenkins_$(date +%F).tgz \
/var/lib/jenkins
# восстановление: распаковать и запустить jenkins- бекапьте ежедневно: jobs, config.xml, credentials, plugins, secrets;
- горячий мастер: второй Jenkins плюс репликация конфигов через Job DSL;
- артефакты сборок хранятся на хранилище, поэтому их бэкап вторичен.
Что дальше
Ты прошёл путь от первого job до полноценного pipeline: триггеры, креденшелы, Git, отчёты и артефакты. Следующие логичные шаги — собрать приложение в Docker внутри пайплайна и выложить на сервер перед Nginx. Если репозиторий на GitHub, сравни подход Jenkins с нативным GitHub Actions, а секреты найди урок HashiCorp Vault.