Используйте легкий исполнитель для декларативной стадии конвейера (агент none)
Я использую Jenkins Pipeline с декларативным синтаксисом, в настоящее время со следующими этапами:
- Подготовка
- Сборка (два параллельных набора шагов)
- Тест (также два параллельных набора шагов)
- Спросите, где/где развернуть
- Deploy
Для шагов 1, 2, 3 и 5 мне нужно и агента (исполнителя), потому что они выполняют фактическую работу в рабочей области. Для шага 4 мне это не нужно, и я бы не хотел блокировать моих доступных исполнителей во время ожидания ввода пользователя. Это, по-видимому, упоминается как "облегченный" или "легкий" исполнитель для классического синтаксиса сценария, но я не могу найти никакой информации о том, как добиться этого с помощью декларативного синтаксиса.
До сих пор я пробовал:
- Настройка агента непосредственно в параметрах конвейера, а затем установка
agent none
на сцене. Это не влияет, и конвейер работает как normalt, блокируя исполнитель во время ожидания ввода. В документации также упоминается, что это не будет иметь никакого эффекта, но я думал, что все равно сделаю это.
- Настройка
agent none
в параметрах конвейера, а затем установка агента для каждого этапа, кроме # 4. К сожалению, но, как ожидается, это выделяет новое рабочее пространство для каждого этапа, что, в свою очередь, требует, чтобы я запихнул и разблокировал. Это бесполезно и дает дополнительные проблемы на параллельных этапах (2 и 3), потому что я не могу иметь код вне конструкции parallel
. Я предполагаю, что параллельные шаги выполняются в одном и том же рабочем пространстве, поэтому удержание/нерест в обоих случаях приведет к неудачным результатам.
Вот контур моего файла Jenkins:
pipeline {
agent {
label 'build-slave'
}
stages {
stage("Prepare build") {
steps {
// ...
}
}
stage("Build") {
steps {
parallel(
frontend: {
// ...
},
backend: {
// ...
}
)
}
}
stage("Test") {
steps {
parallel(
jslint: {
// ...
},
phpcs: {
// ...
},
)
}
post {
// ...
}
}
stage("Select deploy target") {
steps {
script {
// ... code that determines choiceParameterDefinition based on branch name ...
try {
timeout(time: 5, unit: 'MINUTES') {
deployEnvironment = input message: 'Deploy target', parameters: [choiceParameterDefinition]
}
} catch(ex) {
deployEnvironment = null
}
}
}
}
stage("Deploy") {
when {
expression {
return binding.variables.get("deployEnvironment")
}
}
steps {
// ...
}
}
}
post {
// ...
}
}
Мне что-то не хватает, или это просто невозможно в текущей версии?
Ответы
Ответ 1
Настройка agent none
на верхнем уровне, затем agent { label 'foo' }
на каждом этапе, с agent none
снова на этапе input
, похоже, будет работать как ожидалось для меня.
то есть. Каждый этап, выполняющий некоторую работу, работает на одном и том же агенте, а этап input
не использует исполнителя для любого агента.
pipeline {
agent none
stages {
stage("Prepare build") {
agent { label 'some-agent' }
steps {
echo "prepare: ${pwd()}"
}
}
stage("Build") {
agent { label 'some-agent' }
steps {
parallel(
frontend: {
echo "frontend: ${pwd()}"
},
backend: {
echo "backend: ${pwd()}"
}
)
}
}
stage("Test") {
agent { label 'some-agent' }
steps {
parallel(
jslint: {
echo "jslint: ${pwd()}"
},
phpcs: {
echo "phpcs: ${pwd()}"
},
)
}
}
stage("Select deploy target") {
agent none
steps {
input message: 'Deploy?'
}
}
stage("Deploy") {
agent { label 'some-agent' }
steps {
echo "deploy: ${pwd()}"
}
}
}
}
Однако нет никакой гарантии, что использование одной и той же метки агента внутри Pipeline всегда будет работать в том же рабочем пространстве, например. как другая сборка той же работы, в то время как первая сборка ожидает на input
.
Вам нужно будет использовать stash
после шагов сборки. Как вы заметили, в настоящий момент это невозможно сделать с помощью parallel
, поэтому вам придется дополнительно использовать блок script
, чтобы написать фрагмент сценария для сценария для блокировки/блокировки после/перед параллелью шаги.
Ответ 2
Существует обходной путь для использования того же ведомого билда на других этапах. Вы можете установить переменную с именем узла и использовать ее в других.
то есть:
pipeline {
agent none
stages {
stage('First Stage Gets Agent Dynamically') {
agent {
node {
label "some-agent"
}
}
steps {
echo "first stage running on ${NODE_NAME}"
script {
BUILD_AGENT = NODE_NAME
}
}
}
stage('Second Stage Setting Node by Name') {
agent {
node {
label "${BUILD_AGENT}"
}
}
steps {
echo "Second stage using ${NODE_NAME}"
}
}
}
}