Jenkins流水线语法

declarative pipelines vs scripted pipelines#

这其实是两种语法,declarative pipelines 有详细文档说明,文档末尾提到了 scripted pipelines,但是没有详细说明。

在动态生成 pipeline 时,代码需要返回 scripted pipelines。

def agents  = ['master', 'agent1', 'agent2']

def generateStage(nodeLabel) {
  return {
	stage("Runs on ${nodeLabel}") {
	  node(nodeLabel) {
		echo "Running on ${nodeLabel}"
	  }
	}
  }
}
def parallelStagesMap = agents.collectEntries {
  ["${it}" : generateStage(it)]
}
pipeline {
  agent none
  stages {
	stage('non-parallel stage') {
	  steps {
		echo 'This stage will be executed first.'
	  }
	}

	stage('parallel stage') {
	  steps {
		script {
		  parallel parallelStagesMap
		}
	  }
	}
  }
}

上面代码中根据 agents 数组动态生成任务并执行,下面 pipeline 代码块中的内容是 declarative pipelines 语法,而函数 generateStage 中生成的任务需要使用 scripted pipelines 语法,否则会报错。

不得不说这个设计很容易把人搞晕。

在指定的节点上执行任务#

在 declarative pipelines 语法中,通过使用 agent 来指定节点。

在 scripted pipelines 语法中,使用 node 来指定节点(见上面动态生成的代码示例)。

普通的 groovy 脚本不会在节点上执行!#

stage('Test') {
  agent { label 'db1' }
  steps {
	sh 'uname -a'
	println "uname -a".execute().text
  }
}

如果执行上面的代码,会发现 sh 中的 shell 脚本是在节点 db1 上运行的,但是第二句 println “uname -a”.execute().text 是在 master 节点上运行的!

非常坑的设定,网上也有人提出了这个问题:https://stackoverflow.com/questions/43748826/jenkins-declarative-pipeline-run-groovy-script-on-slave-agent

在 pipeline step 语法中有 withGroovy 的说明,使用时需要安装 plugin,但是该 plugin 文档上说其当前版本不支持 pipeline 语法。

最后在 Jenkins Script Console 的说明文档中找到一个可以实现的例子:

import hudson.util.RemotingDiagnostics
import jenkins.model.Jenkins

String agentName = 'your agent name'
//groovy script you want executed on an agent
groovy_script = '''
println System.getenv("PATH")
println "uname -a".execute().text
'''.trim()

String result
Jenkins.instance.slaves.find { agent ->
  agent.name == agentName
}.with { agent ->
  result = RemotingDiagnostics.executeGroovy(groovy_script, agent.channel)
}
println result

代码虽然复杂,好歹能实现功能,封装一下应该使用就更简单了。

Steps 中可用的插件#

https://www.jenkins.io/doc/pipeline/steps/

comments powered by Disqus