如何使用声明性Jenkins管道在同一节点上运行多个阶段?

如何使用声明性Jenkins管道在同一节点上运行多个阶段?,jenkins,jenkins-pipeline,Jenkins,Jenkins Pipeline,目标 在同一节点上运行声明性Jenkins管道的多个阶段 设置 这只是说明问题的一个最小示例。有两个Windows节点“Windows-slave1”和“Windows-slave2”都标有“Windows”标签 注意:我的real Jenkins文件不能使用全局代理,因为需要在不同的节点(例如Windows和Linux)上运行多组阶段 预期行为 Jenkins根据标签选择“阶段1”中的一个节点,并在“阶段2”中使用相同的节点,因为变量windowsNode已更新为“阶段1”中选择的节点 实际行

目标
在同一节点上运行声明性Jenkins管道的多个阶段

设置
这只是说明问题的一个最小示例。有两个Windows节点“Windows-slave1”和“Windows-slave2”都标有“Windows”标签

注意:我的real Jenkins文件不能使用全局代理,因为需要在不同的节点(例如Windows和Linux)上运行多组阶段

预期行为
Jenkins根据标签选择“阶段1”中的一个节点,并在“阶段2”中使用相同的节点,因为变量windowsNode已更新为“阶段1”中选择的节点

实际行为
“阶段2”有时在与“阶段1”相同的节点上运行,有时在不同的节点上运行。请参见下面的输出

Jenkinsfile

#!棒极了
windowsNode='windows'
管道{
一号特工
舞台{
阶段(“阶段1”){
代理人{
标签窗口节点
}
台阶{
剧本{
//所有后续步骤都应在同一windows节点上运行
windowsNode=节点名称
}
echo“windowsNode:$windowsNode,NODE\u NAME:$NODE\u NAME”
}
}
阶段(“阶段2”){
代理人{
标签窗口节点
}
台阶{
echo“windowsNode:$windowsNode,NODE\u NAME:$NODE\u NAME”
}
}
}
}
输出

[Pipeline] stage
[Pipeline] { (Stage 1)
[Pipeline] node
Running on windows-slave2 in C:\Jenkins\workspace\test-agent-allocation@2
[Pipeline] {
[Pipeline] script
[Pipeline] {
[Pipeline] }
[Pipeline] // script
[Pipeline] echo
windowsNode: windows-slave2, NODE_NAME: windows-slave2
[Pipeline] }
[Pipeline] // node
[Pipeline] }
[Pipeline] // stage
[Pipeline] stage
[Pipeline] { (Stage 2)
[Pipeline] node
Running on windows-slave1 in C:\Jenkins\workspace\test-agent-allocation
[Pipeline] {
[Pipeline] echo
windowsNode: windows-slave2, NODE_NAME: windows-slave1
[Pipeline] }
[Pipeline] // node
[Pipeline] }
[Pipeline] // stage
[Pipeline] End of Pipeline
Finished: SUCCESS
你知道设置有什么问题吗?我想这就是Jenkins文件的解析和执行方式


其他建议?最初设置windowsNode时,可能有一个Jenkins API可以根据“windows”标签选择节点。

代理无
替换为
代理任何
您可以在脚本块内定义阶段。这些阶段是在给定代理中运行的父阶段的子阶段。这是我在一个与你类似的用例中必须使用的方法

#!棒极了
windowsNode='windows'
管道{
一号特工
舞台{
阶段(‘阶段A’){
代理人{
标签窗口节点
}
台阶{
剧本{
阶段('阶段1'){
windowsNode=节点名称
echo“windowsNode:$windowsNode,NODE\u NAME:$NODE\u NAME”
}
阶段(“阶段2”){
echo“windowsNode:$windowsNode,NODE\u NAME:$NODE\u NAME”
}
}
}
}
}
}

我发现它的工作原理与您预期的一样

#!groovy

windowsNode = 'windows'

pipeline {
    agent none
    stages {
        stage('Stage 1') {
            steps {
                node(windowsNode) {
                    script {
                        // all subsequent steps should be run on the same windows node
                        windowsNode = NODE_NAME
                    }
                    echo "windowsNode: $windowsNode, NODE_NAME: $NODE_NAME"
                }
            }
        }
        stage('Stage 2') {
            steps {
                node(windowsNode) {
                    echo "windowsNode: $windowsNode, NODE_NAME: $NODE_NAME"
                }
            }
        }
    }
}

自1.3版声明性管道插件以来,这一功能得到了官方支持。 官方称之为“连续阶段”


此处正式宣布:

您的第2阶段没有使用重命名的变量。如果您将
windowsNode='windows'
更改为
windowsNode='asdf'
,那么您应该会看到一个“没有带有标签'asdf'的节点”错误,这意味着您的stage 2仍在运行
label'windows'
而不是
label'windows-slave2'
。但是,我尝试了
stage(“stage 2”){environment{someVariable=“$windowsNode”}代理{label env.someVariable}..
虽然它分配了一个节点并且没有“缺少属性”错误(意思是
代理
至少知道someVariable存在),它不起作用。如果我打印
env.someVariable
的值,它就是节点名,因此尽管它可以看到正确的
windowsNode
变量,但我怀疑
someVariable
agent
指令中处于某种空白状态,导致它运行类似
agent label''的东西,而不是
agent标签“windows-slave2”
。我还尝试了
环境{someVariable=“\'$windowsNode\”}
,这使得变量
'windows-slave2'
而不仅仅是
windows-slave2
,但它仍然在我的两个测试节点之间随机分配(尽管变量或标签名称仍然没有错误)。这不会有帮助。使用
代理any
意味着如果
步骤中未提供代理,则它将尝试在
任何可用节点上运行。OP希望这些步骤在特定节点上运行。这是不正确的,在管道开始处指定代理会为整个脚本分配代理。如果从属节点也有两个执行器,我已经阻止了这项工作的两个执行器,是否可以用这种方法使用并行阶段?很好的功能,但是如果必须在阶段序列中分配两个单独的节点:stage1-nodeA stage2-nodeB stage3-nodeA stage4-nodeA?是否可以将节点名称保存到变量nodeA | B和nodeA中阶段3和阶段4在代理{node nodeA | B}中使用它?当序列块本身是并行阶段的一部分时,如果我尝试这样做,我会遇到语法错误。我在发起此开发的问题中看到类似的抱怨。这一点并不少见,但实现此功能的人似乎没有想到。如果有办法使其工作,我会很高兴听到。事实上,我不得不使用管道环境中定义的变量,在脚本块的第一个seq阶段中设置,并在不使用env.前缀的情况下写入/读取。
pipeline {
    agent none

    stages {
        stage("check code style") {
            agent {
                docker "code-style-check-image"
            }
            steps {
                sh "./check-code-style.sh"
            }
        }

        stage("build and test the project") {
            agent {
                docker "build-tools-image"
            }
            stages {
               stage("build") {
                   steps {
                       sh "./build.sh"
                   }
               }
               stage("test") {
                   steps {
                       sh "./test.sh"
                   }
               }
            }
        }
    }
}