Управление артефактами: публикация в Nexus и Artifactory

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

Управление артефактами: публикация в Nexus и Artifactory

Сообщение 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
Конвейер собрал jar, war, питоновый wheel или Docker-образ. Стейдж позеленел, тесты прошли. И что дальше? Если артефакт остался лежать в рабочей директории агента, считай, его нет. Эфемерный pod в Kubernetes умрёт через минуту после сборки, рабочее пространство затрётся следующим билдом, а ты потом будешь искать, что же именно ушло в продакшен три недели назад. Собрать - это полдела. Вторая половина - положить результат туда, откуда его заберёт деплой, причём с правильной версией и так, чтобы через год можно было воспроизвести ровно ту сборку.

Этот урок про то, куда складывать собранные артефакты и как настроить публикацию из Jenkins в нормальное хранилище. Разберём два главных репозитория - Sonatype Nexus и JFrog Artifactory, версионирование, политики хранения сборок и частный случай - публикацию Docker-образов в registry.

Зачем нужен репозиторий артефактов

Артефакт - это собранный, готовый к доставке результат: бинарник, архив, образ, пакет. Хранить его прямо в Git - плохая идея: репозиторий распухнет, а Git не про бинарные блобы. Для этого есть отдельный класс систем - репозитории артефактов. Они дают версионирование, дедупликацию, контроль доступа, проксирование внешних реестров (Maven Central, npm, PyPI) и метаданные о происхождении сборки.

Два лидера рынка:
  • Sonatype Nexus Repository - есть бесплатная Community-редакция, классика для Maven/Gradle-мира, умеет npm, PyPI, NuGet, Docker и raw.
  • JFrog Artifactory - мощнее по фичам, сильная связка с собственным CLI (jf), хранит "build info" - подробные метаданные о сборке, что критично для трассируемости. Есть OSS-редакция, но многое в платных.
Оба работают по одному принципу: репозитории делятся на hosted (твои собственные артефакты), proxy (зеркало внешнего реестра) и group/virtual (объединяющий фасад). Jenkins публикует именно в hosted-репозиторий.

Изображение

Публикация артефактов в Nexus из конвейера

Для Nexus стандартный путь - плагин Nexus Artifact Uploader, он даёт declarative-совместимый шаг nexusArtifactUploader. Доступ к Nexus храним не в открытом виде, а в Jenkins Credentials (тип Username with password), а в pipeline дёргаем через withCredentials либо через nexusCredentialsId.

Вот рабочий пример публикации jar в Nexus после сборки:

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

pipeline {
    agent any
    options {
        buildDiscarder(logRotator(numToKeepStr: '20', artifactNumKeepStr: '5'))
        timestamps()
    }
    environment {
        NEXUS_URL  = 'nexus.internal:8081'
        APP_GROUP  = 'ru.cyberlake'
        APP_NAME   = 'billing-service'
    }
    stages {
        stage('Build') {
            steps {
                sh './mvnw -B -DskipTests clean package'
            }
        }
        stage('Publish to Nexus') {
            steps {
                nexusArtifactUploader(
                    nexusVersion: 'nexus3',
                    protocol: 'http',
                    nexusUrl: "${NEXUS_URL}",
                    groupId: "${APP_GROUP}",
                    version: "1.4.${BUILD_NUMBER}",
                    repository: 'releases',
                    credentialsId: 'nexus-deploy',
                    artifacts: [[
                        artifactId: "${APP_NAME}",
                        classifier: '',
                        file: "target/${APP_NAME}-1.4.${BUILD_NUMBER}.jar",
                        type: 'jar'
                    ]]
                )
            }
        }
    }
}
Если проект на Maven и ты публикуешь через сам Maven (deploy:deploy-file или mvn deploy), координаты Nexus прописываются в settings.xml или distributionManagement, а кредлы прокидываются так:

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

        stage('Maven deploy') {
            steps {
                configFileProvider([configFile(fileId: 'maven-settings', variable: 'MVN_SETTINGS')]) {
                    sh './mvnw -B -s $MVN_SETTINGS deploy -DskipTests'
                }
            }
        }
Jenkins и Artifactory: современный путь через jf CLI

Для Artifactory в 2026 году актуальный плагин - JFrog Plugin (jenkins-jfrog-plugin). Старый шаг rtUpload из плагина Artifactory всё ещё работает и встречается в легаси-конвейерах, но новый подход - запускать команды JFrog CLI (jf) прямо из pipeline через шаг jf. Это даёт больше контроля и, главное, автоматически собирает build-info - метаданные о том, какие зависимости пошли в сборку и из какого окружения.

Сервер Artifactory настраивается глобально (Manage Jenkins -> JFrog) либо через Configuration as Code, а в конвейере используется так:

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

pipeline {
    agent any
    tools {
        jfrog 'jfrog-cli'
    }
    options {
        buildDiscarder(logRotator(numToKeepStr: '30', artifactNumKeepStr: '10'))
    }
    stages {
        stage('Build') {
            steps {
                sh './gradlew clean assemble'
            }
        }
        stage('Resolve deps from Artifactory') {
            steps {
                // получение зависимостей из приватного репозитория
                jf 'rt dl libs-release/internal/ deps/'
            }
        }
        stage('Upload artifact') {
            steps {
                jf 'rt upload "build/libs/*.jar" libs-release-local/ru/cyberlake/billing/1.4.${BUILD_NUMBER}/'
            }
        }
        stage('Publish build info') {
            steps {
                jf 'rt build-collect-env'
                jf 'rt build-publish'
            }
        }
    }
}
Шаг jf 'rt build-publish' отправляет в Artifactory связную картину: какой билд, какие артефакты он произвёл, какие зависимости использовал. Потом по этой build-info можно одной командой повысить артефакт до релиза или, наоборот, найти все сборки, куда затесалась уязвимая библиотека.

Для сравнения - в GitLab CI и GitHub Actions публикация артефактов в Nexus/Artifactory делается обычно голым curl, mvn deploy или тем же jf CLI внутри шага; отдельной богатой интеграции с build-info, как у Jenkins-плагина JFrog, там из коробки нет, поэтому связка Jenkins + Artifactory до сих пор остаётся сильным аргументом в пользу Jenkins для зрелого артефакт-менеджмента.

Версионирование и политики хранения сборок

Версия артефакта - это его удостоверение личности. Плохая практика - публиковать всё как latest или перетирать одну и ту же версию: ты теряешь воспроизводимость. Хорошая практика - неизменяемые (immutable) версии. Для снапшотов годится схема вида 1.4.0-SNAPSHOT в snapshot-репозиторий, для релизов - чистый SemVer 1.4.7 в release-репозиторий, который Nexus/Artifactory защищают от перезаписи.

Удобно встраивать в версию номер сборки и короткий хеш коммита:

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

        stage('Set version') {
            steps {
                script {
                    env.GIT_SHA = sh(returnStdout: true,
                        script: 'git rev-parse --short HEAD').trim()
                    env.APP_VERSION = "1.4.${BUILD_NUMBER}-${env.GIT_SHA}"
                }
                echo "Будем публиковать версию ${env.APP_VERSION}"
            }
        }
Теперь про jenkins release как процесс: релизный артефакт - это особая сборка, обычно с тега, без -SNAPSHOT, которая попадает в защищённый release-репозиторий и больше не меняется. Часто релиз отделяют от обычной сборки отдельным параметризованным конвейером или веткой when { tag "v*" }.

Отдельная важная тема - сколько билдов хранить в самом Jenkins. Без присмотра история сборок съест диск контроллера. Для этого есть директива buildDiscarder в блоке options:

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

    options {
        buildDiscarder(logRotator(
            numToKeepStr: '50',        // хранить последние 50 сборок
            daysToKeepStr: '30',       // и/или не старше 30 дней
            artifactNumKeepStr: '5',   // тяжёлые артефакты - только у 5 последних
            artifactDaysToKeepStr: '7'
        ))
    }
Тонкость: numToKeepStr отвечает за метаданные и логи сборки, а artifactNumKeepStr отдельно ограничивает хранение тяжёлых архивированных артефактов. Логи можно держать долго, а бинарники чистить быстро - они и так лежат в Nexus/Artifactory, дублировать их в Jenkins смысла нет.

Docker-образ как частный случай артефакта

Образ контейнера - такой же артефакт, просто хранится в Docker registry. Им может быть тот же Nexus или Artifactory (у обоих есть Docker-репозитории), GitLab Registry, GitHub Container Registry или Harbor. Принцип тот же: собрал, протегировал осмысленной версией, запушил, а потом этот тег уезжает в деплой.

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

        stage('Build & push image') {
            steps {
                script {
                    def tag = "registry.internal/cyberlake/billing:1.4.${BUILD_NUMBER}"
                    docker.withRegistry('https://registry.internal', 'registry-creds') {
                        def img = docker.build(tag, '--pull .')
                        img.push()
                        img.push('latest')
                    }
                }
            }
        }
Через JFrog CLI это выглядит так - и сразу подтягивает build-info по слоям образа:

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

                sh 'docker build -t registry.internal/cyberlake/billing:1.4.${BUILD_NUMBER} .'
                jf 'docker push registry.internal/cyberlake/billing:1.4.${BUILD_NUMBER}'
                jf 'rt build-publish'
Главный принцип здесь - связь сборка -> артефакт -> деплой по неизменяемому тегу. Никаких mutable-тегов в проде. Деплой берёт ровно тот образ, который собрал и проверил конвейер.

Типичные грабли
  • Latest вместо версии. Перезаписываешь один тег - и теряешь возможность откатиться и понять, что в продакшене. Только неизменяемые версии.
  • Кредлы Nexus/Artifactory в открытом виде. Логин-пароль в Jenkinsfile или в переменной окружения, видимой в логах - это утечка. Только Jenkins Credentials и withCredentials, маскирование секретов.
  • Публикация до прохождения тестов. Стейдж публикации должен идти после тестов и качества, иначе в репозиторий попадёт битьё.
  • Забытый buildDiscarder. Диск контроллера забивается архивами, Jenkins начинает тормозить. Ставь ротацию сразу в шаблоне пайплайна.
  • Снапшоты в release-репозиторий. Mutable-снапшоты в защищённый релизный репозиторий ломают неизменяемость. Разводи snapshot и release по разным репозиториям.
Мини-лаба
  • Подними локально Nexus (docker run sonatype/nexus3) или Artifactory OSS, создай hosted-репозиторий для своих артефактов.
  • Заведи в Jenkins Credentials деплой-пользователя (Username with password) и пропиши credentialsId в pipeline.
  • Собери простой Maven- или Gradle-проект и опубликуй jar шагом nexusArtifactUploader или jf rt upload с версией вида 1.0.${BUILD_NUMBER}.
  • Добавь в options блок buildDiscarder и проверь, что старые сборки начинают вычищаться.
  • Собери Docker-образ, протегируй номером сборки, запушь в registry и убедись, что тег latest указывает на свежий образ, а версионный тег неизменен.
Контрольные вопросы
  • Чем hosted-репозиторий отличается от proxy и group, и куда из них публикует Jenkins?
  • Почему публиковать артефакт как latest - плохо, и какую схему версионирования стоит выбрать для релизов?
  • За что отвечает numToKeepStr, а за что artifactNumKeepStr в buildDiscarder?
  • Что такое build-info в Artifactory и зачем нужен шаг jf rt build-publish?
Итог

Артефакт без хранилища - это потерянная сборка. Nexus и Artifactory дают версионирование, контроль доступа и трассируемость, а Jenkins публикует в них через nexusArtifactUploader или современный jf CLI с build-info. Версии держи неизменяемыми, секреты - в Credentials, историю сборок ограничивай через buildDiscarder, а Docker-образы трактуй как обычные артефакты с осмысленными тегами. Тогда цепочка сборка -> артефакт -> деплой становится прозрачной и воспроизводимой - именно то, ради чего и затевался весь конвейер.
👍3 ❤️4 🔥1 😄 🤔
Аватара пользователя
policity
Сообщения: 1
Зарегистрирован: 19 май 2026, 05:36

Re: Управление артефактами: публикация в Nexus и Artifactory

Сообщение policity »

Подскажите, а jf rt upload и старый rtUpload это вообще про одно и то же или нет? У нас в легаси конвейерах везде rtUpload, стоит переписывать на jf CLI или пусть живёт?
👍 ❤️ 🔥 😄 🤔
Аватара пользователя
iffies
Сообщения: 1
Зарегистрирован: 15 май 2026, 07:10

Re: Управление артефактами: публикация в Nexus и Artifactory

Сообщение iffies »

Спасибо за разбор buildDiscarder, наконец дошло почему логи можно держать долго а артефакты чистить быстро. У нас контроллер диск забивал именно архивами, поставил artifactNumKeepStr 5 и сразу полегчало.
👍1 ❤️ 🔥1 😄 🤔1
Ответить
← Предыдущая глава
Качество кода: SonarQube и покрытие тестами
Следующая глава →
Docker в Jenkins: образы как агенты сборки

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

Поделиться темой: ✈ Telegram VK

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

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

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