Skip to content

Jenkins CI/CD

Что это такое

Непрерывная интеграция (CI, Continuous Integration) - практика разработки программного обеспечения, которая заключается в постоянном слиянии рабочих копий в общую основную ветвь разработки (до нескольких раз в день) и выполнении частых автоматизированных сборок проекта для скорейшего выявления потенциальных дефектов и решения интеграционных проблем. В обычном проекте, где над разными частями системы разработчики трудятся независимо, стадия интеграции является заключительной. Она может непредсказуемо задержать окончание работ. Переход к непрерывной интеграции позволяет снизить трудоёмкость интеграции и сделать её более предсказуемой за счёт наиболее раннего обнаружения и устранения ошибок и противоречий, но основным преимуществом является сокращение стоимости исправления дефекта, за счёт раннего его выявления.

CICD

Схема взаимодействия Jenkins+GitLab+Nexus+Docker:

  • Jenkins - сервер предназначен для обеспечения процесса непрерывной интеграции программного обеспечения (имеет некий пул агентов на которых и выполняется сборка)
  • Nexus - сервер предназначен для бинарных артефактов включает в себя docker registry
  • GitLab - веб-инструмент жизненного цикла DevOps и распределённая система управления версиями
  • Docker - программное обеспечение для автоматизации развёртывания и управления приложениями в средах с поддержкой контейнеризации
  • Docker образ - некий набор библиотек из которых состоит окружение для работы приложения (предназначенного для какой то конкретной задачи)

(git push) → (gitlab - git hook) → (jenkins run build) → (jenkins git clone, test, build, etc) → (nexus artifactory) → (jenkins etc) → (.....)

  • (git push) - программист отправляет изменения в репозиторий или сливает в мастер ветку (зависит от того на что настроен хук)
  • (gitlab - git hook) - GitLab делает http запрос на определённый URL по определённым событиям (ниже на скриншотах будет пример)
  • (jenkins run build) - сборка проекта (при необходимости скачивается docker образ из Nexus docker registry)
  • (jenkins git clone, test, build, etc) - шаги сборки проекта описываются в файле конфигурации (Jenkinsfile) или в web интерфейсе Jenkins в зависимости от выбранного типа проекта
  • (nexus artifactory) - результат сборки проекта Jenkins отправляет в сервер бинарных артефактов Nexus, так же на моменте сборки проекта Jenkins может использовать библиотеки либо другие артефакты
  • (jenkins etc) - По завершению сборки проекта можно вызвать сборки других проектов которые будут проводить дополнительные действия (например либо доставку кода на целевой вычислитель)

Результат работы системы непрерывной интеграции - бинарный файл, или докер образ в docker-registry

Требования

Для применения практики необходимо выполнение ряда базовых требований к проекту разработки. В частности, исходный код и всё, что необходимо для сборки и тестирования проекта, должно храниться в репозитории системы управления версиями, а операции копирования из репозитория, сборки и тестирования всего проекта должны быть автоматизированы и легко вызываться из внешних программ.

Для организации процесса непрерывной интеграции на выделенном сервере запускается служба, в задачи которой входят:

  • получение исходного кода из репозитория;
  • сборка проекта;
  • выполнение тестов;
  • развёртывание готового проекта;
  • отправка отчетов.

Локальная сборка может осуществляться по внешнему запросу, по расписанию, по факту обновления репозитория и по другим критериям.

В основном есть несколько подходов к созданию проектов автоматизированных сборок.

  • Pipeline - один из вариантов, который позволяет программистам самостоятельно управлять своей сборкой и хранить файл конфигурации вместе с кодом.
  • В этом случае все шаги сборки описываются в файле который обычно хранится в репозитории с самим проектом. (пример файла будет ниже)
  • Свободная конфигурация даёт больше свободы в выборе плагинов и механизмов управления, но теряется удобство хранение конфигурации вместе к кодом.
  • В этом варианте настройка всех шагов происходит через web интерфейс и хранится исключительно на Jenkins сервере. Соответственно для того что бы внести изменения в сборку - нужны соответствующие права на редактирования.

Создание проекта с использованием файла конигурации (Jenkinsfile) тип проекта "pipeline"

Создание проекта в Jenkins для типа проекта "pipeline" включает в себя следующие этапы:

  1. создание проекта Jenkins через Web интерфейс
  2. создание токена (набора символов для идентификации ) для удалённого вызова сборки через http запрос
  3. добавление репозитория в проект (клонирование происходит в момент сборки проекта, ssh ключ надо выбрать cicd при этом пользователю jenkins должен быть доступен репозиторий как минимум на чтение)
  4. пример результатов сборки проекта
  5. более человеко-читаемый вид сборки проекта виден в представлении Open Blue Ocean

Ниже приведены изображения с Web интерфейса Jenkins, и Gitlab показывающие поэтапное создание цепочки CI

1.1) Создание сборочного проекта

1.1

1.2) Выбор имени и типа проекта

1.2

2) Создание идентификатора (токена) для удалённого вызова сборки проекта по http запросу

2

3) Добавление целевого репозитория (файл конфигурации проекта Jenkinsfile будет взят из клонированного репозитория)

3

4.1) В корне проекта будут видны результаты сборок, один из результатов выполнения сборки показан на изображении ниже

4.1

4.2) Лог сборки можно посмотреть по нажатию на конкретный шаг сборки (кубик с временем работы)

4.2

4.3) Лог сборки первого шага (клонирования репозитория)

4.3

5) Попасть в Open Blue Ocean можно нажав на одноимённую кнопку в корне проекта

5

Создание проекта с использованием файла конигурации (Jenkinsfile) тип проекта "multibranch pipeline"

Основное отличие заключается в автоматическом сканировании веток репозитория. Создание проекта в Jenkins для типа проекта "multibranch pipeline" включает в себя следующие этапы:

  1. создание проекта Jenkins через Web интерфейс
  2. добавление репозитория в проект (клонирование происходит в момент сборки проекта, ssh ключ надо выбрать cicd при этом пользователю jenkins должен быть доступен репозиторий как минимум на чтение)
  3. лог сканирования репозитория на наличия веток
  4. пример результатов сборки проекта
  5. создание токена (набора символов для идентификации ) для удалённого вызова сборки через http запрос
  6. более человеко-читаемый вид сборки проекта виден в представлении Open Blue Ocean
  7. настройка GitLab hook для вызова сборки через http запрос с помощью токена (в зависимости от варианта item'а токен может определять какую именно сборку запустить т.к. в мультибранчевых сборках основной URL одинаковый, различаются только токены)
  8. создание файла инструкций для этого item'а

1) Ниже приведены изображения с Web интерфейса Jenkins, и Gitlab показывающие поэтапное создание цепочки CI

1

2) Добавление целевого репозитория (файл конфигурации проекта Jenkinsfile будет взят из клонированного репозитория)

2

3.1) После сканирования веток, запускаются сборки тех которые были изменены по отношению к последней сборки. В первый раз запускаются все имеющиеся ветки.

3.1

3.2) По умолчанию тип проекта multibranch pipeline сканирует все ветки проекта и пытается из запустить. На скриншоте показан корень проекта.

3.21

4.1) В корне ветки проекта будут видны результаты сборок, один из результатов выполнения сборки ветки master показан на изображении ниже.

4.1

5) Создание идентификатора (токена) для удалённого вызова сборки проекта по http запросу

5

Настройка GitLab hook по событию и отображения результата сборки в проекте GitLab в виде бейджа

Для автоматизации сборок проекта необходимо настроить GitLab. Настройка включает в себя следующие этапы:

  1. настройка GitLab hook для вызова сборки через http запрос
  2. настройка бейджа статуса сборки проекта

Ниже приведены изображения с Web интерфейса Gitlab показывающие поэтапное создание цепочки CI

1) В GitLab настройках проекта в параметрах интеграция указываются события при которых будет выполнен http запрос (в примере URL запроса указан токен "t")

1

2.1) Статус сборки можно наблюдать по определённому URLу предоставляемом Jenkins сервером. На скриншоте примеры разных бейджей.

2.1

2.2) В GitLab настройках проекта в параметрах основных настроек есть вкладка Badges. Пример настройки бейджа показан на скринщоте.

2.2

Если доступ к сборкам виден только после авторизации то надо указывать так:

  • https://jenkins.example.org/buildStatus/icon?job=example-multibranch-pipeline&style=plastic&subject=example-multibranch-pipeline

2.3) В результате статус сборки виден в проекте GitLab пример показан на скриншоте

2.3

Пример файла конигурации (Jenkinsfile) для тип проекта "multibranch pipeline" и "pipline"

Файл конфигурации проекта описывается на groovy

Пример Jenkinsfile
#!groovy
// Run build stm32
properties([disableConcurrentBuilds()])

pipeline {
    agent any
    options {
        buildDiscarder(logRotator(numToKeepStr: '10', artifactNumToKeepStr: '10'))
        timestamps()
    }
    stages {
        stage('docker login') {
            steps {
              ansiColor(colorMapName: 'xterm') {
                echo " ============== docker login =================="
                withCredentials([usernamePassword(credentialsId: 'ldap_jenkins', usernameVariable: 'USERNAME', passwordVariable: 'PASSWORD')]) {
                    sh """
                    docker login -u${USERNAME} -p${PASSWORD} ${DOCKERREGISTRY}
                    """
                }
              }
            }
        }

        stage('docker pull') {
            steps {
              ansiColor(colorMapName: 'xterm') {
                echo " ============== docker pull =================="
                sh '''
                docker pull ${DOCKERREGISTRY}/ubuntu1804/arm-none-eabi-gcc
                '''
              }
            }
        }

// Использовался для отладки
//        stage('git clone') {
//          steps {
//            ansiColor(colorMapName: 'xterm') {
//                sshagent(credentials: ['git']) {
//                  echo " ============== git clone =================="
//                  sh 'rm -rf ./*'
//                  sh 'git clone --recursive --branch=dev --depth 1 git@gitlab.dtulyakov.ru:project2.0/stm32f7-firmware.git'
//                }
//            }
//          }
//        }

        stage('build') {
          steps {
            ansiColor(colorMapName: 'xterm') {
              echo " ============== build =================="
                sh '''
                   docker run -u 1000 --rm --name=${JOB_BASE_NAME} \
                   --volumes-from Jenkins-Slave \
                   --workdir ${WORKSPACE} \
                   ${DOCKERREGISTRY}/ubuntu1804/arm-none-eabi-gcc \
                   sh -c "${WORKSPACE}/build.sh"
                    '''
            }
          }
        }

        stage('send artifact') {
            steps {
              ansiColor(colorMapName: 'xterm') {
                echo " ============== send artifact =================="
                withCredentials([usernamePassword(credentialsId: 'ldap_jenkins', usernameVariable: 'USERNAME', passwordVariable: 'PASSWORD')]) {
                    sh """
                    cd ${WORKSPACE}/build/ \
                    && tar -cJvf ${WORKSPACE}/stm32f7-firmware.tar.xz \
                      stm32f7-bind-eval_crc.bin \
                      stm32f7-bind-eval_crc.hex \
                      stm32f7-bind-eval_crc.srec
                    cd ${WORKSPACE}
                    sha256sum --tag stm32f7-firmware.tar.xz > ${WORKSPACE}/stm32f7-firmware.tar.xz.sum
                    sha1sum --tag stm32f7-firmware.tar.xz >> ${WORKSPACE}/stm32f7-firmware.tar.xz.sum
                    md5sum --tag stm32f7-firmware.tar.xz >> ${WORKSPACE}/stm32f7-firmware.tar.xz.sum
                    curl -u "${USERNAME}:${PASSWORD}" -X PUT "${NEXUSRAW}/stm32f7-firmware/stm32f7-firmware.tar.xz" -T ${WORKSPACE}/stm32f7-firmware.tar.xz
                    curl -u "${USERNAME}:${PASSWORD}" -X PUT "${NEXUSRAW}/stm32f7-firmware/stm32f7-firmware.tar.xz.sum" -T ${WORKSPACE}/stm32f7-firmware.tar.xz.sum
                    """
                }
              }
            }
        }

  }
}

Создание проекта с использованием тип проекта "свободная конфигурация"

Создание проекта в Jenkins для типа проекта "свободная конфигурация" включает в себя следующие этапы:

  1. создание проекта Jenkins через Web интерфейс
  2. настройка очистки сборочного каталога от старых сборок
  3. добавление репозитория в проект (клонирование происходит в момент сборки проекта, ssh ключ надо выбрать cicd при этом пользователю jenkins должен быть доступен репозиторий как минимум на чтение)
  4. создание токена (набора символов для идентификации ) для удалённого вызова сборки через http запрос
  5. настройка консоли сборки и добавление шага сборки (тип shell script)
  6. триггер для запуска другого проекта

1) Ниже приведены изображения с Web интерфейса Jenkins, показывающие поэтапное создание цепочки CI

1

1.1) Корень проекта "cpp_base" (проект на скриншоте вызывает другой проект по своему успешному завершению)

1.1

2) Настройка очистки истории сборок

2

3) Добавление целевого репозитория (в этом примере клонирование происходит с саб-модулями)

3

4) Настройка токена в поле "триггеры сборки" и параметров для docker-registry. Сделано для того, что бы в открытом виде не было видно логины/пароли. Создаётся переменная в которую заносятся параметры которые не видны при сборках проекта (в примере переменные USERNAME и PASSWORD)

4

5.1) Настройка консоли (логирование времеи выполнения команд, тип консоли xterm). И пример шага сборки

5.1

5.2) Настройка консоли вывода и шага сборки

buildrun () {
    docker login -u${LUSERNAME} -p${LPASSWORD} ${DOCKERREGISTRY}
    docker pull ${DOCKERREGISTRY}/ubuntu1804/cpp_start
    chown -R jenkins:jenkins ${WORKSPACE}
    docker run -u 1000 --rm --name=${JOB_BASE_NAME} \
        --volumes-from Jenkins-Slave \
        --workdir ${WORKSPACE}/app/gis-srv-app \
        ${DOCKERREGISTRY}/ubuntu1804/cpp_start \
    sh -c "cmake . -DOSG_DIR=/usr/ && make -j $(nproc --ignore=2)"
}
for submodule in $(awk '/path/{print $NF}' ${WORKSPACE}/.gitmodules); do cd ${WORKSPACE}/${submodule} ; git pull origin develop ; done
buildrun;

6) Настройка триггера для запуска другого проекта (при удачной сборке текущего проекта)

6

Сервер бинарных артефактов Nexus

Сервер Nexus может содержать различные типы репозиториев для хранения бинарных артефактов:

  1. Raw (бинарный) репозиторий (любые бинарные файлы)
  2. Репозиторий контейнеризованных приложений (Docker реестр или docker registry)
  3. Репозиторий пакетов (deb, rpm, ...)

На скриншоте видно два репозитория, один docker registry второй raw для бинарных артефактов

Nexus

1) Пример артефакта для проекта прошивки микроконтроллера (stm32f7) в raw репозитории

1

2) Пример образов в docker registry репозитории

2

Ссылки