将轻量级执行程序用于声明性管道阶段(代理无)

时间:2017-02-10 12:17:56

标签: jenkins jenkins-pipeline

我正在使用具有声明性语法的Jenkins Pipeline,目前具有以下阶段:

  1. 准备
  2. 构建(两组并行的步骤)
  3. 测试(也是两组并行的步骤)
  4. 询问是否/部署
  5. 部署
  6. 对于步骤1,2,3和5,我需要和代理(执行程序),因为它们在工作区上进行实际工作。对于第4步,我不需要一个,我想在等待用户输入时不阻止我的可用执行程序。对于经典的脚本语法,这似乎被称为“flyweight”或“轻量级”执行器,但我找不到有关如何使用声明性语法实现此目的的任何信息。

    到目前为止,我已经尝试过:

    1. 直接在管道选项中设置代理,然后在舞台上设置agent none。这没有任何效果,并且管道正常运行,在等待输入时阻塞执行程序。在文档中也提到它没有任何效果,但我想我还是试一试。
    2. 在管道选项中设置agent none,然后为除#4之外的每个阶段设置代理。不幸的是,但是预计会为每个阶段分配一个新的工作区,这反过来要求我藏匿和解除搁置。这既麻烦又在并行阶段(2和3)给我进一步的问题,因为我不能在parallel结构之外有代码。我假设并行步骤在同一个工作区中运行,因此两者中的存储/取消存储都会产生不幸的结果。
    3. 以下是我的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 {
              // ...
          }
      }
      

      我在这里遗漏了什么,或者在当前版本中是不可能的?

3 个答案:

答案 0 :(得分:13)

在顶层设置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()}"
            }
        }
    }
}

但是,无法保证在管道中使用相同的代理标签总是会使用相同的工作区,例如当第一个构建在input上等待时,作为同一作业的另一个构建。

在构建步骤之后,您必须使用stash。正如您所指出的那样,目前无法通过parallel正常完成此操作,因此您必须另外使用script块,以便为之后的存储/取消存储写入一段Scripted Pipeline /在平行步骤之前。

答案 1 :(得分:1)

从今天(2021 年)开始,您可以使用嵌套阶段 (https://www.jenkins.io/doc/book/pipeline/syntax/#sequential-stages) 将输入步骤之前必须在同一工作区中运行的所有阶段以及必须在同一工作区中运行的所有阶段进行分组输入步骤后的工作空间。当然,您需要在输入步骤之前将工件隐藏或存储在某个外部存储库中,因为第二个工作区可能与第一个不同:

pipeline {
    agent none
    stages {
        stage('Deployment to Preproduction') { 
            agent any 
            stages {
                stage('Stage PRE.1') { 
                    steps {
                        echo "StagePRE.1"
                        sleep(10)
                    }
                }
                stage('Stage PRE.2') { 
                    steps {
                        echo "Stage PRE.2"
                        sleep(10)
                    }
                }
            }
        }
        stage('Stage Ask Deploy') { 
            steps {
                input message: 'Deploy to production?'
            }
        }
        stage('Deployment to Production') { 
            agent any 
            stages {
                stage('Stage PRO.1') { 
                    steps {
                        echo "Stage PRO.1"
                        sleep(10)
                    }
                }
                stage('Stage PRO.2') { 
                    steps {
                        echo "Stage PRO.2"
                        sleep(10)
                    }
                }
            }
        }
    }
}

答案 2 :(得分:0)

有一种解决方法,可以在其他阶段使用相同的构建从属。 您可以使用节点名称设置变量,然后在其他节点中使用它。

即:

pipeline {
    agent none
    stages {
        stage('First Stage Gets Agent Dinamicaly') {
            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}"
            }
        }
    }
}