将轻量级执行器用于声明性管道阶段(代理 none)
Use a lightweight executor for a declarative pipeline stage (agent none)
我正在使用声明式语法的 Jenkins Pipeline,目前有以下阶段:
- 准备
- 构建(两组平行的步骤)
- 测试(也是两组平行的步骤)
- 要求 if/where 部署
- 部署
对于第 1、2、3 和 5 步,我需要代理(执行者),因为他们在工作区上进行实际工作。对于第 4 步,我不需要一个,并且我不想在等待用户输入时阻止可用的执行程序。这似乎被称为经典脚本语法的 "flyweight" 或 "lightweight" 执行程序,但我找不到有关如何使用声明性语法实现此目的的任何信息。
到目前为止我已经尝试过:
- 直接在管道选项中设置代理,然后在舞台上设置
agent none
。这没有任何效果,并且管道 运行s 正常,在等待输入时阻塞执行程序。文档中也提到它不会有任何效果,但我想我还是试一试。
- 在管道选项中设置
agent none
,然后为除#4 之外的每个阶段设置代理。不幸的是,但意料之中的是,这会为每个阶段分配一个新的工作空间,这反过来又需要我存储和取消存储。这既混乱又给我带来了并行阶段(2 和 3)的更多问题,因为我不能在 parallel
构造之外编写代码。我假设在同一个工作区中的并行步骤 运行,因此两者中的 stashing/unstashing 都会有不幸的结果。
这是我的 Jenkinsfile 的大纲:
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 {
// ...
}
}
我是不是遗漏了什么,或者在当前版本中是不可能的?
在顶层设置 agent none
,然后在每个阶段设置 agent { label 'foo' }
,在 input
阶段再次设置 agent none
似乎符合我的预期。
即每个执行某些工作的阶段都在同一个代理上运行,而 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
块,以便为 [=28= 编写一段脚本化管道] after/before并行步骤。
有一种解决方法可以在其他阶段使用相同的构建从属。
您可以使用节点名称设置一个变量并在其他变量中使用它。
即:
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}"
}
}
}
}
从今天(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)
}
}
}
}
}
}
我正在使用声明式语法的 Jenkins Pipeline,目前有以下阶段:
- 准备
- 构建(两组平行的步骤)
- 测试(也是两组平行的步骤)
- 要求 if/where 部署
- 部署
对于第 1、2、3 和 5 步,我需要代理(执行者),因为他们在工作区上进行实际工作。对于第 4 步,我不需要一个,并且我不想在等待用户输入时阻止可用的执行程序。这似乎被称为经典脚本语法的 "flyweight" 或 "lightweight" 执行程序,但我找不到有关如何使用声明性语法实现此目的的任何信息。
到目前为止我已经尝试过:
- 直接在管道选项中设置代理,然后在舞台上设置
agent none
。这没有任何效果,并且管道 运行s 正常,在等待输入时阻塞执行程序。文档中也提到它不会有任何效果,但我想我还是试一试。 - 在管道选项中设置
agent none
,然后为除#4 之外的每个阶段设置代理。不幸的是,但意料之中的是,这会为每个阶段分配一个新的工作空间,这反过来又需要我存储和取消存储。这既混乱又给我带来了并行阶段(2 和 3)的更多问题,因为我不能在parallel
构造之外编写代码。我假设在同一个工作区中的并行步骤 运行,因此两者中的 stashing/unstashing 都会有不幸的结果。
这是我的 Jenkinsfile 的大纲:
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 {
// ...
}
}
我是不是遗漏了什么,或者在当前版本中是不可能的?
在顶层设置 agent none
,然后在每个阶段设置 agent { label 'foo' }
,在 input
阶段再次设置 agent none
似乎符合我的预期。
即每个执行某些工作的阶段都在同一个代理上运行,而 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
块,以便为 [=28= 编写一段脚本化管道] after/before并行步骤。
有一种解决方法可以在其他阶段使用相同的构建从属。 您可以使用节点名称设置一个变量并在其他变量中使用它。
即:
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}"
}
}
}
}
从今天(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)
}
}
}
}
}
}