如何使用声明性 Jenkins 管道在同一节点上运行多个阶段?
Posted
技术标签:
【中文标题】如何使用声明性 Jenkins 管道在同一节点上运行多个阶段?【英文标题】:How to run multiple stages on the same node with declarative Jenkins pipeline? 【发布时间】:2017-12-05 20:39:56 【问题描述】:目标 在同一节点上运行声明式 Jenkins 管道的多个阶段。
设置 这只是显示问题的一个最小示例。有 2 个 Windows 节点“windows-slave1”和“windows-slave2”都标有“windows”标签。
注意:我真正的 Jenkinsfile 不能使用全局代理,因为有一组阶段需要在不同的节点上运行(例如 Windows 与 Linux)。
预期行为 Jenkins 根据标签选择“Stage 1”中的节点之一,并在“Stage 2”中使用相同的节点,因为变量 windowsNode 已更新为“Stage 1”中选择的节点。
实际行为 “Stage 2”有时在与“Stage 1”相同的节点上运行,有时在不同的节点上运行。请参阅下面的输出。
Jenkinsfile
#!groovy
windowsNode = 'windows'
pipeline
agent none
stages
stage('Stage 1')
agent
label windowsNode
steps
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')
agent
label windowsNode
steps
echo "windowsNode: $windowsNode, NODE_NAME: $NODE_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
您知道设置有什么问题吗?我猜这就是 Jenkinsfile 的解析和执行方式。
其他建议?最初设置 windowsNode 时,可能有一个 Jenkins API 可以根据“windows”标签选择一个节点。
【问题讨论】:
您的第 2 阶段没有拾取重命名的变量。如果您将windowsNode = 'windows'
更改为windowsNode = 'asdf'
,那么您应该会看到“没有带有标签‘asdf’的节点”错误,这意味着您的第2 阶段仍在运行label 'windows'
而不是label 'windows-slave2'
。
但是,我尝试了stage("Stage 2" ) environment someVariable = "$windowsNode" agent label env.someVariable ..
,尽管它分配了一个节点并且没有给出“缺少属性”错误(这意味着agent
至少知道 someVariable 存在),但它不起作用。如果我打印env.someVariable
的值,它是节点名称,所以虽然它可以看到正确的windowsNode
变量,但我怀疑someVariable
在agent
指令中处于某种空白状态,导致它运行类似agent label ''
而不是 agent label 'windows-slave2'
。
我也尝试了environment someVariable = "\'$windowsNode\'"
,它使变量'windows-slave2'
而不仅仅是windows-slave2
,但它仍然在我的两个测试节点之间随机分配(尽管变量或标签名称仍然没有错误) .
【参考方案1】:
从Declarative Pipeline 插件的1.3 版开始,正式支持此功能。 它被正式称为“顺序阶段”。
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"
官方公告在这里:https://jenkins.io/blog/2018/07/02/whats-new-declarative-piepline-13x-sequential-stages/
【讨论】:
不错的功能,但是如果您必须在阶段序列中分配 2 个单独的节点,您会使用什么: stage1 - nodeA stage2 - nodeB stage3 - nodeA stage4 - nodeA ?您可以将 NODE_NAME 保存到变量 nodeA|B 中并在第 3 阶段和第 4 阶段在代理 node nodeA|B 中使用它吗? 如果在顺序块本身是并行阶段的一部分时尝试执行此操作,则会出现语法错误。我在引发这一发展的问题中看到了类似的抱怨。这一点也不罕见,但实现该功能的人似乎没有想到它。如果有办法让它发挥作用,我会很高兴听到。事实上,我不得不求助于管道环境中定义的变量,在第一个 seq 阶段的脚本块中设置,并在没有环境的情况下写入/读取它。前缀。【参考方案2】:您可以在脚本块中定义阶段。这些阶段是在给定代理中运行的父阶段的子阶段。这是我不得不在与您类似的用例中使用的方法。
#!groovy
windowsNode = 'windows'
pipeline
agent none
stages
stage('Stage A')
agent
label windowsNode
steps
script
stage('Stage 1')
windowsNode = NODE_NAME
echo "windowsNode: $windowsNode, NODE_NAME: $NODE_NAME"
stage('Stage 2')
echo "windowsNode: $windowsNode, NODE_NAME: $NODE_NAME"
【讨论】:
如果从服务器也有两个执行器,并且我已经阻止了这两个执行器来完成这项工作,是否可以使用这种方法使用并行阶段?【参考方案3】:我发现这正如你所期望的那样工作
#!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"
【讨论】:
【参考方案4】:将agent none
替换为agent any
【讨论】:
这无济于事。使用agent any
意味着如果step
中未提供代理,那么它将尝试在any
可用节点上运行。 OP 希望这些步骤在特定节点上运行。
这是不正确的,在管道的开头指定一个代理会为整个脚本分配一个代理。以上是关于如何使用声明性 Jenkins 管道在同一节点上运行多个阶段?的主要内容,如果未能解决你的问题,请参考以下文章
Jenkins 声明性管道 - 如果不满足某些条件而不是跳过一个阶段,如何中止整个构建?
如何防止相同类型的两个管道 jenkins 作业在同一节点上并行运行?
如何在同一个 Jenkins 节点中加载另一个 groovy 脚本?