Делаем Jenkins Pipeline: шаг за шагом
Привет! Если ты обратил внимание на этот материал, то значит ты начинаешь разбираться в мире Jenkins. Самым сложным в любом деле является начало. На первом этапе окружает много незнакомых и непонятных терминов, сложно понять логику процесса и последовательность действий. Кажется, что это какая-то магия. Чтобы первые шаги были чуточку легче, я опишу простой пример, который можно использовать в качестве основы для реальных задач.
Я буду отталкиваться от того что у тебя уже установлен Jenkins. Установка Jenkins’а неплохо описана и показана в сети. Мы же будем смотреть на то, как создается Jenkins Pipeline или труба (конвейер) Jenkins.
Что вообще такое Jenkins? Jenkins — это крутая программа, которая реализует практики DevOps. Практики DevOps, в свою очередь, это логичные действия, которые позволяют повысить качество создаваемых продуктов. Под «качеством» будем понимать сразу много преимуществ – уменьшение количества ошибок в продукте, снижение Time-to-Market, повышение пользовательской лояльности и т.д.
Jenkins является «конвейером» поставки ПО от среды разработки в промышленную среду. «Конвейер», конечно же, условный. Jenkins выполняет шаг за шагом простейшие операции над кодом словно это автомобильный завод, на котором ваш фольксваген или форд движется по цехам и проходит разные этапы превращения металла в автомобиль. Такой «конвейер» в Jenkins называют Pipeline.
О DevOps и его практиках
DevOps, грубо говоря, регламентирует «завод» и «конвейер» на нём.
Одной из практик DevOps является CI/CD/CDP. Эта практика описывает шаги «конвейера».
CI (Continuous Integration, непрерывная интеграция) – начальная стадия «конвейера» по сборке кода и загрузке собранного ПО в среду разработки.
CD (Continuous delivery, непрерывная поставка) – является продолжением CI. В этой практике производится автоматизированное развертывание на тестовую среду продукта и разнообразные тесты над ним.
CDP (Continuous Deployment, непрерывное развертывание) – поставка результатов работы CI и CD практик в промышленную среду.
Jenkins, в свою очередь, может реализовать CI/CD/CDP на практике.
Описание примера
Теперь, имея представление что такое Jenkins и для чего он нужен, сделаем тестовую трубу, которая реализует в очень урезанном виде CI/CD практику.
В качестве разворачиваемого продукта будем использовать SSIS-пакет. SSIS (SQL Server Integration Services) – это инструмент создания решений по интеграции и преобразованию данных. То есть решение по переносу данных из одного источника в другой с возможностью преобразования этих данных в процессе переноса.
Подобных примеров в сети я почти не встречал, поэтому убью сразу двух зайцев – построю трубу Jenkins на интересном примере из моей практики. Принцип создания труб одинаковый, поэтому вы сможете применить пример из статьи для своих целей.
Чтобы было ещё интереснее, сделаем задачу со звёздочкой – в одном SSIS-проекте будет сразу несколько SSIS-пакетов.
Опишу шаги, которые будет делать труба:
1) Чекаут из Git (в моём случае Bitbucket)
2) Сборка SSIS-проекта
3) Развертывание собранного файла проекта в среду разработки.
Мой подопытный SSIS-кролик выглядит следующим образом:
Внутри проекта «AUDIT_Import_ALL» находится четыре SSIS-пакета с расширением «.dtsx». Если этот проект собрать, то получится один файл с именем «AUDIT_Import_ALL» и расширением «.ispac». Данный файл предназначен для развертывания проекта в MS SQL Server.
Подготовительные шаги
Проект «AUDIT_Import_ALL» загружен в Bitbucket. В репозиторий проекта я добавлю папку, содержащую Jenkinsfile.
Jenkinsfile – это простой текстовый файл с кодом на языке Groovy, который используется для конфигурации трубы Jenkins.
Теперь я создам тестовую трубу в самом Jenkins. Для этого на главной странице пространства Jenkins нажимаю «New Item», далее выбираю Pipeline и задаю имя.
После нажатия «ОК», открывается окно с настройками. Не будем подробно останавливаться на этом окне. Для тестового примера мне никакие настройки здесь не нужны, кроме раздела с расширенными настройками. А именно, окно настройки «Pipeline».
В нём я свяжу Jenkinsfile, который находится в Bitbucket, с только что созданной трубой Jenkins. Для этого в пункте «Definition» выбираем «Pipeline script from SCM». Этим пунктом я сообщаю Jenkins что мой Jenkinsfile лежит в SCM (source control management – система контроля версий).
На следующем шаге я выбираю SCM, где лежит мой файл. В моём случае это Git (Bitbucket). Далее я прописываю путь до репозитория в SSH формате (возможно и в HTTPS) и указываю учетные данные в поле «Credentials» (или добавляю новую учетную запись через кнопку «Add»).
Jenkinsfile лежит в master-ветке репозитория в Bitbucket, поэтому я не трогаю пункт «Branch Specifier (blank for ‘any’)». Так же, не трогаю следующие два пункта. А вот пункт «Script Path» мне необходимо поменять, потому что по умолчанию Jenkins будет искать Jenkinsfile в корне репозитория. Отдельная папка нужна затем, что файлов для работы Jenkins-трубы может быть несколько и содержать их в корне проекта будет просто неудобно.
Jenkins SSIS стенд
Хочу затронуть архитектурное решение моего Jenkins-стенда. Для тех, кто не будет строить DevOps для SSIS, можно перейти сразу к следующему разделу.
Архитектурно Jenkins строится по принципу master-slave. Есть один ведущий узел, который управляет множеством ведомых. У меня уже была развернута master-нода Jenkins. К ней я подключил slave-ноду, которая была создана под задачу DevOps SSIS. На этом сервере находится программа SSISBuild.exe, предоставляемая Microsoft как раз для наших нужд. SSISBuild предназначена для удаленной сборки SSIS-проектов и не требует установленной Visual Studio или среды выполнения SSIS.
Сервер, куда я буду развертывать SSIS-проект, содержит установленный MS SQL Server с установленной службой Integration Services. На этом сервере установлена вторая программа для DevOps SSIS – SSISDeploy.exe. SSISDeploy предназначена для развертывания файлов проектов (файлов с расширением ispac).
Более подробную информацию о SSISBuild и SSISDeploy вы сможете найти по ссылке.
Jenkinsfile
Итак, труба настроена, связь с Bitbucket установлена, необходимые сервера на связи. Осталось совсем чуть-чуть до запуска. Разберем Jenkinsfile чтобы понимать, как будут происходить те шаги, которые я описал в начале статьи.
Наиболее фундаментальной частью конвейера является «step». По сути, шаги говорят Jenkins, что делать, и служат базовым строительным блоком для синтаксиса конвейеров.
Все операции с конвейером должны быть заключены в блок «pipeline»:
Блок «pipeline» содержит разделы. Первым разделом является «agent». Раздел «agent» указывает, где будет выполняться труба Jenkins. Раздел должен быть определен на верхнем уровне внутри блока «pipeline».
В моём случае конвейер будет работать на сервере TestNode:
Раздел «options» позволяет настраивать параметры конвейера непосредственно из Jenkinsfile. Эти параметры также можно задавать в графическом интерфейсе Jenkins.
Раздел «parameters» задает список параметров, которые пользователь должен предоставить при запуске трубы. Заданные пользователем значения становятся доступными для шагов конвейера через объект params. Я создам два булевых параметра, с помощью которых можно будет управлять запуском шагов конвейера:
Раздел «environment» определяет глобальные и локальные (в пределах конкретного «step») переменные в Jenkinsfile. Глобальные переменные удобно использовать для подстановки статических значений:
Раздел «stages» является местом, где будет происходить основная часть работы конвейера. Раздел делится на этапы, которые содержат описание шагов. У меня будет три этапа:
Теперь рассмотрим шаги на каждом этапе.
Раздел «post» определяет дополнительные действия, которые будут выполняться после завершения работы основного кода конвейера или этапа (в зависимости где стоит post).
На этом мой блок «pipeline» в Jenkinsfile заканчивается. Далее располагается метод «PrintStage», который встречался на этапах Build и Deploy:
Запуск конвейера
Теперь всё готово к запуску. Открываю окно нашего конвейера и нажимаю кнопку «Собрать с параметрами».
Откроется окно с параметрами, которые я определил в разделе «parameters». Выбираю этапы, которые хочу запустить и нажимаю «собрать».
Далее, труба начинает собираться и если всё сделано правильно, то Jenkins нарисует красивую картинку:
Как добавить учетную запись в Jenkins
Для этого на главной странице вашего пространства нажмите кнопку «Credentials», далее выбрать «Folder».
Наведите курсор на пункт «Global credentials (unrestricted)» и у вас появится «галочка» для вызова выпадающего списка. Нажмите на неё. Всплывет маленькое окошко «Add credentials» — нажимайте!
Здесь вы можете задать вашу учетную запись. В моём примере с учетной записью WinRM, я использовал «Secret text» для хранения пароля.
По итогу мы сделали трубу, которая собирает и деплоит SSIS-пакеты на MS SQL Server. Данный пример является учебным , но его можно взять за основу и доработать под ваши задачи. Например, если вы делаете веб-приложение на ASP.NET, то вместо ssisdeploy можно использовать webdeploy. По аналогии можно добавить шаги с разнообразными тестами, созданием release notes, загрузкой дистрибутива в централизованное хранилище и т.д.
Какие преимущества даёт Jenkins? Он автоматизирует многие рутинные процессы, связанные с разработкой программного обеспечения. Например, запуск трубы с прохождение различных тестов при коммите в нужную ветку в Bitbucket. Такой подход уменьшит количество ошибок. Применение Jenkins объединяет процессы сборки, тестирования и внедрения и создает четко выстроенный подход к созданию продукта.
Буду рад, если моя статья была кому-то полезна.
Если у вас остались вопросы, оставляйте их в комментариях – я обязательно отвечу.
Core Concepts¶
Below are some core concepts to understand before building pipelines in Jenkins.
- Pipeline as Code
- Step
- Master vs Nodes
- Checkout
- Workspace
- Stage
- Sandbox and Script Security
- Java vs. Groovy
- Env (object)
- Stash & archive
- Credentials
- Tools & Build Environment
- Pipeline Syntax Page
Terminology¶
The terminology used in this page is based upon the terms used by Cloudbees as related to Jenkins.
If in doubt, please consult the Jenkins Glossary.
Pipeline as Code¶
A single task; fundamentally steps tell Jenkins what to do inside of a Pipeline or Project.
Consider the following piece of pipeline code:
The only execution that happens (almost) exclusively on the node (or build slave) are the isUnix(), sh and bat shell commands.
Those specific tasks are the steps in pipeline code.
Master vs Nodes¶
There are many things to keep in mind about Pipelines in Jenkins. By far the most important are those related to the distinction between Masters and Nodes.
Aside from the points below, the key thing to keep in mind: Nodes (build slaves) are designed to executes task, Masters are not.
Except for the steps themselves, all of the Pipeline logic, the Groovy conditionals, loops, etc execute on the master. Whether simple or complex! Even inside a node block!
Steps may use executors to do work where appropriate, but each step has a small on-master overhead too.
Pipeline code is written as Groovy but the execution model is radically transformed at compile-time to Continuation Passing Style (CPS).
This transformation provides valuable safety and durability guarantees for Pipelines, but it comes with trade-offs:
- Steps can invoke Java and execute fast and efficiently, but Groovy is much slower to run than normal.
- Groovy logic requires far more memory, because an object-based syntax/block tree is kept in memory.
Pipelines persist the program and its state frequently to be able to survive failure of the master.
Source: Sam van Oort, Cloudbees Engineer
A machine which is part of the Jenkins environment and capable of executing Pipelines or Projects. Both the Master and Agents are considered to be Nodes.
Master¶
The central, coordinating process which stores configuration, loads plugins, and renders the various user interfaces for Jenkins.
What to do?¶
So, if Pipeline code can cause big loads on Master, what should we do than?
- Try to limit the use of logic in your groovy code
- Avoid blocking or I/O calls unless explicitly done on a slave via a Step
- If you need heavy processing, and there isn’t a Step, create either a
- Or use a CLI tool via a platform independent language, such as Java or Go
If need to do any I/O, use a plugin or anything related to a workspace, you need a node. If you only need to interact with variables, for example for an input form, do this outside of a node block. See Pipeline Input for how that works.
Workspace¶
A disposable directory on the file system of a Node where work can be done by a Pipeline or Project. Workspaces are typically left in place after a Build or Pipeline run completes unless specific Workspace cleanup policies have been put in place on the Jenkins Master.
The key part of the glossary entry there is disposable directory. There are absolutely no guarantees about Workspaces in pipeline jobs.
That said, what you should take care of:
- always clean your workspace before you start, you don’t know the state of the folder you get
- always clean your workspace after you finish, this way you’re less likely to run into problems in subsequent builds
- a workspace is a temporary folder on a single node’s filesystem: so every time you use node<> you have a new workspace
- after your build is finish or leaving the node otherwise, your workspace should be considered gone: need something from? stash or archive it!
Checkout¶
There are several ways to do a checkout in the Jenkins pipeline code.
In the groovy DSL you can use the Checkout dsl command, svn shorthand or the git shorthand.
If you use a pipeline from SCM, multi-branch pipeline or a derived job type, beware! Only the Jenkinsfile gets checked out. You still need to checkout the rest of your files yourself!
However, when using pipeline from SCM, multi-branch pipeline or a derived job type. You can use a shorthand: checkout scm. This checks out the scm defined in your job (where the Jenkinsfile came from).
Stage¶
Stage is a step for defining a conceptually distinct subset of the entire Pipeline, for example: «Build», «Test», and «Deploy», which is used by many plugins to visualize or present Jenkins Pipeline status/progress.
The stage «step» has a primary function and a secondary function.
- Its primary function is to define the visual boundaries between logically separable parts of the pipeline.
- For example, you can define SCM, Build, QA, Deploy as stages to tell you where the build currently is or where it failed.
- Just like most programming languages, code blocks are a more than just syntactic sugar, they also limit the scope of variables.
Stages in classic view¶
Stages in Blue Ocean view¶
Sandbox and Script Security¶
In Jenkins some plugins — such as the pipeline plugin — allow you to write groovy code that gets executed on the master.
This means you could run code on the master that accesses the host machine with the same rights as Jenkins. As is unsafe, Jenkins has some guards against this in the form the sandbox mode and the script security.
When you create a pipeline job, you get a inline code editor by default. If you’re an administrator you get the option to turn the «sandbox» mode of.
If you use a pipeline from SCM or any of the higher abstraction pipeline job types (Multibranch Pipeline, BitBucket Team) you are always running in sandbox mode.
When you’re in sandbox mode, your script will run past the script security. This uses a whitelisting technique to block dangerous or undesired methods, but is does so in a very restrictive manner.
It could be you’re doing something that is safe but still gets blocked. An administrator can then go to the script approval page (under Jenkins Administration) and approve your script.
For more details, please consult Script Security plugin page.
Example error¶
There are three ways to deal with these errors.
- go to manage jenkins → script approval and approve the script
- use a Shared Library
- use a CLI tool/script via a shell command to do what you need to do
Java vs. Groovy¶
The pipeline code has to be written in groovy and therefor can also use java code. Two big difference to note:
- the usage of double quoted string (gstring, interpreted) and single quoted strings (literal)
- def abc = ‘xyz’ # is a literal
- echo ‘$abc’ # prints $abc
- echo «$abc» # prints xyz
Unfortunately, due to the way the Pipeline code is processed, many of the groovy features don’t work or don’t work as expected.
Things like the lambda’s and for-each loops don’t work well and are best avoided. In these situations, it is best to keep to the standard syntax of Java.
For more information on how the groovy is being processed, it is best to read the technical-design.
Env (object)¶
The env object is an object that is available to use in any pipeline script.
The env object allows you to store objects and variables to be used anywhere during the script. So things can be shared between nodes, the master and nodes and code blocks.
Why would you want to use it? As in general, global variables are a bad practice. But if you need to have variables to be available through the execution on different machines (master, nodes) it is good to use this.
Also the env object contains context variables, such as BRANCH_NAME, JOB_NAME and so one. For a complete overview, view the pipeline syntax page.
Don’t use the env object in functions, always feed them the parameters directly. Only use it in the «pipeline flow» and use it for the parameters of the methods.
Stash & archive¶
If you need to store files for keeping for later, there are two options available stash and archive.
Both should be avoided as they cause heavy I/O traffic, usually between the Node and Master.
For more specific information, please consult the Pipeline Syntax Page.
Stash¶
Stash allows you to copy files from the current workspace to a temp folder in the workspace in the master. If you’re currently on a different machine it will copy them one by one over the network, keep this in mind.
The files can only be retrieved during the pipeline execution and you can do so via the unstash command.
Saves a set of files for use later in the same build, generally on another node/workspace. Stashed files are not otherwise available and are generally discarded at the end of the build. Note that the stash and unstash steps are designed for use with small files. For large data transfers, use the External Workspace Manager plugin, or use an external repository manager such as Nexus or Artifactory.
Archive & archiveArtifacts¶
Archives build output artifacts for later use. As of Jenkins 2.x, you may use the more configurable archiveArtifacts.
With archive you can store a file semi-permanently in your job. Semi as the files will be overridden by the latest build.
The files you archive will be stored in the Job folder on the master.
One usecase is to save a log file from a build tool.
Credentials¶
In many pipelines you will have to deal with external systems, requiring credentials.
Jenkins has the Credentials API which you can also utilize in the pipeline.
You can use do this via the Credentials and Credentials Binding plugins, the first is the core plugin the second provides the integration for the pipeline.
The best way to generate the required code snippet, is to go to the pipeline syntax page, select withCredentials and configure what you need.
For more examples, please consult Cloudbees’ Injecting-Secrets-into-Jenkins-Build-Jobs blog post.
Tools & Build Environment¶
Jenkins would not be Jenkins without the direct support for the build tools, such as JDK’s, SDK’s, Maven, Ant what have you not.
So, how do you use them in the pipeline?
Unfortunately, this is a bit more cumbersome than it is in a freestyle (or legacy) job.
You have to do two things:
- retrieve the tool’s location via the tool DSL method
- set the environment variables to suit the tool
Pipeline Syntax Page¶
Soooo, do I always have to figure out how to write these code snippets?
No, don’t worry. You don’t have to.
At every pipeline job type there is a link called «Pipeline Syntax».
This gives you a page with a drop down menu, from where you can select all the available steps.
Once you select a step, you can use the UI to setup the step and then use the generate button to give you the correct syntax.
Jenkins Pipeline: заметки об оптимизации. Часть 1

Меня зовут Илья Гуляев, я занимаюсь автоматизацией тестирования в команде Post Deployment Verification в компании DINS.
В DINS мы используем Jenkins во многих процессах: от сборки билдов до запуска деплоев и автотестов. В моей команде мы используем Jenkins в качестве платформы для единообразного запуска смоук-проверок после деплоя каждого нашего сервиса от девелоперских окружений до продакшена.
Год назад другие команды решили использовать наши пайплайны не только для проверки одного сервиса после его обновления, но и проверять состояние всего окружения перед запуском больших пачек тестов. Нагрузка на нашу платформу возросла в десятки раз, и Jenkins перестал справляться с поставленной задачей и стал просто падать. Мы быстро поняли, что добавление ресурсов и тюнинг сборщика мусора могут лишь отсрочить проблему, но не решат ее полностью. Поэтому мы решили найти узкие места Jenkins и оптимизировать их.
В этой статье я расскажу, как работает Jenkins Pipeline, и поделюсь своими находками, которые, возможно, помогут вам сделать пайплайны быстрее. Материал будет полезен инженерам, которые уже работали с Jenkins, и хотят познакомиться с инструментом ближе.
Что за зверь Jenkins Pipeline
Jenkins Pipeline — мощный инструмент, который позволяет автоматизировать различные процессы. Jenkins Pipeline представляет собой набор плагинов, которые позволяют описывать действия в виде Groovy DSL, и является преемником плагина Build Flow.
Скрипт для плагина Build Flow исполнялся напрямую на мастере в отдельном Java-потоке, который выполнял Groovy-код без барьеров, препятствующих доступу к внутреннему API Jenkins. Данный подход представлял угрозу безопасности, что впоследствии стало одной из причин отказа от Build Flow, и послужило предпосылкой для создания безопасного и масштабируемого инструмента для запуска скриптов — Jenkins Pipeline.
Подробнее об истории создания Jenkins Pipeline можно узнать из статьи автора Build Flow или доклада Олега Ненашева о Groovy DSL в Jenkins.
Как работает Jenkins Pipeline
Теперь разберемся, как работают пайплайны изнутри. Обычно говорят, что Jenkins Pipeline — совершенно другой вид заданий в Jenkins, непохожий на старые добрые freestyle-джобы, которые можно накликать в веб-интерфейсе. С точки зрения пользователя это, может, и выглядит так, но со стороны Jenkins пайплайны — набор плагинов, которые позволяют перенести описание действий в код.
Сходства Pipeline и Freestyle джобы
- Описание джобы (не шагов) хранится в файле config.xml
- Параметры хранятся в config.xml
- Триггеры тоже хранятся в config.xml
- И даже некоторые опции хранятся в config.xml
Правда в том, что параметры, описанные в Pipeline, автоматически добавятся в раздел настройки в веб-интерфейсе при запуске джобы. Верить мне можно потому, что этот функционал в последней редакции писал я, но об этом подробнее во второй части статьи.
Отличия Pipeline и Freestyle джобы
- На момент старта джобы Jenkins ничего не знает про агента для выполнения джобы
- Действия описываются в одном groovy-скрипте
Запуск Jenkins Declarative Pipeline
Процесс запуска Jenkins Pipeline состоит из следующих шагов:
- Загрузка описания задания из файла config.xml
- Старт отдельного потока (легковесного исполнителя) для выполнения задания
- Загрузка скрипта пайплайна
- Построение и проверка синтаксического дерева
- Обновления конфигурации задания
- Объединение параметров и свойств заданных в описании задания и в скрипте
- Сохранение описания задания в файловую систему
- Выполнение скрипта в groovy-песочнице
- Запрос агента для всего задания или отдельного шага
При старте pipeline-джобы Jenkins создает отдельный поток и направляет задание в очередь на выполнение, а после загрузки скрипта определяет, какой агент нужен для выполнения задачи.
Для поддержки данного подхода используется специальный пул потоков Jenkins (легковесных исполнителей). Можно заметить, что они выполняются на мастере, но не затрагивают обычный пул исполнителей:

Количество потоков в данном пуле не ограничено (на момент написания статьи).
Работа параметров в Pipeline. А также триггеров и некоторых опций
Обработку параметров можно описать формулой:

Из параметров джобы, которые мы видим при запуске, сначала удаляются параметры Pipeline из предыдущего запуска, а уже потом добавляются параметры заданные в Pipeline текущего запуска. Это позволяет удалить параметры из джобы, если они были удалены из Pipeline.
Как это работет изнутри?
Рассмотрим пример config.xml (файл, в котором хранится конфигурация джобы):
В секции properties находятся параметры, триггеры и опции, с которыми будет запускаться джоба. Дополнительная секция DeclarativeJobPropertyTrackerAction служит для хранения параметров, заданных только в пайплайне.
При удалении параметра из пайплайна, он будет удлён как из DeclarativeJobPropertyTrackerAction так и из properties, так как Jenkins будет знать, что параметр был определён только в пайплайне.
При добавлении параметра ситуация обратная, параметр добавится DeclarativeJobPropertyTrackerAction и properties, но только в момент исполнения пайплайна.
Именно поэтому если задать параметры только в пайплайне, то они будут недоступны при первом запуске.
Выполнение Jenkins Pipeline
Когда Pipeline-скрипт загружен и скомпилирован, начинается процесс выполнения. Но этот процесс состоит не только из выполнения groovy. Я выделил основные тяжеловесные операции, которые выполняются в момент исполнения джобы:
Выполнение Groovy-кода
Скрипт пайплайна всегда выполняется на мастере — об этом нельзя забывать, чтобы не создавать лишнюю нагрузку на Jenkins. На агенте исполняются только шаги, которые взаимодействуют с файловой системой агента или системными вызовами.

В пайплайнах есть замечательный плагин, который позволяет делать HTTP запросы. В добавок ответ можно сохранять в файл.
Изначально может показаться, что данный код должен полностью выполняться на агенте, послать с агента запрос, а ответ сохранить в файл result.json. Но всё происходит наоборот, и запрос выполняется с самого дженкинса, а для сохранения содержимое файла копируется на агент. Если дополнительная обработка ответа в пайплайне не требуется, то советую заменять такие запросы на curl:
Работа с логами и артефактами
Независимо от того, на каком агенте выполняются команды, логи и артефакты обрабатываются и сохраняются на файловую систему мастера в режиме реального времени.Если в пайплайне используются секреты (credentials), то перед сохранением логи дополнительно фильтруются на мастере.

Сохранение шагов (Pipeline Durability)
Jenkins Pipeline позиционирует себя как задача, которая стоит из отдельных кусочков, которые независимы и могут быть воспроизведены при падении мастера. Но за это приходится платить дополнительными записями на диск, потому что в зависимости от настроек задачи шаги с различной степенью детализации сериализуются и сохраняются на диск.

В зависимости от параметра живучести (pipeline durability) шаги графа пайплайна будут храниться в одном или нескольких файлах для каждого запуска джобы. Выдержка из документации:
В плагине workflow-support для хранения степов (FlowNode) используется класс FlowNodeStorage и его реализации SimpleXStreamFlowNodeStorage и BulkFlowNodeStorage.
- FlowNodeStorage использует кэширование в памяти для объединения операций записи на диск. Буфер автоматически записывается во время выполнения. Как правило, вам не нужно беспокоиться об этом, но имейте в виду, что сохранение FlowNode не гарантирует, что он будет немедленно записан на диске.
- SimpleXStreamFlowNodeStorage использует по одному небольшому XML-файлу для каждого FlowNode — хотя мы используем кеш с soft-reference в памяти для узлов, это приводит к гораздо худшей производительности при первом прохождении через степы (FlowNodes).
- BulkFlowNodeStorage использует один XML-файл большего размера со всеми FlowNodes в нем. Этот класс используется в режиме живучести PERFORMANCE_OPTIMIZED, который записывает гораздо реже. Как правило, это намного эффективнее, потому что одна большая потоковая запись выполняется быстрее, чем группа небольших записей, и сводит к минимуму нагрузку на ОС для управления всеми крошечными файлами.
Storage: in the workflow-support plugin, see the ‘FlowNodeStorage’ class and the SimpleXStreamFlowNodeStorage and BulkFlowNodeStorage implementations.
- FlowNodeStorage uses in-memory caching to consolidate disk writes. Automatic flushing is implemented at execution time. Generally, you won’t need to worry about this, but be aware that saving a FlowNode does not guarantee it is immediately persisted to disk.
- The SimpleXStreamFlowNodeStorage uses a single small XML file for every FlowNode — although we use a soft-reference in-memory cache for the nodes, this generates much worse performance the first time we iterate through the FlowNodes (or when)
- The BulkFlowNodeStorage uses a single larger XML file with all the FlowNodes in it. This is used in the PERFORMANCE_OPTIMIZED durability mode, which writes much less often. It is generally much more efficient because a single large streaming write is faster than a bunch of small writes, and it minimizes the system load of managing all the tiny files.
Сохранённые шаги можно найти в директории:
Итоги
Надеюсь, данный материал был интересен и помог лучше понять, что из себя представляют пайплайны и как они работают изнутри. Если у вас остались вопросы — делитесь ими ниже, буду рад ответить!
Во второй части статьи я рассмотрю отдельные кейсы, которые помогут найти проблемы с Jenkins Pipeline и ускорить ваши задачки. Узнаем, как решать проблемы параллельного запуска, рассмотрим параметры «живучести» и обсудим, зачем профилировать Jenkins.
Какая информация копируется на главный узел jenkins во время выполнения задачи

Меня зовут Илья Гуляев, я занимаюсь автоматизацией тестирования в команде Post Deployment Verification в компании DINS.
В DINS мы используем Jenkins во многих процессах: от сборки билдов до запуска деплоев и автотестов. В моей команде мы используем Jenkins в качестве платформы для единообразного запуска смоук-проверок после деплоя каждого нашего сервиса от девелоперских окружений до продакшена.
Год назад другие команды решили использовать наши пайплайны не только для проверки одного сервиса после его обновления, но и проверять состояние всего окружения перед запуском больших пачек тестов. Нагрузка на нашу платформу возросла в десятки раз, и Jenkins перестал справляться с поставленной задачей и стал просто падать. Мы быстро поняли, что добавление ресурсов и тюнинг сборщика мусора могут лишь отсрочить проблему, но не решат ее полностью. Поэтому мы решили найти узкие места Jenkins и оптимизировать их.
В этой статье я расскажу, как работает Jenkins Pipeline, и поделюсь своими находками, которые, возможно, помогут вам сделать пайплайны быстрее. Материал будет полезен инженерам, которые уже работали с Jenkins, и хотят познакомиться с инструментом ближе.
Что за зверь Jenkins Pipeline
Jenkins Pipeline — мощный инструмент, который позволяет автоматизировать различные процессы. Jenkins Pipeline представляет собой набор плагинов, которые позволяют описывать действия в виде Groovy DSL, и является преемником плагина Build Flow.
Скрипт для плагина Build Flow исполнялся напрямую на мастере в отдельном Java-потоке, который выполнял Groovy-код без барьеров, препятствующих доступу к внутреннему API Jenkins. Данный подход представлял угрозу безопасности, что впоследствии стало одной из причин отказа от Build Flow, и послужило предпосылкой для создания безопасного и масштабируемого инструмента для запуска скриптов — Jenkins Pipeline.
Подробнее об истории создания Jenkins Pipeline можно узнать из статьи автора Build Flow или доклада Олега Ненашева о Groovy DSL в Jenkins.
Как работает Jenkins Pipeline
Теперь разберемся, как работают пайплайны изнутри. Обычно говорят, что Jenkins Pipeline — совершенно другой вид заданий в Jenkins, непохожий на старые добрые freestyle-джобы, которые можно накликать в веб-интерфейсе. С точки зрения пользователя это, может, и выглядит так, но со стороны Jenkins пайплайны — набор плагинов, которые позволяют перенести описание действий в код.
Сходства Pipeline и Freestyle джобы
- Описание джобы (не шагов) хранится в файле config.xml
- Параметры хранятся в config.xml
- Триггеры тоже хранятся в config.xml
- И даже некоторые опции хранятся в config.xml
Правда в том, что параметры, описанные в Pipeline, автоматически добавятся в раздел настройки в веб-интерфейсе при запуске джобы. Верить мне можно потому, что этот функционал в последней редакции писал я, но об этом подробнее во второй части статьи.
Отличия Pipeline и Freestyle джобы
- На момент старта джобы Jenkins ничего не знает про агента для выполнения джобы
- Действия описываются в одном groovy-скрипте
Запуск Jenkins Declarative Pipeline
Процесс запуска Jenkins Pipeline состоит из следующих шагов:
- Загрузка описания задания из файла config.xml
- Старт отдельного потока (легковесного исполнителя) для выполнения задания
- Загрузка скрипта пайплайна
- Построение и проверка синтаксического дерева
- Обновления конфигурации задания
- Объединение параметров и свойств заданных в описании задания и в скрипте
- Сохранение описания задания в файловую систему
- Выполнение скрипта в groovy-песочнице
- Запрос агента для всего задания или отдельного шага
При старте pipeline-джобы Jenkins создает отдельный поток и направляет задание в очередь на выполнение, а после загрузки скрипта определяет, какой агент нужен для выполнения задачи.
Для поддержки данного подхода используется специальный пул потоков Jenkins (легковесных исполнителей). Можно заметить, что они выполняются на мастере, но не затрагивают обычный пул исполнителей:

Количество потоков в данном пуле не ограничено (на момент написания статьи).
Работа параметров в Pipeline. А также триггеров и некоторых опций
Обработку параметров можно описать формулой:

Из параметров джобы, которые мы видим при запуске, сначала удаляются параметры Pipeline из предыдущего запуска, а уже потом добавляются параметры заданные в Pipeline текущего запуска. Это позволяет удалить параметры из джобы, если они были удалены из Pipeline.
Как это работет изнутри?
Рассмотрим пример config.xml (файл, в котором хранится конфигурация джобы):
В секции properties находятся параметры, триггеры и опции, с которыми будет запускаться джоба. Дополнительная секция DeclarativeJobPropertyTrackerAction служит для хранения параметров, заданных только в пайплайне.
При удалении параметра из пайплайна, он будет удлён как из DeclarativeJobPropertyTrackerAction так и из properties, так как Jenkins будет знать, что параметр был определён только в пайплайне.
При добавлении параметра ситуация обратная, параметр добавится DeclarativeJobPropertyTrackerAction и properties, но только в момент исполнения пайплайна.
Именно поэтому если задать параметры только в пайплайне, то они будут недоступны при первом запуске.
Выполнение Jenkins Pipeline
Когда Pipeline-скрипт загружен и скомпилирован, начинается процесс выполнения. Но этот процесс состоит не только из выполнения groovy. Я выделил основные тяжеловесные операции, которые выполняются в момент исполнения джобы:
Выполнение Groovy-кода
Скрипт пайплайна всегда выполняется на мастере — об этом нельзя забывать, чтобы не создавать лишнюю нагрузку на Jenkins. На агенте исполняются только шаги, которые взаимодействуют с файловой системой агента или системными вызовами.

В пайплайнах есть замечательный плагин, который позволяет делать HTTP запросы. В добавок ответ можно сохранять в файл.
Изначально может показаться, что данный код должен полностью выполняться на агенте, послать с агента запрос, а ответ сохранить в файл result.json. Но всё происходит наоборот, и запрос выполняется с самого дженкинса, а для сохранения содержимое файла копируется на агент. Если дополнительная обработка ответа в пайплайне не требуется, то советую заменять такие запросы на curl:
Работа с логами и артефактами
Независимо от того, на каком агенте выполняются команды, логи и артефакты обрабатываются и сохраняются на файловую систему мастера в режиме реального времени.Если в пайплайне используются секреты (credentials), то перед сохранением логи дополнительно фильтруются на мастере.

Сохранение шагов (Pipeline Durability)
Jenkins Pipeline позиционирует себя как задача, которая стоит из отдельных кусочков, которые независимы и могут быть воспроизведены при падении мастера. Но за это приходится платить дополнительными записями на диск, потому что в зависимости от настроек задачи шаги с различной степенью детализации сериализуются и сохраняются на диск.

В зависимости от параметра живучести (pipeline durability) шаги графа пайплайна будут храниться в одном или нескольких файлах для каждого запуска джобы. Выдержка из документации:
В плагине workflow-support для хранения степов (FlowNode) используется класс FlowNodeStorage и его реализации SimpleXStreamFlowNodeStorage и BulkFlowNodeStorage.
- FlowNodeStorage использует кэширование в памяти для объединения операций записи на диск. Буфер автоматически записывается во время выполнения. Как правило, вам не нужно беспокоиться об этом, но имейте в виду, что сохранение FlowNode не гарантирует, что он будет немедленно записан на диске.
- SimpleXStreamFlowNodeStorage использует по одному небольшому XML-файлу для каждого FlowNode — хотя мы используем кеш с soft-reference в памяти для узлов, это приводит к гораздо худшей производительности при первом прохождении через степы (FlowNodes).
- BulkFlowNodeStorage использует один XML-файл большего размера со всеми FlowNodes в нем. Этот класс используется в режиме живучести PERFORMANCE_OPTIMIZED, который записывает гораздо реже. Как правило, это намного эффективнее, потому что одна большая потоковая запись выполняется быстрее, чем группа небольших записей, и сводит к минимуму нагрузку на ОС для управления всеми крошечными файлами.
Storage: in the workflow-support plugin, see the ‘FlowNodeStorage’ class and the SimpleXStreamFlowNodeStorage and BulkFlowNodeStorage implementations.
- FlowNodeStorage uses in-memory caching to consolidate disk writes. Automatic flushing is implemented at execution time. Generally, you won’t need to worry about this, but be aware that saving a FlowNode does not guarantee it is immediately persisted to disk.
- The SimpleXStreamFlowNodeStorage uses a single small XML file for every FlowNode — although we use a soft-reference in-memory cache for the nodes, this generates much worse performance the first time we iterate through the FlowNodes (or when)
- The BulkFlowNodeStorage uses a single larger XML file with all the FlowNodes in it. This is used in the PERFORMANCE_OPTIMIZED durability mode, which writes much less often. It is generally much more efficient because a single large streaming write is faster than a bunch of small writes, and it minimizes the system load of managing all the tiny files.
Сохранённые шаги можно найти в директории:
Итоги
Надеюсь, данный материал был интересен и помог лучше понять, что из себя представляют пайплайны и как они работают изнутри. Если у вас остались вопросы — делитесь ими ниже, буду рад ответить!
Во второй части статьи я рассмотрю отдельные кейсы, которые помогут найти проблемы с Jenkins Pipeline и ускорить ваши задачки. Узнаем, как решать проблемы параллельного запуска, рассмотрим параметры «живучести» и обсудим, зачем профилировать Jenkins.
Введение новичка в Дженкинс – CI/CD
В этом руководстве для начинающих мы познакомимся с Jenkins, сервером автоматизации CI/CD, а также запустим и автоматизируем процесс сборки простого проекта.
- Автор записи
Вступление
Появление быстро развивающейся разработки со многими методологиями, такими как Scrum , Agile и Канбан , привело к некоторым ключевым проблемам: разработчики, работающие небольшими шагами, потратили много времени в ожидании создания новой версии, достигли тестировщиков и в конечном итоге были развернуты. Процесс разработки был бы намного быстрее, если бы этот цикл исключал вмешательство человека везде, где это возможно.
Возникла идея серверов автоматизации . На протяжении многих лет многие решения появлялись и исчезали, но Дженкинс сумел выйти на первое место и стать стандартом, когда дело доходит до автоматизации. Хотя Дженкинс идеально подходит для простого планирования и выполнения командных или пакетных сценариев, будучи открытым исходным кодом и имея широкую поддержку сообщества, он обеспечивает легкую интеграцию со многими инструментами, платформами и фреймворками с более чем 1500 плагинами, что делает весь процесс легким.
Ключевые концепции Дженкинса
Чтобы понять, почему кто-то должен использовать Дженкинса, нам нужно понять, какие проблемы Дженкинс стремится решить.
Конвейер CI/CD
От начала до конца жизненный цикл программного обеспечения состоит из нескольких этапов. Автоматизация помогает нам преодолеть разрывы между ними, делая весь процесс бесшовным. В качестве примера возьмем простой, обычный рабочий процесс-сервер автоматизации будет прослушивать новые версии разработки, извлекать их и запускать соответствующие команды для создания и тестирования новой версии и, наконец, запускать новую версию в производство, если все прошло успешно.
Все эти этапы , которые состоят из меньших этапов , их сроки и порядок должны быть определены как единый конвейер .
Архитектура Контроллера-Агента
Чтобы распределить нагрузку на параллельные сборки и задачи, Дженкинс представляет архитектуру Контроллер-агент . “Контроллер” – сервер Дженкинса отвечает за администрирование проектов, конфигураций, пользователей и данных. “Агенты” могут быть вызваны для выполнения определенных этапов конкретного конвейера. Это дает множество преимуществ, таких как простота масштабирования, оптимальное аппаратное обеспечение (крупномасштабная математика или сложные процессы с данными), тестовые серверы и сборки для конкретной платформы.
Плагины
Плагины являются основой успеха Дженкинса. Любой разработчик Java может написать свой собственный плагин и поделиться им с сообществом. Дженкинс очень подчеркивает это и написал несколько очень подробных руководств по этому вопросу. Какой бы инструмент вы ни хотели использовать в конвейере, Дженкинс, вероятно, снабдит вас плагином, который облегчит весь процесс настройки и интеграции с этим инструментом.
Помимо аспекта рабочего процесса, существует множество плагинов, написанных непосредственно для управления самим Дженкинсом – от более красивого пользовательского интерфейса до более простого управления несколькими пользователями и их правами доступа.
Соглашения об именовании
На протяжении всего жизненного цикла Дженкинса номенклатура немного менялась, в том числе из-за того, что определенная терминология может рассматриваться как оскорбительная.
Несмотря на то, что некоторые соглашения об именах были введены много лет назад, сообщество по-прежнему использует их взаимозаменяемо. Чтобы избежать путаницы, вот несколько синонимичных терминов:
- Мастер
- Раб
- Работа
- Рабочий процесс
Более старая Ведущая/Ведомая архитектура была переименована в Контроллер/Агент архитектура из-за негативных коннотаций терминологии.
Установка
Существует множество способов установки Дженкинса. Наряду с установками для конкретной платформы многие платформы облачного хостинга предлагают предварительно настроенные пакеты Jenkins. Существует также официальный образ докера , а также общий файл Java war .
В этом руководстве будет описан процесс установки в Ubuntu 20.04 , хотя этот процесс не сильно отличается для Windows, Mac или других дистрибутивов. Проверьте страницу загрузки Дженкинса для вашей конкретной машины (или облачной службы).
Установка JDK/JRE
Будучи написанным на Java, Дженкинсу для запуска требуется Среда выполнения Java . Обратите внимание , что для OpenJDK доступны только версии 8 и 11 поддерживаются. Если вы хотите создавать Java-приложения с помощью Jenkins, вам нужно будет установить JDK вместо только JRE .
Давайте продолжим и установим openjdk-11-jdk :
Обновление списка источников и установка с помощью apt
Дженкинс недоступен в официальном репозитории Linux, поэтому нам придется добавить его собственный репозиторий. Мы собираемся установить версию LTS ( Долгосрочная поддержка ), которая обновляется каждые 12 недель, согласно веб-сайту Дженкинса.
Для острия, если, например, вы хотите разрабатывать плагины, удалите часть -stable из первой и второй строк ниже:
Наконец, мы можем продолжить и зарегистрировать Дженкинса в качестве сервиса и запустить его через терминал:
Доступ к Дженкинсу из браузера
По умолчанию Дженкинс размещен на порту 8080 .
Если вы установили Jenkins на локальном компьютере, доступ к нему можно получить из браузера, перейдя по адресу localhost:8080 . Если вы установили его на виртуальной машине, выполнение команды ifconfig (часть net-tools ) покажет IP-адрес виртуальной машины в вашей локальной сети.
При первом запуске Дженкинса требуется скрытый пароль. Его можно найти в /var/lib/Дженкинс/секреты/начальный пароль администратора , написанный на сервере. Извлеките и введите его, чтобы продолжить:
На второй странице выберите опцию Установить предлагаемые плагины . Установка плагина рассматривается далее в этом руководстве. Дождитесь установки плагинов, создайте учетную запись администратора, настройте URL-адрес Дженкинса (в нашем случае мы оставим его на localhost:8080 ) для доступа других пользователей, и вам будет представлена Панель мониторинга :
Использование Дженкинса
Дженкинс-это большой и сложный проект, и мы рассмотрим большинство наиболее важных функций.
Для этого мы рассмотрим три примера рабочего процесса:
- Использование браузера для создания проекта Maven с уведомлениями по электронной почте.
- Подключение к репозиторию GitHub и создание нашего приложения Maven с помощью файла репозитория Дженкинса .
- Используя jenkins-cli.jar Для выполнения повседневных задач, таких как управление заданиями, запуск сборок, проверка журналов и т.д. Из командной строки.
Мы будем использовать фиктивный проект Maven , созданный для этого руководства.
Простая Локальная Сборка
Чтобы легко настроить Maven – мы установим плагин Maven для Дженкинса.
Установка плагинов
Перейдите к опции Управление плагинами в разделе Управление Дженкинсом :
Выбрав вкладку Доступно , найдите “Maven” и установите флажок рядом. Выберите Установить без перезагрузки :
Дождитесь установки плагина, прежде чем продолжить.
Настройка Maven
В разделе Управление Дженкинсом перейдите в раздел Глобальная конфигурация инструмента . Прокрутите страницу вниз и добавьте установку Maven. Сохраните новые изменения.
Настройка электронной почты
Перейдите в Настройка системы в Управление Дженкинсом . Перейдите вниз к Уведомлению по электронной почте и настройте адрес электронной почты, который будет использовать Дженкинс. Обратите внимание , что Google и многие другие сервисы требуют настройки паролей для конкретных приложений из соображений безопасности.
Создание проекта
Выберите Новый элемент на боковой панели, дайте своему проекту имя и отметьте его как Проект Maven , прежде чем нажать ОК :
Git Essentials
Ознакомьтесь с этим практическим руководством по изучению Git, содержащим лучшие практики и принятые в отрасли стандарты. Прекратите гуглить команды Git и на самом деле изучите это!
В нижней части настройте файл POM расположение и настройте дополнительный шаг post для отправки уведомлений по электронной почте. Обратите внимание, что в Unix-подобных системах Дженкинс создает отдельного пользователя Дженкинс , поэтому могут потребоваться права доступа.
По умолчанию “Триггер” для отправки электронных писем является неудачной сборкой, но это можно изменить в Дополнительных настройках .
Запуск сборки
Настроив шаги, мы можем начать сборку. Боковая панель сообщит нам о ходе работы, а также покажет историю сборки. Неудачные сборки (#1) будут отображаться другим цветом.
Перейдите к параметру Вывод на консоль для получения более подробной информации:
Отслеживание репозитория GitHub и чтение файла Дженкинса
Нам пришлось рассмотреть более простой пример выше, чтобы понять, как работает Дженкинс. Следующий пример, безусловно, является наиболее частым способом настройки любого конвейера. Размещение конфигурации конвейера в текстовом файле и в CVS обеспечивает большую переносимость и возможность настройки.
Чтобы продвинуть наши изменения вверх по течению или при работе с частным репозиторием, нам придется аутентифицировать Дженкинса в GitHub. Мы также будем указывать Дженкинсу в направлении файла Дженкинса , который обычно содержится в корневом каталоге репозитория.
Файл Дженкинса – это просто файл, содержащий определение конвейера . Это должно быть проверено в системе управления версиями. Используя файл Дженкинса, Дженкинс может выполнять конвейеры.
Учетные данные GitHub
Чтобы безопасно получить доступ к GitHub, мы сгенерируем пару ключей , зарегистрируем закрытый ключ в Jenkins и запишем открытый ключ в список развертывания репозитория GitHub. Таким образом, мы можем иметь общедоступный код с открытым исходным кодом (или просто код, которым делятся коллеги), сохраняя при этом безопасность.
Для создания пары ключей мы будем использовать команду ssh-keygen :
Выберите, где хранить ключи, и установите пароль, если хотите.
Затем скопируйте закрытый ключ и перейдите на панель управления Дженкинса. Оттуда в разделе Управление Дженкинсом перейдите в Управление учетными данными -> Дженкинс -> Глобальные учетные данные -> Добавить учетные данные .
Выберите Имя пользователя SSH с закрытым ключом , вставьте ключ вместе с его парольной фразой и нажмите “ОК”.
Скопируйте открытый ключ и вставьте его в список ключей развертывания для вашего репозитория, расположенный по адресу https://github.com/user/repo/setting/keys/new . Дайте ему имя, установите флажок разрешить доступ на запись, если вы хотите, чтобы изменения были частью вашего конвейера, и нажмите Добавить клавишу .
Теперь пришло время создать проект и настроить его.
Создание проекта
На панели мониторинга перейдите в Новый элемент -> Многоответвленный конвейер . Дайте ему название и продолжайте. В разделе Источники филиалов выберите git , укажите имя источника, введите адрес хранилища и выберите соответствующие учетные данные, которые мы только что добавили. Сохраните изменения и продолжайте.
Мы заставим наш проект прослушивать изменения в репозитории, прокрутив вниз Сканирование триггеров конвейера с несколькими ответвлениями и установив флажок, выбрав 1 минуту в качестве желаемого интервала. Нажмите сохранить .
Примечание: Если рядом с Git вы видите GitHub в качестве опции , это означает, что у вас установлен плагин GitHub. Использование GitHub в качестве источника филиала требует, чтобы вы использовали комбинацию имени пользователя/пароля или имени пользователя/учетных данных токена – , которая обеспечивает доступ ко всем репозиториям, для которых авторизована учетная запись .
Маршрут Git также является более общим, поскольку процедура одинакова для любого удаленного репозитория Git – он не обязательно должен размещаться на GitHub, но, возможно, на сервере компании или в другой службе хостинга, такой как BitBucket и GitLab.
Пока наш проект будет проверять только изменения в нашем репозитории Git. Давайте напишем файл Дженкинса , чтобы Дженкинс знал, что он должен делать.
Написание файла Дженкинса
Чтобы определить набор процедур для запуска – конвейер – мы используем Файлы Дженкинса . Аналогично тому, как Docker использует Dockerfiles в качестве списка выполняемых команд, Дженкинс делает то же самое. Файлы Дженкинса используют синтаксис, похожий на заводной.
Давайте продолжим и напишем сценарий, похожий на Groovy, под названием “Файл Дженкинса” (без расширения) и зафиксируем/переместим его в корневой каталог вашего репозитория:
Этот простой синтаксис очень удобочитаем и достаточно понятен. Мы определили конвейер, который может быть выполнен любым доступным агентом . Существует только один этап ( ‘сборка’ ), на котором будет запущена команда оболочки для создания нашего кода.
После завершения этапа будет отправлено электронное письмо с уведомлением о завершении конвейера, содержащее некоторую информацию и ссылку на URL-адрес сборки для получения дополнительной информации.
Этот процесс или любой другой, если бы мы вносили изменения в файл Дженкинса, будет выполняться каждый раз, когда новая фиксация будет отправлена в репозиторий.
Служебные задачи в командной строке
Чтобы избежать использования браузера для повседневных задач, таких как запуск/остановка заданий, проверка вывода сборки на консоль или импорт/экспорт, нам нужно будет загрузить jenkins-cli.jar .
Он входит в комплект каждой установки Дженкинса:
Чтобы узнать, сможем ли мы подключиться к Дженкинсу, давайте введем следующую команду:
Соединение прошло успешно. Давайте свяжемся с пользователем с более широкими правами доступа, чтобы иметь возможность управлять проектами, плагинами, сборками и т.д. Чтобы избежать ввода пароля в консоли, можно настроить маркер API.
Создание маркера API
Давайте создадим токен для нашего пользователя-администратора, выполним действия на изображении и скопируем полученный текст:
Чтобы указать пользователя, мы будем использовать параметр -auth , который получает параметры [ПОЛЬЗОВАТЕЛЬ:СЕКРЕТНЫЙ | @ФАЙЛ] . Давайте поместим наше имя пользователя:токен в файл с именем учетные данные , на который мы будем ссылаться при подключении.
Список заданий и запущенных сборок
Чтобы перечислить и запустить наши задания, мы будем использовать команды list-jobs и build , а также использовать команду console для получения выходных данных. Обратите внимание , что Приложение GitHub Maven , будучи многоотраслевым проектом, требует указания ветви с синтаксисом project/branch , в нашем случае “GitHub Maven/Maven”:
Импорт/Экспорт Существующих Заданий
Все конфигурации в Jenkins определяются с помощью XML. Это позволяет легко повторно использовать существующие конфигурации или импортировать новые. Помимо определений проектов, глобальные конфигурации, такие как плагины и учетные данные, все написаны в XML.
jenkins-cli обеспечивает поддержку импорта и экспорта с помощью команд get-job и create-job , которые принимают XML в качестве параметра. Следующий код дублирует наш проект Maven в новый:
Вывод
Ключевой вывод здесь – это мощь автоматизации. Стоит вложить некоторое время и усилия в мощный инструмент, тщательно все настроить и больше никогда не тратить время на ручную работу. Отдача от инвестиций неоценима.
Это руководство предназначено для ознакомления с мощью и расширяемостью Дженкинса. Хорошо понимая основные принципы, ваши знания о Дженкинсе взлетят до небес, как только вы начнете экспериментировать с различными проектами, смешивая и сопоставляя различные инструменты сборки, языки и среды сборки.
Если вы хотите продолжить свое путешествие по Дженкинсу – вы можете ознакомиться с нашим руководством по планированию заданий в Дженкинсе или настройке закрытых проверок для проектов Spring Boot на GitHub .
Jenkins. Continuous Integration — это просто. Ну, почти

У нас есть сервер, на котором лежит множество проектов на WordPress и Magento CMS. Мне как PHP-разработчику была поставлена задача внедрить Jenkins для этих проектов, чтобы публикация изменений исходного кода на сервер происходила быстрее.
К чему нам Continuous Integration?
Вопрос повышения эффективности разработки и сопровождения программных продуктов для меня, как для веб-разработчика, всегда был и остается актуальным и интересным. Процессы сборки проекта и публикации его на сервер являются тем звеном, которое может быть легко автоматизированно при помощи средств Continuous Integration (CI).
CI многими уже давно и успешно применяется. Использование этого метода разработки позволяет существенно сократить время на публикацию проекта на сервер, сводя эту работу к исполнению нескольких консольных команд. Кроме того, при применении CI имеется возможность в любое время оперативно вернуться к предыдущей версии проекта, благодаря тому, что Continuous Integration неразрывно связана с репозиторием системы контроля версий.
Принцип работы CI довольно прост. В моем случае участвовало 3 сервера:
- Сервер системы контроля версий (СКВ), где хранится репозиторий с рабочей версией проекта, в который разработчик сохраняет свои изменения.
- Сервер Continuous Integration, на котором установлена одна из систем управления CI.
- Сервер, где развернута рабочая версия проекта.
Сразу после изменения репозитория в системе контроля версий, сервер СКВ инициирует выполнение задачи на сервере CI (как правило, с помощью веб-хука). Эта задача выполняет сборку и развертывание исходного кода из репозитория СКВ на сервер рабочей версии проекта.

Развертывание исходного кода из репозитория СКВ на сервер рабочей версии проекта
Более подробно о преимуществах, которые предоставляет использование Continuous Integration, можно почитать в этой статье.
Данное руководство собирает в себе информацию, достаточную для того, чтобы быстро сконфигурировать систему CI Jenkins и начать работу с ней. Также здесь представлена информация по настройке и организации взаимодействия такой популярной системы CI, как Jenkins и не менее известной системы контроля версий Git. В качестве веб-сервиса для git будем использовать GitHub.
Внимание, задача
Необходимо установить и настроить Jenkins таким образом, чтобы при push-е в репозиторий GitHub происходило обновление измененных файлов на сервере рабочей версии проекта. В наличии:
- Сервер Debian 8.2 x64.
- Система на локальной машине: Linux Mint 17.2.
Предварительным требованием является установленный git на обеих машинах. Про то, как его установить, можно прочитать здесь.
Решение
1. Установка Jenkins
Установку выполним на выделенном для CI сервере. Вводим следующие команды для добавления репозитория Jenkins в список репозиториев системы:
Обновим apt и установим Jenkins:
Теперь порт 8080 сервера CI будет «прослушиваться» Jenkins. Это значит, что при переходе в браузере по адресу <ip CI сервера: >8080, пользователь попадет в панель управления Jenkins. Конечно, такой способ доступа является не очень удобным, поэтому на сервере CI можно настроить доступ к Jenkins с помощью виртуальных хостов в Apache или Nginx.

Приветственное окно Jenkins
Следующим важным шагом является настройка прав доступа. Это очень важно, особенно если сервер доступен через Интернет. Без соответствующих настроек он будет открыт для всех.
2. Добавление администратора
Manage Jenkins → Configure Global Security (глобальная настройка безопасности).
1. Заполняем необходимую информацию:
- Enable security — true; //включить защиту;
- Jenkins’own user database — «Jenkins’ own user database»; //использовать для авторизации базу данных Jenkins;
- Authorization — «Matrix-based security»; //матричное распределение прав доступа (распределение прав на уровне проектов);
- User/group to add — «admin». //предоставляем пользователю «admin» право доступа в панель управления Jenkins.
2. Сохраняем настройки.
Теперь при попытке входа в панель управления Jenkins будет требовать от пользователя авторизоваться.
3. Создание пользователя для GitHub
Теперь необходимо создать учетные данные для доступа GitHub к серверу Jenkins.
В панели управления Jenkins переходим Manage Jenkins → Manage Users → Create User. Заполняем форму регистрации, идентичную той, которая была при регистрации администратора, нажимаем Sign Up.
После создания пользователя следует дать ему необходимые права. Для этого перейдем в Manage jenkins → Configure Global Security (настройка глобальной безопасности).
Из всех этих настроек нам необходима матрица безопасности.
Для начала добавим пользователя в эту матрицу. В поле «User/group to add» вводим имя созданного пользователя и нажимаем Add. Пользователь появится в матрице. Предоставим ему права на чтение и сборку. Для этого в подстолбцах Read и Build столбца «Job» напротив имени созданного пользователя устанавливаем чек-боксы и нажимаем Save.

Создание пользователя для GitHub
4. Установка плагина для GitHub
Переходим в Manage Jenkins → Manage Plugins → Вкладка «Available». Выбираем для установки три плагина:
- Github Authentication plugin;
- GitHub plugin;
- GitHub API Plugin.
Нажимаем на кнопку «Download now and install after restart» и ожидаем завершения установки.
5. Настройка сервера для работы с Jenkins
На продукционном сервере проекта (куда будет производиться автодеплой) необходимо создать пользователя «jenkins»:
Далее на сервере необходимо сгенерировать ssh ключи. От пользователя «jenkins» выполняем команду:
И вводим необходимую информацию.
Также для доступа необходимо добавить публичный ключ в файл. /jenkins/.ssh/authorized_keys (если файла нет, его необходимо создать)
Кроме этого требуется создать на GitHub открытый SSH ключ для данного сервера. О том, как это сделать, можно посмотреть здесь.
Данный этап завершен.
Если что-то по ssh-аутентификации является непонятным, рекомендую прочитать очень полезную статью на данную тему.
6. Настройка доступа к серверу
Для того чтобы Jenkins при автодеплое на сервере с рабочей версией проекта мог авторизовываться на нем, в панели управления требуется создать необходимые данные для аутентификации. Для этого в панели управления Jenkins переходим Credentials → Global credentials → Add Credentials и делаем следующее:
- В качестве Kind выбираем «SSH Username with private key»;
- Username — вводим имя созданного на сервере пользователя («jenkins») ;
- Private Key — «Enter directly», в текстовое поле копируем все содержимое файла приватного ключа jenkins-пользователя. («. /jenkins/.ssh/id_rsa»);
- Нажимаем «OK».
Теперь необходимо настроить подключение к серверу. Для этого в панели управления jenkins перейдем Manage Jenkins → Manage Nodes → New Node. Производим следующие действия:
- Вводим имя продукционного сервера (к примеру — «target»), устанавливаем «Dumb Slave», нажимаем «OK»;
- Вводим путь к корневой директории Jenkins на продукционном сервере. В качестве корневой директории на целевом сервере обычно выбирается директория пользователя jenkins («. /jenkins»);
- Вводим «Labels»; например — «target_server». Label — это метка, по которой задача будет привязываться к конкретному серверу;
- Host — вводим имя хоста, к которому будем обращаться;
- Credentials — выбираем ранее созданные данные для аутентификации;
- Нажимаем «Save».
Через некоторое время, подключение к серверу должно успешно установиться. Если все прошло успешно, в Manage Jenkins → Manage Nodes вы должны увидеть примерно следующую картину:

Настройка подключения к серверу
Если подключение не устанавливается, нажимаем на созданное подключение («target»), выбираем «Log» в левом навигационном меню и смотрим, что произошло не так.
Наиболее распространенными ошибками являются:
Первое решение — изменить в настройках подключения корневую директорию на домашнюю директорию пользователя Jenkins.
Второе решение — предоставить пользователю Jenkins права на запись и чтение указанной в настройках подключения директории.
7. Настройка хука GitHub
Для GitHub-репозитория, который будет использоваться, необходимо настроить веб-хук так, чтобы при обновлении репозитория, хук отсылал запрос на обновление Jenkins. Для этого:
- Переходим в созданный репозиторий на GitHub-е.
- «Settings» → «Webhooks & services».
- «Add webhook».
- Вводим «Payload URL» (куда будет обращаться GitHub). Он должен иметь следующий формат
8. Создание задачи Jenkins
Теперь необходимо создать задачу, которая будет выполняться при обновлении репозитория. В панели администрирования Jenkins делаем следующее:
- Нажимаем «New Item».
- Вводим название задачи в поле «Item name».
- Выбираем «Freestyle project» и нажимаем «OK».
- «Restrict where this project can be run» — вводим имя метки, которое было выбрано при добавлении сервера (например — «target_server»).
- «Source Code Management» — выбираем «Git» и вводим адрес репозитория в поле «Repository URL» (например — «git@github.com: TestCi/Continuous-integration.git»).
- В поле «Credentials» выбираем ранее созданные учетные данные.
- «Build Triggers» — «Build when a change is pushed to GitHub».
- «Build» — «Execute shell» (shell-скрипт будет выполняться при каждом push-е на github):
Первая строка производит синхронизацию на продукционном сервере рабочей директории Jenkins с целевой директорией проекта. Вторая строка —
установка владельца файлов проекта.
Чтобы не возникло никаких проблем с правами при выполнении команд, необходимо в файл sudoers с помощью команды visudo дописать пару строчек:
Вот и все! Теперь, при push-e кода в GitHub репозиторий, происходит автодеплой кода на продукционный сервер проекта. Цель достигнута!