关于 jenkins:如何在声明式管道中等待用户输入而不阻塞重量级执行器

How to wait for user input in a Declarative Pipeline without blocking a heavyweight executor

我正在将现有构建管道重建为 jenkins 声明式管道(多分支管道),但在处理构建传播时遇到问题。

在打包并存储所有相关文件后,管道应该等待用户输入以触发部署。

如果我只是添加一个输入步骤,当前的构建节点就会被阻止。由于这个 executor 很重,我想把这一步移到更轻的机器上。

最初我是作为脚本管道完成这项工作的,只是创建了两个不同的 node('label') 块。有没有办法让我用声明式语法做类似的事情?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
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
}

我已经尝试了几件事:

在顶级配置代理并向传播步骤添加额外的代理配置,但随后我有两个执行程序阻塞,因为顶级定义的构建节点没有停止。

在顶级设置 agent none 并按步骤配置代理。那么第一个节点上不存在 git checkout。

编辑 1

我按照你的建议重新配置了我的管道,它目前看起来像这样:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
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 集群上生成 build slaves,所以改变 executor mid build 将是一个问题)

我希望 jenkins 只与当前执行程序一起运行,只要代理定义中的标签不改变。


参见最佳实践 7:Dona€?t:在节点块中使用输入。在声明式管道中,节点选择是通过 agent 指令完成的。

此处的文档描述了如何为管道定义 none,然后使用阶段级 agent 指令在所需节点上运行阶段。我也尝试了相反的方法(在某个节点上定义一个全局代理,然后在舞台级别为输入定义 none),但这不起作用。如果流水线分配了一个从属设备,则您不能在一个或多个特定阶段释放该从属设备。

这是我们管道的结构:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
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\
yes', 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"的构建从属设备上执行,但输入阶段在主设备上运行。


另一种方法是使用表达式指令和 beforeAgent,它会跳过"决定"步骤并避免与"env"全局混淆:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
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 {
                ...
            }
        }
    }
}


我知道这个线程很旧,但我相信除了存储之外,"编辑 2"问题的解决方案是使用嵌套阶段。

https://jenkins.io/blog/2018/07/02/whats-new-declarative-piepline-13x-sequential-stages/#running-multiple-stages-with-the-same-agent-or-环境或选项

根据本页:

... if you are using multiple agents in your Pipeline, but would like to be sure that stages using the same agent use the same workspace, you can use a parent stage with an agent directive on it, and then all the stages inside its stages directive will run on the same executor, in the same workspace.

这是提供的示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
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"
            }
        }
    }
}


在顶部使用无代理,并为除了包括输入步骤的阶段之外的每个阶段定义代理。

来源:使用轻量级执行器进行声明性管道阶段(无代理)中的讨论

更新:"第一个节点上不存在 git checkout"是什么意思?请展示到目前为止您对声明性管道的了解。


OP 的问题是如何"在声明式管道中等待用户输入而不阻塞......"。这似乎不可能。尝试使用 agent: none 不会释放声明式管道中的构建执行程序。

这个:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
pipeline {
agent none
stages {
    stage('Build') {
        agent { label 'big-boi' }
        steps {
            echo 'Stubbed'
        }
    }

    stage('Prompt for deploy') {
        agent { label 'tiny' }
        steps {
            input 'Deploy this?'
        }
    }

    stage('Deploy') {
        agent { label 'big-boi' }
        steps {
            echo"Deploying"
            build job: 'deploy-to-higher-environment'
        }
    }
}
}

...运行时,如下所示:

enter

enter