如果您阅读此博客文章,则很有可能正在寻找有关脚本化和声明性管道之间的实际差异的信息,对吗?那你找不到更好的地方了。我将向您展示这两者之间的四个最实际的区别。和我待几分钟,享受旅程!
为什么要有两种管道类型?
- 脚本化管道是Jenkins中作为代码的管道的第一个实现。即使它使用底层的管道子系统,它还是或多或少地设计为使用Groovy构建的通用DSL。这意味着它不具有固定的结构,并且由您决定如何定义管道逻辑。
- 声明性管道更自以为是,其结构是明确定义的。可能看起来有些局限。
但实际上,您可以使用脚本化或声明性管道来实现相同的目的。那么选择哪一个呢?如果您问我这个问题,我会说使用声明性管道。以下内容这就是为什么。
1.管道启动时的代码验证
- pipeline {
- agent any
- stages {
- stage("Build") {
- steps {
- echo "Some code compilation here..."
- }
- }
- stage("Test") {
- steps {
- echo "Some tests execution here..."
- echo 1
- }
- }
- }
- }
如果我们尝试运行以下管道,则验证将很快使构建失败。该日志显示只能与触发String参数,所以我们得到这样的错误。
![](https://s3.51cto.com/oss/202101/08/58d912344971c503b69e0f54b4d71195.png)
请注意,管道没有执行任何阶段,只是失败了。这可能为我们节省了很多时间-想象一下执行Build阶段几分钟,而只是获取echo步骤希望得到的信息java.lang.String而不是java.lang.Integer。
现在,让我们看一下与该示例等效的脚本管道。
- node {
- stage("Build") {
- echo "Some code compilation here..."
- }
- stage("Test") {
- echo "Some tests execution here..."
- echo 1
- }
- }
该管道执行相同的阶段和相同的步骤。但是,有一个明显的区别。让我们执行它,看看它产生什么结果。
![](https://s3.51cto.com/oss/202101/08/bdf4395b61c733a2c08eed9080d88b62.png)
它按预期失败。但是这次是执行Build阶段,也是Test阶段的第一步。如您所见,没有验证管道代码。在这种情况下,声明式管道可以更好地处理此类用例。
2.从指定步骤重新开始
声明式管道具有的另一个很酷的功能是“从阶段重新启动”。让我们修复上一个示例中的管道,看看是否只能重新启动Test阶段。
- pipeline {
- agent any
- stages {
- stage("Build") {
- steps {
- echo "Some code compilation here..."
- }
- }
- stage("Test") {
- steps {
- echo "Some tests execution here..."
- }
- }
- }
- }
让我们执行它。
![](https://s3.51cto.com/oss/202101/08/47465e4107c6147a0d7d8f30b0d5c022.png)
在这里您可以看到已选择测试阶段。在右侧的步骤列表上方,有一个名为“重新启动测试”的选项。让我们单击它并查看结果。
![](https://s3.51cto.com/oss/202101/08/d19ae7c57f0d4f327df63c09f1fdf1ba.png)
如您所见,Jenkins跳过了Build阶段(它使用了先前构建中的工作空间),并从Test阶段开始了下一个管道执行。当您执行一些外部测试并且由于远程环境的某些问题而导致测试失败时,这可能会很有用。您可以使用测试环境解决问题,然后重新运行该阶段,而无需重建所有工件。(在这种情况下,应用程序的代码未更改。)
现在,让我们看一下脚本化管道示例。
- node {
- stage("Build") {
- echo "Some code compilation here..."
- }
- stage("Test") {
- echo "Some tests execution here..."
- }
- }
如您所见,没有重新启动选项。声明式管道与脚本式管道-2:0。
3.声明式管道options块
两种管道类型都支持第三个功能,但是我认为声明性管道更好地处理了它。假设我们将以下功能添加到上一个管道中。
- 控制台日志中的时间戳。
- ANSI颜色输出。
- 在1分钟的超时构建阶段,2分钟超时的测试阶段。
声明式管道如下所示。
- pipeline {
- agent any
- options {
- timestamps()
- ansiColor("xterm")
- }
- stages {
- stage("Build") {
- options {
- timeout(time: 1, unit: "MINUTES")
- }
- steps {
- sh 'printf "\\e[31mSome code compilation here...\\e[0m\\n"'
- }
- }
- stage("Test") {
- options {
- timeout(time: 2, unit: "MINUTES")
- }
- steps {
- sh 'printf "\\e[31mSome tests execution here...\\e[0m\\n"'
- }
- }
- }
- }
让我们运行它。
![](https://s3.51cto.com/oss/202101/08/2387c3c311e970abb65469f5aedbe5ee.png)
这是控制台日志。
- Started by user Szymon Stepniak
- Running in Durability level: MAX_SURVIVABILITY
- [Pipeline] Start of Pipeline
- [Pipeline] node
- Running on Jenkins in /home/wololock/.jenkins/workspace/pipeline-sandbox
- [Pipeline] {
- [Pipeline] timestamps
- [Pipeline] {
- [Pipeline] ansiColor
- [Pipeline] {
- [Pipeline] stage
- [Pipeline] { (Build)
- [Pipeline] timeout
- 15:10:04 Timeout set to expire in 1 min 0 sec
- [Pipeline] {
- [Pipeline] sh
- 15:10:04 + printf '\e[31mSome code compilation here...\e[0m\n'
- 15:10:04 Some code compilation here...
- [Pipeline] }
- [Pipeline] // timeout
- [Pipeline] }
- [Pipeline] // stage
- [Pipeline] stage
- [Pipeline] { (Test)
- [Pipeline] timeout
- 15:10:04 Timeout set to expire in 2 min 0 sec
- [Pipeline] {
- [Pipeline] sh
- 15:10:05 + printf '\e[31mSome tests execution here...\e[0m\n'
- 15:10:05 Some tests execution here...
- [Pipeline] }
- [Pipeline] // timeout
- [Pipeline] }
- [Pipeline] // stage
- [Pipeline] }
- [Pipeline] // ansiColor
- [Pipeline] }
- [Pipeline] // timestamps
- [Pipeline] }
- [Pipeline] // node
- [Pipeline] End of Pipeline
- Finished: SUCCESS
在声明性管道中,选项与管道脚本逻辑分开。该脚本管道也支持timestamps,ansiColor和timeout选项,但它需要一个不同的代码。这是使用脚本化管道表达的相同管道。
- node {
- timestamps {
- ansiColor("xterm") {
- stage("Build") {
- timeout(time: 1, unit: "MINUTES") {
- sh 'printf "\\e[31mSome code compilation here...\\e[0m\\n"'
- }
- }
- stage("Test") {
- timeout(time: 2, unit: "MINUTES") {
- sh 'printf "\\e[31mSome tests execution here...\\e[0m\\n"'
- }
- }
- }
- }
- }
我想你看到了问题。在这里,我们仅使用timestamps和ansiColorJenkins插件。想象再添加一个或两个插件。声明式与脚本式,3:0。
4.用when块跳过阶段。
在此博客文章中我最后要提到的是when声明性管道支持的块。让我们改进前面的示例并添加以下条件:
- 仅在等于时执行测试阶段。env.FOO``bar
这是声明性管道代码的外观。
- pipeline {
- agent any
- options {
- timestamps()
- ansiColor("xterm")
- }
- stages {
- stage("Build") {
- options {
- timeout(time: 1, unit: "MINUTES")
- }
- steps {
- sh 'printf "\\e[31mSome code compilation here...\\e[0m\\n"'
- }
- }
- stage("Test") {
- when {
- environment name: "FOO", value: "bar"
- }
- options {
- timeout(time: 2, unit: "MINUTES")
- }
- steps {
- sh 'printf "\\e[31mSome tests execution here...\\e[0m\\n"'
- }
- }
- }
- }
然后执行它。
![](https://s5.51cto.com/oss/202101/08/999e50e44e5ef2496d7d56d0e34888c0.png)
该测试如预期阶段被跳过。现在,让我们尝试在脚本化管道示例中执行相同的操作。
- node {
- timestamps {
- ansiColor("xterm") {
- stage("Build") {
- timeout(time: 1, unit: "MINUTES") {
- sh 'printf "\\e[31mSome code compilation here...\\e[0m\\n"'
- }
- }
- if (env.FOO == "bar") {
- stage("Test") {
- timeout(time: 2, unit: "MINUTES") {
- sh 'printf "\\e[31mSome tests execution here...\\e[0m\\n"'
- }
- }
- }
- }
- }
- }
如您所见,我们必须使用if-condition来检查是否env.FOO等于bar,然后才添加Test阶段。(不幸的是,这并不是真正的跳过。)让我们运行它,看看结果如何。
![](https://s6.51cto.com/oss/202101/08/708d51a817ae829cf3e8dd109cae8970.png)
这是不同的结果。在脚本化管道用例中,甚至不会呈现“ 测试”阶段。在我看来,这可能会带来一些不必要的混乱,声明性管道会更好地处理它。声明式与脚本式,4:0。
结论
这是我在声明性和脚本化Jenkins管道之间的四大区别。这些不是唯一的区别,我想您的列表可能看起来有些不同。你的选择是什么?您更喜欢声明性管道还是脚本化管道?