Руководство прикладного разработчика#

Системные требования#

Системные требования изложены в разделе «Системные требования» Руководства по установке.

Подключение и конфигурирование#

Вход в приложение#

Для работы с Pipeliner рекомендуется использовать следующие браузеры:

  • Яндекс (22.1+) - рекомендовано

  • Google Chrome (98.0+) - опционально

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

  1. Перейдите по адресу http://{pipeliner-ipAddress}:8888/, где {pipeliner-ipAddress} - адрес сервера Pipeliner.

  2. На открывшейся странице в правом верхнем углу нажмите «Войти».

  3. Введите имя пользователя и пароль и подтвердите ввод.

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

Если введенные данные были корректны, откроется Главная страница Pipeliner:

dev1

Подключение#

Настройка агентов с помощью Docker#

Агенты Pipeliner можно запускать на физических машинах, виртуальных машинах, кластерах Kubernetes и с образами Docker. Этот раздел показывает как подключить агенты Docker к Pipeliner с помощью SSH.

Для этого потребуется:

  • Java

  • Pipeliner

  • Docker

  • Пара ключей SSH

Создание пары ключей SSH#

Чтобы сгенерировать пару ключей SSH, необходимо запустить инструмент командной строки ssh-keygen. Генерацию пары ключей SSH можно выполнить в любой операционной системе. Допускается использовать любую установку OpenSSH.

  1. В окне терминала выполните команду: ssh-keygen -f ~/.ssh/pipeliner_agent_key.

  2. Укажите кодовую фразу для использования с ключом (она может быть пустой).

  3. Пример вывода:

    ubuntu@desktop:~$ ssh-keygen -f ~/.ssh/pipeliner_agent_key
    Generating public/private rsa key pair.
    Enter passphrase (empty for no passphrase):
    Enter same passphrase again:
    Your identification has been saved in /home/ubuntu/.ssh/pipeliner_agent_key
    Your public key has been saved in /home/ubuntu/.ssh/pipeliner_agent_key.pub
    The key fingerprint is:
    SHA256: {SHA256-value}
    The key's randomart image is:
    +---[RSA 3072]----+
      {image-value}
    +----[SHA256]-----+
    

Создание учетных данных Pipeliner SSH#

  1. Перейдите на панель инструментов Pipeliner.

  2. Перейдите к опции «Manage Pipeliner» (Управление Pipeliner) в главном меню и нажмите на кнопку «Manage Credentials» (Управление учетными данными).

    conn-1

  3. Выберите вариант «Add Credentials» (Добавить учетные данные) из элемента global.

    conn-2

  4. Заполните поля формы:

    Поле

    Значение

    Kind (Вид)

    Выберите «Имя пользователя SSH с закрытым SSH-ключом»

    Scope (Область действия)

    Global - если учетные данные добавляются для Pipeline проекта/элемента. Выбор этой опции применяет область учетных данных к проекту/элементу Pipeline и всем его дочерним объектам. System - если учетные данные предназначены для того, чтобы сам экземпляр Pipeline взаимодействовал с функциями системного администрирования, такими как подключение агента и т. д. Выбор этой опции применяет область учетных данных только к одному объекту.

    ID (Идентификатор)

    Pipeliner

    Username (Имя пользователя)

    Pipeliner

    Password (Пароль)

    Введите пароль

    Description (Описание)

    Ключ Pipeliner SSH

    Private Key (Приватный ключ)

    Выберите «Enter directly» (Ввести) и нажмите кнопку «Add» (Добавить), чтобы вставить содержимое вашего файла закрытого ключа из ~/.ssh/Pipeliner_agent_key

    Passphrase (Парольная фраза)

    Введите парольную фразу, используемую для генерации пары ключей SSH (оставьте пустым, если вы не использовали ее на предыдущем шаге)

    conn-3

  5. Нажмите кнопку «Create» (Создать).

Создание своего Docker агента в Linux#

Здесь используется образ docker-ssh-agent для создания контейнеров агента.

  1. Выполните команду для запуска первого агента, где [your-public-key] - открытый ключ SSH:

    docker run -d --rm --name=agent1 -p 22:22 \
    -e "JENKINS_AGENT_SSH_PUBKEY=[your-public-key]" \
    jenkins/ssh-agent:alpine
    
  2. Выполните cat ~/.ssh/pipeliner_agent_key.pub, чтобы узнать значение открытого ключа. Если на вашем компьютере уже присутствует ssh-сервер, работающий на этом 22-ом порту (подключение к компьютеру по SSH), используйте другой порт для docker команды, например -p 4444:22

  3. Чтобы обновить среду контейнера, выполните:

    $ VARS1="HOME=|USER=|MAIL=|LC_ALL=|LS_COLORS=|LANG="
    $ VARS2="HOSTNAME=|PWD=|TERM=|SHLVL=|LANGUAGE=|_="
    $ VARS="${VARS1}|${VARS2}"
    $ docker exec agent1 sh -c "env | egrep -v '^(${VARS})' >> /etc/environment"
    

Теперь контейнер agent1 работает. Также можно использовать команду docker ps, чтобы проверить, работает ли контейнер должным образом.

Способы запуска агентов#

Есть 2 способа запуска агентов:

  • Запуск агентов с помощью контроллера (Launch agent by connecting it to the controller);

  • Запуск агентов через SSH (Launch agents via SSH).

Запуск агентов с помощью контроллера (Launch agent by connecting it to the controller)#

Позволяет агенту подключаться к контроллеру Pipeliner, используя Java Web Start. В этом случае на компьютере агента должен быть открыт файл JNLP, который установит TCP-соединение с контроллером Pipeliner. Это означает, что агент не обязательно должен быть доступен с контроллера - агент должен иметь возможность связаться с контроллером. Данный способ описан в разделе "Настройка agent1 на Pipeliner".

Запуск агентов через SSH (Launch agents via SSH)#

Запускает агент, отправляя команды по защищенному SSH-соединению. Агент должен быть доступен с главного компьютера, и необходимо указать учетную запись, которая может входить в систему на целевом компьютере. Данный способ запуска предоставляет плагин SSH Build Agents.

Настройка agent1 на Pipeliner#

  1. Перейдите в панель инструментов Pipeliner.

  2. Перейдите к опции «Настроить Pipeliner» в главном меню.

  3. Перейдите к элементу «Управление средами сборки».

    agent-conn1

  4. Перейдите к опции «Новый узел» в боковом меню.

  5. Заполните имя узла/агента и выберите тип (например, имя: agent1, тип: Permanent Agent).

  6. Заполните поля:

    Поле

    Пример значения

    Корень удаленной ФС

    /home/pipeliner/

    Метки

    agent1

    Использование

    Use this node as much as possible (Максимально возможное использование узла)

    Способ запуска

    Launch agent by connecting it to the controller (Запуск агента при подключении к контроллеру)

    agent-conn2.1

    agent-conn2.2

  7. Нажмите кнопку «Save» (Сохранить), и agent1 будет зарегистрирован, но пока не будет в сети. Нажмите на созданный агент «agent1»:

    dev2

  8. Появится сообщение «Этот узел запускается…» (This node is being launched…). Если это не так, нажмите кнопку «Перезапустить агент» (Relaunch agent), подождите несколько секунд и нажмите кнопку «Лог» (Log) слева. В журнал последней строкой выведется сообщение: «Агент успешно подключен» (Agent successfully connected and online).

    dev3

Если ваш контроллер Pipeliner не запускает агент через SSH, проверьте порт агента. Скопируйте его, а затем нажмите кнопку «Advanced…» (Дополнительно). Затем необходимо вставить номер порта в текстовое поле «Port» (Порт).

Делегирование первого задания для agent1#

  1. Перейдите на панель инструментов Pipeliner.

  2. Выберите «Создать Item» в боковом меню.

  3. Введите имя (например: First Job to Agent1).

  4. Выберите «Создать опцию со свободной конфигурацией» и нажмите «OK».

  5. Отметьте опцию «Блокировать сборку, пока вызванная задача не завершена».

  6. Заполните поле «Отображаемое имя» (например: agent1).

    dev4

  7. Выберите опцию «Выполнить команду shell» в разделе сборки.

    agent-job2

  8. Добавьте команду: echo $NODE_NAME в поле «Команда» шага «Выполнить команду shell», чтобы имя агента печаталось внутри лога при запуске этого задания.

  9. Нажмите кнопку сохранения, а затем выберите вариант «Собрать сейчас».

  10. Подождите несколько секунд, а затем перейдите на страницу «Вывод консоли».

    date

  11. Если все успешно, то выведется следующее:

    Started by user Admin User
    Running as SYSTEM
    Building remotely on agent1 in workspace /home/Pipeliner/workspace/First Job to Agent1
    [First Job to Agent1] $ /bin/sh -xe /tmp/jenkins15623311211559049312.sh
    + echo $NODE_NAME
    agent1
    Finished: SUCCESS
    

Конфигурация#

Можно получить различные параметры конфигурации для Pipeliner, щелкнув пункт «Настроить Pipeliner» в боковом меню. Откроется следующий экран:

conf-2

Нажмите «Конфигурация системы». Ниже описаны некоторые параметры конфигурации Pipeliner.

Домашняя директория#

Pipeliner требуется место на диске для выполнения сборок и хранения архивов. Это местоположение можно проверить на экране конфигурации Pipeliner. По умолчанию установлено ~/.jenkins, и это местоположение изначально будет храниться в вашем профиле пользователя. Измените это местоположение на подходящее место для хранения всех соответствующих сборок и архивов. Один раз можно сделать это следующими способами:

  • Перед запуском контейнера сервлетов задайте для переменной среды JENKINS_HOME новый домашний каталог.

  • Установите системное свойство JENKINS_HOME для контейнера сервлета.

Ниже описано, как использовать первый вариант установки переменной среды JENKINS_HOME.

  1. Создайте новую папку. Скопируйте все содержимое из существующего ~/.jenkins в этот новый каталог.

  2. Установите переменную среды JENKINS_HOME, чтобы она указывала на расположение базового каталога, в котором на вашем компьютере установлена Java. Установите JENKINS_HOME=/usr/local/Jenkins или в другое необходимое вам местоположение.

  3. На панели инструментов Pipeliner нажмите «Настроить Pipeliner» в меню слева. Затем нажмите «Конфигурация системы».

В домашней директории находится новый настроенный каталог.

Количество сборщиков#

Показывает общее количество заданий, которые могут одновременно выполняться на компьютере. Рекомендуется оставить это число таким же, как количество процессоров на машинах для повышения производительности.

Переменные среды#

Используется для добавления пользовательских переменных среды, которые будут применяться ко всем заданиям. Это пары ключ-значение, к которым можно получить доступ и использовать их в сборках, где это необходимо.

URL-адрес Pipeliner#

По умолчанию установлено localhost. Это поможет при отправке ссылок по электронной почте, поскольку можно напрямую получить доступ к URL-адресу Pipeliner, используя переменную среды JENKINS_URL, доступ к которой можно получить как ${JENKINS_URL}.

Уведомление по электронной почте#

В области уведомлений по электронной почте можно настроить параметры SMTP для отправки электронных писем. Это необходимо для подключения к почтовому серверу SMTP и отправления электронных писем списку получателей.

Работа c Jenkinsfile#

Использование переменных среды#

Pipeliner предоставляет переменные среды через глобальную переменную env, которая доступна из любого места внутри файла Jenkinsfile. Полный список переменных среды, доступных из Pipeliner Pipeline, задокументирован по адресу ${Pipeliner_URL}/pipeline-syntax/globals#env и включает:

  • BUILD_ID
    Текущий идентификатор сборки, идентичный BUILD_NUMBER для сборок.

  • BUILD_NUMBER
    Текущий номер сборки, например 153.

  • BUILD_TAG
    Строка jenkins-${JOB_NAME}-${BUILD_NUMBER}. Удобно помещать в файл ресурсов, файл jar и т.д. для облегчения идентификации.

  • BUILD_URL
    URL-адрес, по которому находятся результаты этой сборки.

  • EXECUTOR_NUMBER
    Уникальный номер, идентифицирующий текущего исполнителя (среди исполнителей одной машины), выполняющего эту сборку. Это число отображается в поле «Статус исполнителя сборки».

  • JAVA_HOME
    Если ваше задание настроено на использование определенного JDK, эта переменная устанавливается в JAVA_HOME указанного JDK. Когда эта переменная установлена, PATH также обновляется.

  • JENKINS_URL
    Полный URL-адрес Pipeliner.
    ПРИМЕЧАНИЕ: доступно, если URL-адрес Pipeliner установлен в «Конфигурация системы».

  • JOB_NAME
    Имя проекта этой сборки, например foo или foo/bar.

  • NODE_NAME
    Имя узла, на котором выполняется текущая сборка. Установите master для контроллера Pipeliner.

  • WORKSPACE Абсолютный путь рабочей области.

Ссылка или использование этих переменных среды может выполняться так же, как доступ к любому ключу в Groovy, например:

Jenkinsfile (Declarative Pipeline)
pipeline {
    agent any
    stages {
        stage('Example') {
            steps {
                echo "Running ${env.BUILD_ID} on ${env.JENKINS_URL}"
            }
        }
    }
}

Установка переменных окружения#

Установка переменной среды в конвейере Pipeliner выполняется по-разному в зависимости от того, используется ли декларативный или скриптовый конвейер.

Декларативный конвейер поддерживает директиву среды, тогда как пользователи скриптового конвейера должны использовать этот withEnv шаг:

Jenkinsfile (декларативный конвейер)
pipeline {
    agent any
    environment { 
        CC = 'clang'
    }
    stages {
        stage('Example') {
            environment { 
                DEBUG_FLAGS = '-g'
            }
            steps {
                sh 'printenv'
            }
        }
    }
}
  1. Директива environment, используемая в блоке верхнего уровня pipeline, будет применяться ко всем шагам в конвейере.

  2. Директива environment, определенная в stage файле, будет применять данные переменные среды только к шагам в файле stage.

Динамическая установка переменных среды#

Переменные среды могут быть установлены во время выполнения и могут использоваться скриптами оболочки (sh), пакетными скриптами bat и скриптами powershell. Каждый скрипт может возвращать либо returnStatus, либо returnStdout.

Ниже приведен пример декларативного конвейера, использующего sh (оболочку) с обоими returnStatus и returnStdout.

Jenkinsfile (declarative pipeline)
pipeline {
    agent any 
    environment {
        // Using returnStdout
        CC = """${sh(
                returnStdout: true,
                script: 'echo "clang"'
            )}""" 
        // Using returnStatus
        EXIT_STATUS = """${sh(
                returnStatus: true,
                script: 'exit 1'
            )}"""
    }
    stages {
        stage('Example') {
            environment {
                DEBUG_FLAGS = '-g'
            }
            steps {
                sh 'printenv'
            }
        }
    }
}
  1. Agent должен быть установлен на верхнем уровне конвейера. Это не удастся, если агент установлен как agent none.

  2. При использовании завершающего пробела returnStdout к возвращаемой строке будет добавлен пробел. Используйте .trim() для удаления.

Миграция на текущую версию#

Установка нового Pipeliner war-файла#

Файл jenkins.war на сервере Pipeliner находится в каталоге /usr/lib/jenkins.

  1. Сделайте резервную копию существующей версии war-файла jenkins.

    cp /usr/lib/jenkins/jenkins.war /downloads/jenkins.war.previous.version

  2. Скопируйте загруженный war-файл в каталог /usr/lib/jenkins.

    cp /downloads/jenkins.war /usr/lib/jenkins/

  3. Перезапустите службу Pipeliner, как показано ниже. Используйте команду systemctl или service.

    systemctl stop jenkins
    systemctl start jenkins
    

Если сервер Pipeliner работает с новым файлом, выведется следующая информация:

# systemctl status jenkins
? jenkins.service - LSB: Jenkins Continuous Integration Server
   Loaded: loaded (/etc/rc.d/init.d/jenkins)
   Active: active (running) since Sun 2016-06-11 20:33:16 PDT; 3s ago
     Docs: man:systemd-sysv-generator(8)
  Process: 32453 ExecStop=/etc/rc.d/init.d/jenkins stop (code=exited, status=0/SUCCESS)
  Process: 32473 ExecStart=/etc/rc.d/init.d/jenkins start (code=exited, status=0/SUCCESS)
   Memory: 461.2M
   CGroup: /system.slice/jenkins.service
           +-32498 /etc/alternatives/java -Dcom.sun.akuma.Daemon=daemonized -Djava.awt.headless=true -DJENKINS_HOME=/var/lib/jenkins -jar /usr/lib/jenkins/jenkins.war --log...

Jun 10 20:33:15 devdb systemd[1]: Starting LSB: Jenkins Continuous Integration Server...
Jun 10 20:33:15 devdb runuser[32474]: pam_unix(runuser:session): session opened for user jenkins by (uid=0)
Jun 10 20:33:16 devdb runuser[32474]: pam_unix(runuser:session): session closed for user jenkins
Jun 10 20:33:16 devdb jenkins[32473]: Starting Jenkins [  OK  ]
Jun 10 20:33:16 devdb systemd[1]: Started LSB: Jenkins Continuous Integration Server.

Задачи после обновления#

После обновления войдите в пользовательский интерфейс Pipeliner и убедитесь, что номер версии в правом нижнем углу обновился на новый.

Также вы можете выполнить следующую команду из командной строки, чтобы увидеть новую версию:

java -jar jenkins-cli.jar -s http://localhost:8080/ version

Быстрый старт#

Загрузка и установка Pipeliner#

  1. Загрузите универсальный пакет Java для Pipeliner (.war).

  2. Откройте терминал в каталоге загрузки.

  3. Наберите команду java -jar jenkins.war --httpPort=8080

  4. Откройте в браузере: http://localhost:8080.

  5. Следуйте инструкциям для завершения установки.

Когда установка будет завершена, можно приступать к работе с Pipeliner.

Создание Pipeline#

Pipeliner Pipeline (или просто «Pipeline») — это набор подключаемых модулей, которые поддерживают реализацию и интеграцию конвейеров непрерывной доставки в Pipeliner.

Конвейер непрерывной доставки — это автоматизированный процесс доставки программного обеспечения от системы контроля версий до пользователей и клиентов.

Pipeliner Pipeline предоставляет расширяемый набор инструментов для моделирования конвейеров доставки от простых к сложным «в виде кода». Определение конвейера Pipeliner обычно записывается в текстовый файл (называемый Jenkinsfile), который, в свою очередь, проверяется в репозитории системы контроля версий проекта.

Чтобы быстро начать работу с Pipeline:

  1. Скопируйте один из приведенных ниже примеров в свой репозиторий и назовите его Jenkinsfile.

    Java

    Jenkinsfile (Declarative Pipeline)
    pipeline {
        agent { docker { image 'maven:3.8.4-openjdk-11-slim' } }
        stages {
            stage('build') {
                steps {
                    sh 'mvn --version'
                }
            }
        }
    }
    

    Node.js / JavaScript

    Jenkinsfile (Declarative Pipeline)
    pipeline {
        agent { docker { image 'node:16.13.1-alpine' } }
        stages {
            stage('build') {
                steps {
                    sh 'node --version'
                }
            }
        }
    }
    

    Ruby

    Jenkinsfile (Declarative Pipeline)
    pipeline {
        agent { docker { image 'ruby:3.0.3-alpine' } }
        stages {
            stage('build') {
                steps {
                    sh 'ruby --version'
                }
            }
        }
    }
    

    Python

    Jenkinsfile (Declarative Pipeline)
    pipeline {
        agent { docker { image 'python:3.10.1-alpine' } }
        stages {
            stage('build') {
                steps {
                    sh 'python --version'
                }
            }
        }
    }
    

    PHP

    Jenkinsfile (Declarative Pipeline)
    pipeline {
        agent { docker { image 'php:8.1.0-alpine' } }
        stages {
            stage('build') {
                steps {
                    sh 'php --version'
                }
            }
        }
    }
    

    Go

    Jenkinsfile (Declarative Pipeline)
    pipeline {
        agent { docker { image 'golang:1.17.5-alpine' } }
        stages {
            stage('build') {
                steps {
                    sh 'go version'
                }
            }
        }
    }
    
  2. Щелкните «New item» (Новый элемент) в меню Pipeliner.

  3. Укажите имя вашего нового элемента (например, My-Pipeline) и выберите Multibranch Pipeline.

  4. Нажмите кнопку «Добавить источник», выберите тип репозитория для использования и заполните данные.

  5. Нажмите кнопку «Сохранить».

После настройки конвейера Pipeliner автоматически обнаружит любые новые ветки или запросы на извлечение, созданные в репозитории, и запустит для них конвейеры.

Использование программного компонента#

Примеры работы с API#

Чтобы посмотреть доступные endpoints в API продукта, перейдите по следующему адресу: https://{pipeliner-ip:port}/api, где:

  • pipeliner-ip - IP-адрес продукта Pipeliner;

  • port - порт адреса.

Контроль объема данных, которые извлекает пользователь#

amount-data-1

amount-data-2

Общая статистика загрузки Jenkins#

statistics

Работа с заданиями, хранящимися в Pipeliner#

Создание и редактирование сценариев развертывания ведется через веб-интерфейс Pipeliner.

Работа с заданиями, хранящимися в git#

Способ хранения задается в блоке pipeline:

Выберите «Pipeline script from SCM» (Pipeline-скрипт из SCM) и укажите параметры репозитория (адрес, учетные данные, ветка, название файла со сценарием).

В репозитории должен находится как минимум 1 файл со сценарием.

Также здесь можно разместить специфичные для конкретной задачи скрипты, библиотеки и т.д. При запуске такого задания все содержимое репозитория будет клонировано на slave и будет доступно при выполнении pipeline-скрипта.

Хранение учетных данных и подготовка задания#

Учетные данные рекомендуется хранить с помощью credentials plugin, а не в открытом виде.

Для создания учетных записей перейдите в папку с заданием, выберите «Credentials» (Учетные данные) (слева) > «Folder» (Папка) > «Global credentials» (Глобальные учетные данные).

dev5

Далее ими можно воспользоваться:

withCredentials(\[usernamePassword(credentialsId:

'<some credentials>', passwordVariable: 'pass', usernameVariable: 'user')]) { sh 'curl -u {env.user}:{env.pass} localhost:8080/auth' }

Внутри блока заводятся переменные среды, в данном случае user и pass, содержащие учетные данные.

Ниже схематично представлен типовой pipeline для развертывания приложений.

Данный этап подготовительный, на нем задаются переменные окружения и прочие атрибуты задания. Также этот этап включает в себя взаимодействие с пользователем:

  • запрос на продолжение или отмену;

  • загрузка артефактов из ARR;

  • рассылка уведомлений.

Пример интерактивного ввода между этапами Pipeline:

node {
  stage('Build') {
    // код
    // Отправка письма с запросом продолжать/не продолжать
    mail body: "${env.JOB_NAME} требует ввода.<br>Сделайте выбор по 
    <a href=${env.BUILD_URL}>ссылке</a> . <br> ",
  charset: 'utf-8', mimeType: 'text/html', subject: "${env.JOB_NAME}!",
    to: "example@example.ru"
  input 'Запускать deploy?'
}
stage('Deploy') {
  // код
  // Отправка письма с запросом теста
  mail body: "${env.JOB_NAME} требует ввода.<br>Сделайте выбор
  по < a href = $ {
    env.BUILD_URL
  }> ссылке</a > . < br > ",
  charset: 'utf-8', mimeType: 'text/html', subject: "${env.JOB_NAME}!",
    to: "example@example.ru"
  choice = new ChoiceParameterDefinition('Smoketests', ['Smoke1',
    'Smoke2', 'Smoke3', 'Без smoke-теста'
  ] as String[], 'SmokeTests:')
  def userinput = input id: '30', message: 'Какие тесты запускать?', parameters: [choice]
  switch (userinput) {
    case 'Без smoke-теста':
      break
    default:
      stage 'Smoke test' + userinput
      echo "Running smoke test " + userinput
      build userinput
  }
}
}

Пример выбора версии артефакта из ARR:

node {
  def ver
  stage('Stage 1') {
    def versions = getVersionId('http://example:port/nexus/service/local', 'com.example.aep', 'aep-module')
    ver = input message: 'Get Version',
      parameters: [choice(choices: versions, description: '', name: 'versions')]
    echo ver
  }
  stage('Stage 2') {
    echo getNexusLink('http://example:port/nexus/service/local', 'aep-module', ver, 'zip', 'AE-SPARK_group', 'com.example.aep')
    echo 'Hello World 2'
  }
  stage('send mail') {
    echo "pass"
  }
}
@NonCPS
def getNexusLink(nexusRestApiUrl, nexusArtifactId, nexusVersionId, nexusExtensionId, nexusRepositoryId, nexusGroupId) {
  def api = "${nexusRestApiUrl}/artifact/maven/redirect?g=${nexusGroupId}&a=${nexusArtifactId}&v=${nexusVersionId}&e=${nexusExtensionId}&r=${nexusRepositoryId}"
  def con = new URL(api).openConnection()
  con.connect()
  def is = con.getInputStream()
  is.close()
  con.getURL().toString()
}
@NonCPS
def getVersionId(nexusRestApiUrl, nexusGroupId, nexusArtifactId) {
  def versions = []
  def parser = new XmlParser();
  def xml = parser.parse("${nexusRestApiUrl}/lucene/search?g=${nexusGroupId}&a=${nexusArtifactId}");
  xml['data']['artifact']['version'].collect {
    it - >
      it.text()
  }.unique().join("\n")
}

Запуск задания Pipeliner при появлении новой сборки в ARR#

Для этого примера используется Pipeliner плагин URLTrigger Plug-in.

После установки плагина в задании появится пункт URLTrigger — Poll with a URL (Опрос URL):

В данном примере раз в минуту опрашивается изменение содержимого файла, расположенного по ссылке, указанной в URL. При его изменении запускается задание.

Пример настройки задания для запуска:

Посмотреть статус опроса адреса можно через пункт меню Pipeliner — URLTrigger Log (Журнал URLTrigger).

Загрузка и распаковка файла из ARR#

Адрес для загрузки формируется на основе полей artifactId и versionId. Скрипт выполняется на linux Pipeliner slave, на котором должны быть установлены утилиты md5sum, curl и unzip. После загрузки архив распаковывается в каталог arr в текущем Pipeliner workspace.

def getNexusLink(nexusRestApiUrl, nexusArtifactId, nexusVersionId, nexusExtensionId, nexusRepositoryId, nexusGroupId) {
  def api = "$nexusRestApiUrl/artifact/maven/redirect?g=$nexusGroupId&a=$nexusArtifactId&v=$nexusVersionId&e=$nexusExtensionId&r=$nexusRepositoryId"
  def con = new URL(api).openConnection()
  con.connect()
  def is = con.getInputStream()
  is.close()
  con.getURL().toString()
}
def getUrl(url) {
  new URL(url).getText()
}
// artifactId
// versionId
// NEXUS_URL = 'http://localhost:8081/nexus/content/repositories/example/example.zip'
NEXUS_URL = getNexusLink("http://localhost:8081/nexus/service/local",
  "${artifactId}",
  "${versionId}",
  "zip",
  "CC_CD_KK_repo",
  "Infobank.Distrib")
echo "${NEXUS_URL}"
def workspace = pwd()
md5sum = getUrl("${NEXUS_URL}.md5")
writeFile file: "example1.zip.md5", text: "${md5sum}  example1.zip\n"
dir('nexus') {}
sh "if ! md5sum -c example1.zip.md5; then curl -s -L ${NEXUS_URL} -o example1.zip && unzip -o -d ${workspace}/nexus example1.zip -x 'Documentation*'; fi"

Шаг Deploy#

Шаг установки специфичен для каждой автоматизированной системы. Поддерживается широкий набор языков программирования, включая скриптовые.

Средства сборки (ant, maven) и языки программирования (например, python) уже настроены и доступны в качестве инструментов (tools).

Работа в консоли Groovy#

Pipeliner имеет консоль Groovy - Script Console, которая позволяет запускать произвольные сценарии Groovy в основной среде выполнения или в среде на агентах. Script Console - это веб-оболочка Groovy для среды выполнения. К функциям Groovy относится следующее:

  1. Создание подпроцессов и выполнение произвольных команд на мастере и агентах Pipeliner.

  2. Чтение файлов, к которым мастер Pipeliner имеет доступ на хосте (например, /etc/passwd).

  3. Расшифровка учетных данных, настроенных в Pipeliner. Консоль предоставляет обширный набор функций. Например, функция decrypt() может расшифровать учетные данные.

Обратите внимание

  • Доступ к консоли контролируется разрешением Administer.

  • Консоль не предоставляет никаких административных элементов управления, чтобы помешать пользователю (или администратору) повлиять на части инфраструктуры Pipeliner. Предоставление обычному пользователю доступа к консоли скриптов по существу совпадает с предоставлением ему прав администратора в Pipeliner.

  • Доступ к консоли пользователи получают с разрешения администратора, так как с помощью консоли можно настроить любой параметр Pipeliner, например, отключить безопасность, перенастроить безопасность или открыть "backdoor" на операционной системе хоста полностью вне процесса Pipeliner. Поэтому рекомендуется тщательно контролировать доступ к консоли.

  • Из-за возможностей, предоставляемых консолью, Pipeliner и его агенты никогда не должны запускаться от имени пользователя root (в Linux) или системного администратора в любой другой операционной системе.

Обработка ошибок#

Любые потенциально ошибочные операции нужно оборачивать в try-catch-finally, для того, чтобы иметь возможность управлять ходом выполнения задания.

В зависимости от серьезности ошибки можно менять значение переменной currentBuild.result на статусы: успешный, неуспешный или нестабильный.

Пример с запуском тестов:

try {
  // пытаемся запустить тесты
  // даже если тесты прошли успешно, утилита вернет код <> 0, нужно это обработать и принять решение об успешности тестирования
  withCredentials([
    [$class: 'UsernamePasswordMultiBinding', credentialsId: 'ESBavto-WAS', passwordVariable: 'p', usernameVariable: 'u']
  ]) {
    //def RQMRetCode = bat(script: "java -jar tool\\RQMExecutionTool.jar -tserId=${props.tserId} -projectName=${props.Project} -publicURI=https://localhost:8080/example -user=${env.u} -password=${env.u} -scriptId=${props.scriptId} -suiteStepAdapterIds=BDD-%COMPUTERNAME% -exitOnComplete=true -verbose=true", returnCode: true)
    def RQMRes = bat(script: "java -jar tool\\RQMExecutionTool.jar -tserId=${props.tserId} -projectName=${props.Project} -publicURI=https://localhost:8080/example -user=${env.u} -password=${env.u} -scriptId=${props.scriptId} -suiteStepAdapterIds=BDD-%COMPUTERNAME% -exitOnComplete=true -verbose=true", returnCode: true)
  }
} catch (hudson.AbortException RQMErr) {
  // для отладки, вывод кода в лог
  println RQMErr.getMessage()
  // меняем статус сборки в зависимости от ошибки
  println RQMErr.getMessage()
  def t = RQMErr.getMessage()
  // plrintln исключительно для отладки
  // Если приложение вернуло код, отличный от успешного (в данном случае это 20), помечаем этот pipeline как UNSTABLE через переменную currentBuild.result
  switch (t) {
    case 'script returned exit code 20':
      println(t)
      echo 'autoregress done'
      break
    case 'script returned exit code 21':
      println(t)
      println "Test failed."
      err = RQMErr
        // делаем пометку, что сборка не идеальна
      currentBuild.result = "UNSTABLE"
      error t
      break
    case 'script returned exit code 3':
      println(t)
      println "Login failed. Either username or password is wrong."
      err = RQMErr
      currentBuild.result = "UNSTABLE"
      error t
      break
    default:
      println(t)
      println "Test execution finished with error"
      println t
      err = RQMErr
      currentBuild.result = "UNSTABLE"
      error t
  }
} finally {
  // шаги с отправкой писем с результатом работы stage success/unstable
  libs.sendEmailNotification(currentBuild.result, stagename, recipients_email, details, "", "")
  echo currentBuild.result
}

Часто встречающиеся проблемы и пути их устранения#

Ошибки нехватки памяти#

OutOfMemoryError ошибки могут возникать по разным причинам:

  • Размер данных Pipeliner растет, требуя большего пространства кучи. В этом случае требуется выделить больше места.

  • Pipeliner временно обрабатывает большой объем данных (например, отчеты об испытаниях), что требует большего объема памяти. В этом случае также необходимо выделить больше места.

  • У Pipeliner происходит утечка памяти.

  • Ядру операционной системы не хватает виртуальной памяти.

Для определения, в какую категорию OutOfMemoryError попадает ошибка, можно использовать следующие подходы:

  • Используйте VisualVM. Подключитесь к работающему экземпляру и наблюдайте за использованием памяти. Если при загрузке Pipeliner не хватает памяти, выделите больше памяти. Если при работе Pipeliner медленно растет использование памяти — это утечка памяти.

  • Если OutOfMemoryError выводится примерно в одной и той же фазе в сборке, выделите больше памяти.

  • В случаях, когда виртуальной памяти не хватает, система может принудительно прекратить выполнение Pipeliner или прервать отдельные сборки. Если это происходит в Linux, то видно, что сборка завершается с кодом выхода 137 (128+ номер сигнала для SIGKILL). Выходные данные команды dmesg будут отображать сообщения журнала, подтверждающие действия, предпринятые системой.

Если это утечка памяти, разработчикам Pipeliner нужно получить heap dump, чтобы решить проблему. Есть несколько способов сделать это:

  • Запустите JVM -XX:+HeapDumpOnOutOfMemoryError, чтобы JVM автоматически создавала heap dump при достижении OutOfMemoryError.

  • Запустите jmap -dump:live,file=/tmp/jenkins.hprof pid, где pid — это идентификатор процесса целевого процесса Java.

  • Используйте VisualVM. Подключитесь к работающему экземпляру и получите heap dump.

  • Если ваш Pipeliner работает на http://{Pipeliner_address}, перейдите на http://{Pipeliner_address}/heapDump в своем браузере, чтобы получить загруженный heap dump.

  • Также можно воспользоваться профилировщиком Java, который предлагает данный функционал.

После получения heap dump разместите его в каком-либо месте, затем откройте задачу (или найдите повторяющуюся задачу) и прикрепите к ней указатель. Обратите внимание, что heap dump может содержать конфиденциальную информацию различного рода.

Если полный heap dump слишком большой, попробуйте получить гистограмму кучи (jmap -histo:live pid).

Прочие ошибки#

В случае прочих сбоев диагностику ситуации следует начинать с проверок:

  • подключения клиента (компьютера пользователя) к сети;

  • доступности сервера Pipeliner - проверка доступности страниц сервиса;

  • в случае неудачной аутентификации необходимо обратить внимание на корректность введенного логина/пароля при входе в Pipeliner.