Сборка и публикация Docker-образов из конвейера

Рейтинг: 71.7% · 16 голосов
Подробный курс по Jenkins и CI/CD: установка и настройка, плагины и Configuration as Code, конвейеры (pipeline) и Jenkinsfile, declarative и scripted, агенты, Docker и Kubernetes, общие библиотеки на Groovy, безопасность и credentials, интеграции (SonarQube, артефакты), траблшутинг. Актуально на 2026.
Ответить
Аватара пользователя
Andrey_CICD
Сообщения: 47
Зарегистрирован: 11 май 2026, 05:31

Сборка и публикация Docker-образов из конвейера

Сообщение Andrey_CICD »

Оглавление курса (47)
  1. Что такое Jenkins и зачем нужен CI/CD
  2. Jenkins в 2026: версии, экосистема и сравнение с GitLab CI и GitHub Actions
  3. Архитектура Jenkins: контроллер, агенты, узлы и исполнители
  4. Установка Jenkins: пакеты, Docker и Kubernetes
  5. Первичная настройка Jenkins: мастер, плагины, пользователи
  6. Плагины Jenkins: установка, обновление и ключевой набор
  7. Configuration as Code (JCasC): настройка Jenkins декларативно
  8. Конвейеры Jenkins и Jenkinsfile: pipeline as code
  9. Scripted против Declarative: два синтаксиса конвейера
  10. Структура конвейера: node, stage, steps и первый pipeline
  11. Генератор сниппетов, запуск конвейера и Replay
  12. Типы заданий Jenkins: Freestyle, Pipeline, Multibranch и Organization
  13. Декларативный конвейер: структура pipeline, agent, stages
  14. agent, environment и переменные в конвейере
  15. tools, options, parameters и triggers в декларативном конвейере
  16. stages, parallel и matrix: организация этапов
  17. Условное выполнение when и блок post
  18. Триггеры сборки: webhook от GitHub, SCM polling и расписание
  19. Параметры сборки и пользовательский ввод
  20. Управление потоком: timeout, retry, sleep и waitUntil
  21. Параллелизм и блокировки: parallel, lock, milestone
  22. Постобработка и уведомления о результате сборки
  23. Groovy для Jenkins: основы скриптового конвейера
  24. Скриптовый конвейер: логика, циклы и функции
  25. Общие библиотеки Jenkins: Shared Libraries
  26. Подключение и загрузка общих библиотек
  27. Шаги оболочки: sh, bat, powershell и коды возврата
  28. Переменные среды, withEnv и рабочие пространства
  29. Работа с файлами, артефактами и отпечатками
  30. Сборка проектов в конвейере: Maven, Gradle, npm
  31. Качество кода: SonarQube и покрытие тестами
  32. Управление артефактами: публикация в Nexus и Artifactory
  33. Docker в Jenkins: образы как агенты сборки
  34. Сборка и публикация Docker-образов из конвейера (вы здесь)
  35. Jenkins в Kubernetes: динамические pod-агенты
  36. Развёртывание в Kubernetes из конвейера
  37. Безопасность Jenkins: аутентификация и матрица прав
  38. Учётные данные Jenkins: credentials в конвейере
  39. Безопасность сценариев: Groovy sandbox и Vault
  40. Уведомления и отчёты: email, Slack, Telegram, HTML
  41. Blue Ocean и интерфейс Jenkins в 2026
  42. Автоматизация Jenkins: CLI, REST API и script console
  43. Поиск и устранение неисправностей: читаем логи конвейера
  44. Типичные ошибки конвейера: сериализация и неутверждённый код
  45. Эксплуатация Jenkins: бэкап, обновление, масштабирование
  46. Конвертация и миграция: от Freestyle к Jenkinsfile
  47. Итог: сквозной CI/CD конвейер и Jenkins против альтернатив в 2026
Зачем вообще собирать образ внутри Jenkins

Знакомая боль: приложение готово, тесты зелёные, а на сервер оно едет "руками". Кто-то заходит по ssh, делает docker build, забывает поставить тег, пушит не туда, и в проде оказывается образ, который никто не может воспроизвести. Через неделю "а какой коммит там собран" - ответа нет.

Связка jenkins docker эту дыру закрывает. Идея простая: образ собирается ровно там же, где прошли тесты, тегается понятным идентификатором (номер сборки, хеш коммита), сканируется на дыры и публикуется в registry. Один и тот же артефакт едет дальше по конвейеру. В этом уроке разберём, как настроить docker jenkins так, чтобы jenkins docker build и jenkins docker push были обычными шагами пайплайна, а не ручным ритуалом.

Сразу про версии, чтобы не строить на песке. Актуальная LTS на лето 2026 - линия 2.541.x (релиз 2.541.1 от 21 января 2026), и это последняя ветка с поддержкой Java 11. Следующая LTS, которая выходит 15 апреля 2026, требует уже Java 21, а weekly-сборки давно на Java 21. Если ставишь новый контроллер - сразу бери Java 21, чтобы не упереться в обновление через пару месяцев. Blue Ocean из книги Ластера трогать не будем: проект фактически заброшен, новый UI Jenkins живёт своей жизнью, и завязываться на Blue Ocean в 2026 не стоит.

Изображение

Глобальная переменная docker: build, image, withRegistry

Классический путь - плагин Docker Pipeline. Он добавляет глобальную переменную docker с тремя рабочими лошадками:
  • docker.build(tag, context) - собирает образ из Dockerfile, возвращает объект образа.
  • docker.image(ref) - оборачивает существующий образ, чтобы его запускать (.inside, .run, .withRun).
  • docker.withRegistry(url, credsId) - логинится в registry на время блока и пушит туда.
Вот рабочий declarative-конвейер, который делает jenkins build image, гоняет тесты в контейнере и публикует результат. Подразумевается, что на агенте есть docker-демон (через сокет или DinD):

Код: Выделить всё

pipeline {
    agent any

    environment {
        REGISTRY = 'registry.cyberlake.ru'
        IMAGE    = 'team/web-app'
    }

    stages {
        stage('Checkout') {
            steps { checkout scm }
        }

        stage('Build image') {
            steps {
                script {
                    // тег по номеру сборки + короткий хеш коммита
                    def gitSha = sh(returnStdout: true, script: 'git rev-parse --short HEAD').trim()
                    env.IMG_TAG = "${env.BUILD_NUMBER}-${gitSha}"
                    app = docker.build("${REGISTRY}/${IMAGE}:${IMG_TAG}", "-f Dockerfile .")
                }
            }
        }

        stage('Test in container') {
            steps {
                script {
                    // поднимаем собранный образ и прогоняем тесты внутри него
                    app.inside {
                        sh 'pytest -q'
                    }
                }
            }
        }

        stage('Push') {
            steps {
                script {
                    docker.withRegistry("https://${REGISTRY}", 'registry-creds') {
                        app.push("${IMG_TAG}")
                        // двигаем latest только с основной ветки
                        if (env.BRANCH_NAME == 'main') {
                            app.push('latest')
                        }
                    }
                }
            }
        }
    }
}
Что тут важно. Креды registry-creds - это обычный Username/Password секрет в Jenkins (логин и токен/пароль реестра), withRegistry сам делает docker login и logout. Тег собираем осмысленно: BUILD_NUMBER даёт монотонность, короткий sha даёт привязку к коммиту - всегда понятно, из чего собран образ. latest двигаем только с main, иначе ветки перетрут друг друга.

Если хочется обойтись без script-блока, шаг docker. живёт в Groovy, поэтому в declarative его оборачивают в script - это нормально и не считается грязью.

Сборка без docker-демона: kaniko в Kubernetes

Подход выше требует docker-демона на агенте. В Kubernetes это боль и риск: монтировать /var/run/docker.sock в pod - значит дать сборке root-доступ ко всему хосту, а DinD с privileged - ещё хуже. Поэтому в 2026 на эфемерных агентах в k8s docker build почти не делают. Берут rootless-сборщики: kaniko или buildah. Они собирают образ из Dockerfile целиком в userspace, без демона.

Самый ходовой - kaniko. Через kubernetes-плагин описываем pod с двумя контейнерами: один для сборки приложения, второй - kaniko-executor. Важная деталь из практики: бери образ kaniko с тегом debug, потому что в нём есть busybox-shell (/busybox/sh), а в обычном latest шелла нет, и container-шаг просто не запустится.

Код: Выделить всё

pipeline {
    agent {
        kubernetes {
            yaml '''
apiVersion: v1
kind: Pod
spec:
  containers:
  - name: kaniko
    image: gcr.io/kaniko-project/executor:debug
    command: ["sleep"]
    args: ["9999999"]
    volumeMounts:
    - name: docker-config
      mountPath: /kaniko/.docker
  volumes:
  - name: docker-config
    projected:
      sources:
      - secret:
          name: registry-creds
          items:
          - key: .dockerconfigjson
            path: config.json
'''
        }
    }

    stages {
        stage('Build & push') {
            steps {
                container('kaniko') {
                    sh '''
                        /kaniko/executor \
                          --dockerfile=Dockerfile \
                          --context=`pwd` \
                          --destination=registry.cyberlake.ru/team/web-app:${BUILD_NUMBER} \
                          --cache=true
                    '''
                }
            }
        }
    }
}
Креды реестра здесь - это kubernetes-секрет типа docker-registry (поле .dockerconfigjson), который проецируется в /kaniko/.docker/config.json. Kaniko сам его подхватит, отдельного login не нужно. Флаг --cache=true складывает промежуточные слои в реестр и заметно ускоряет повторные сборки. По сути это тот же jenkins docker push, только без демона и без privileged - идеально для эфемерных pod-агентов.

Сканирование образа на уязвимости (Trivy)

Собрать и запушить мало - образ с дырявой базой и кучей CVE отдавать в прод нельзя. Шаг сканирования встраивается между build и push, чтобы дырявый образ просто не доехал до реестра. Удобнее всего гонять Trivy из официального образа, ничего не ставя на агент:

Код: Выделить всё

stage('Scan') {
    steps {
        sh """
            docker run --rm \
              -v /var/run/docker.sock:/var/run/docker.sock \
              aquasec/trivy:latest image \
              --exit-code 1 --severity HIGH,CRITICAL --ignore-unfixed \
              ${REGISTRY}/${IMAGE}:${IMG_TAG}
        """
    }
}
--exit-code 1 на HIGH и CRITICAL роняет сборку, если нашлись исправимые уязвимости - это и есть shift-left: дыру ловим до публикации, а не в проде. --ignore-unfixed убирает шум по тому, на что патча всё равно нет. В k8s-варианте Trivy так же легко добавить отдельным контейнером в pod.

Типичные грабли
  • Сокет docker как root. Монтировать /var/run/docker.sock или гнать privileged DinD на общих агентах - дыра в безопасности. В k8s переходи на kaniko/buildah.
  • kaniko:latest без шелла. container('kaniko') падает, потому что нет /busybox/sh. Нужен тег debug.
  • Тег latest на всё подряд. Каждая ветка перетирает latest, и непонятно, что в реестре. Тегай по сборке и коммиту, latest двигай только с main.
  • Креды в открытую. Никаких паролей реестра в Jenkinsfile. Только credentials-биндинг или k8s-секрет.
  • Trivy без exit-code. Скан, который только печатает и не валит билд, никого ни от чего не защищает.
Чем это отличается от GitLab CI и GitHub Actions

Полезно держать в голове соседей. В GitLab CI и GitHub Actions сборка образа - это, как правило, готовый job/action (docker buildx, kaniko-step, аналог aquasecurity/trivy-action), описанный в YAML, и раннеры эфемерны по умолчанию. Jenkins даёт больше контроля и гибкости (особенно сложные multibranch-конвейеры и Groovy-логика), но требует, чтобы ты сам держал контроллер, агентов и плагины. Связка docker jenkins сильна там, где нужна нетривиальная оркестрация и self-hosted-инфраструктура; для простого "собрал-запушил" облачные системы зачастую короче. Знать оба подхода - значит выбирать инструмент под задачу, а не под привычку.

Мини-лаба
  • Возьми любое приложение с Dockerfile, собери его через docker.build с тегом ${BUILD_NUMBER}-${gitSha}.
  • Заведи в Jenkins секрет registry-creds и запушь образ через docker.withRegistry в свой реестр (подойдёт локальный registry:2).
  • Добавь stage с app.inside и прогони внутри образа хотя бы один тест.
  • Встрой Trivy-скан с --exit-code 1 --severity HIGH,CRITICAL и убедись, что дырявый образ валит сборку.
  • Со звёздочкой: перепиши пайплайн на kubernetes-агент с kaniko:debug и k8s-секретом, без docker-демона.
Контрольные вопросы
  • Чем docker.build отличается от docker.image и когда нужен каждый?
  • Почему в Kubernetes предпочитают kaniko/buildah вместо docker build с сокетом или DinD?
  • Как withRegistry получает доступ к реестру и где должны лежать креды?
  • Что делает --exit-code 1 в Trivy и почему без него скан почти бесполезен?
Итог

Образ должен собираться, проверяться и публиковаться из конвейера, а не руками. Глобальная переменная docker (build, image, withRegistry) закрывает классический сценарий с демоном, kaniko - современный rootless-путь для эфемерных агентов в Kubernetes, а Trivy не пускает дырявый образ в реестр. Тегируй осмысленно, прячь креды, вали билд на критичных CVE - и docker jenkins из источника боли превращается в предсказуемый поток артефактов.
👍2 ❤️ 🔥1 😄 🤔1
Аватара пользователя
vimcoder
Сообщения: 1
Зарегистрирован: 28 май 2026, 00:12

Re: Сборка и публикация Docker-образов из конвейера

Сообщение vimcoder »

Перешёл с docker.build на kaniko в k8s после того как нам зарубили монтирование docker.sock на проде. Минус демон, минус privileged, спится спокойнее. Тег debug реально обязателен, час убил пока не понял почему container падает.
👍 ❤️ 🔥2 😄 🤔
Аватара пользователя
tonyyy
Сообщения: 1
Зарегистрирован: 27 май 2026, 01:45

Re: Сборка и публикация Docker-образов из конвейера

Сообщение tonyyy »

А Trivy с --exit-code 1 не слишком ли агрессивно валит билды? У нас на легаси-образах столько HIGH что ничего не соберётся. Думаю начать с --ignore-unfixed и потом закручивать гайки, спасибо за пример.
👍1 ❤️ 🔥 😄 🤔
Ответить
← Предыдущая глава
Docker в Jenkins: образы как агенты сборки
Следующая глава →
Jenkins в Kubernetes: динамические pod-агенты

Все главы курса «Jenkins: конвейеры CI/CD от основ до продакшена»

Поделиться темой: ✈ Telegram VK
Похожие запросы: что такое jenkins простыми словамикак установить jenkins на linux и в dockerкакие плагины jenkins нужны новичкукак настроить агенты jenkins для сборкиgroovy в jenkins scripted pipeline как написатьпараметры и параллельные стейджи в jenkins pipeline

Вернуться в «Jenkins: конвейеры CI/CD от основ до продакшена»

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и 1 гость