Как подождать ввода пользователя в декларативный трубопровод без блокировки супертяжелого исполнителя

Я перестраиваю существующий конвейер сборки как декларативный конвейер jenkins (multi-branch-конвейер) и имеет проблемы с обработкой сборки.

После упаковки и хранения всех соответствующих файлов конвейер должен ждать ввода пользователем для запуска развертывания.

Если я просто добавлю шаг ввода, блокируется текущий build- node. Поскольку этот исполнитель довольно тяжелый, я бы хотел переместить этот шаг на более легкую машину.

Сначала я выполнил задание как сценарий и только создал два разных блока node('label'). есть ли способ сделать что-то подобное с декларативным синтаксисом?

node('spine') { 
    stage('builder') {
        sh 'mvn clean compile'
        stash name: 'artifact', includes: 'target/*.war'
    }
}
node('lightweight') {
    stage('wait') {
        timeout(time:5, unit:'DAYS') {
            input message:'Approve deployment?'
        }
    }
    // add deployment stages
}

Я уже пробовал пару вещей:

настройка агента на верхнем уровне и добавление дополнительной конфигурации агента на шаг распространения, но тогда у меня есть две исполнители, блокирующие, так как не установленная конструкция верхнего уровня node не останавливается.

Настройка agent none на верхнем уровне и настройка агентов на каждый шаг. то проверка git отсутствует на первом node.

РЕДАКТИРОВАТЬ 1

i переконфигурировал мой конвейер после вашего совета, в настоящее время он выглядит следующим образом:

pipeline {
agent none
tools {
    maven 'M3'
}
stages {
    stage('Build') {
        agent { label 'spine' }
        steps {
            checkout scm // needed, otherwise the workspace on the first step is empty
            sh "mvn clean compile"
        }
    }
    stage('Test') {
        agent { label 'spine' }
        steps {
            sh "mvn verify" // fails because the workspace is empty aggain
            junit '**/target/surefire-reports/TEST-*.xml'
        }
    }
}
}

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

РЕДАКТИРОВАТЬ 2

по-видимому, иногда шаги выполняются на одном и том же исполнителе, а иногда нет. (мы создаем рабочую рабочую станцию ​​на нашем кластере mesos/dcos по требованию, поэтому смена исполнительной средней сборки будет проблемой)

Я ожидал, что jenkins просто запустится с текущим исполнителем до тех пор, пока метка в определении агента не изменится.

Ответ 1

См. наилучшая практика 7: Dont: используйте ввод в блоке node. В декларативном конвейере выбор node выполняется с помощью директивы agent.

Документация здесь описывает, как вы можете определить none для конвейера, а затем использовать директиву уровня agent для запуска ступеней на требуемых узлах. Я тоже попробовал наоборот (определим глобальный агент на некотором node, а затем определим none на уровне сцены для ввода), но это не сработает. Если конвейер назначил ведомое устройство, вы не можете освободить ведомое устройство для одного или нескольких конкретных этапов.

Это структура нашего конвейера:

pipeline {
  agent none
  stages {
    stage('Build') {
      agent { label 'yona' }
      steps {
        ...
      }
    }
    stage('Decide tag on Docker Hub') {
      agent none
      steps {
        script {
          env.TAG_ON_DOCKER_HUB = input message: 'User input required',
              parameters: [choice(name: 'Tag on Docker Hub', choices: 'no\nyes', description: 'Choose "yes" if you want to deploy this build')]
        }
      }
    }
    stage('Tag on Docker Hub') {
      agent { label 'yona' }
      when {
        environment name: 'TAG_ON_DOCKER_HUB', value: 'yes'
      }
      steps {
        ...
      }
    }
  }
}

Как правило, этапы сборки выполняются на ведомом сборки с надписью "yona", но входной каскад выполняется на ведущем устройстве.

Ответ 2

Еще один способ сделать это - использовать директиву expression и beforeAgent, который пропускает шаг "решить" и избегает путаницы с глобальным "env":

pipeline {
    agent none

    stages {
        stage('Tag on Docker Hub') {
            when {
                expression {
                    input message: 'Tag on Docker Hub?'
                    // if input is Aborted, the whole build will fail, otherwise
                    // we must return true to continue
                    return true
                }
                beforeAgent true
            }

            agent { label 'yona' }

            steps {
                ...
            }
        }
    }
}

Ответ 3

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

источник: обсуждение в Используйте легкий исполнитель для стадии декларативного конвейера (агент none)

Обновлено: что вы подразумеваете под "проверкой git нет на первом node"? покажите, что у вас есть до сих пор для декларативного конвейера.

Ответ 4

Я знаю, что эта ветка старая, но я полагаю, что решение проблемы "Изменить 2", помимо сохранения, заключается в использовании вложенных этапов.

https://jenkins.io/blog/2018/07/02/whats-new-declarative-piepline-13x-sequential-stages/#running-multiple-stages-with-the-same-agent-or-environment-or-options

По данным этой страницы:

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

Вот приведенный пример:

pipeline {
    agent none

    stages {
        stage("build and test the project") {
            agent {
                docker "our-build-tools-image"
            }
            stages {
               stage("build") {
                   steps {
                       sh "./build.sh"
                   }
               }
               stage("test") {
                   steps {
                       sh "./test.sh"
                   }
               }
            }
            post {
                success {
                    stash name: "artifacts", includes: "artifacts/**/*"
                }
            }
        }

        stage("deploy the artifacts if a user confirms") {
            input {
                message "Should we deploy the project?"
            }
            agent {
                docker "our-deploy-tools-image"
            }
            steps {
                sh "./deploy.sh"
            }
        }
    }
}