「Jenkins Pipeline」- 常见错误 | 改进 | 问题

场景 | 我们的自动化构建流程 | 实践经验

开发提交代码到代码服务器(GitHub Gitlab BitBucket)
代码服务器通过 WebHook 触发 CI/CD(Codeship、Shippable、CircleCI、Jenkins)
CI 服务拉去最新的代码,构建 Docker 镜像,进行测试
自动集成测试完成后,将镜像推送到私有的 Registry
运维使用最新的 Docker 镜像进行部署

流水线模型

相关链接:
https://www.56dagong.com/info-6945.html

第一版

调试信息()、代码检查()、环境搭建()、创建应用()、应用发布()、执行测试()

现存问题:该阶段的主要问题是Pipeline脚本结构混乱、命名不规范、硬编码

第二版

调试信息()、代码检查()、环境搭建()、创建应用()、应用发布()、执行测试()

工作任务:优化Pipeline脚本

#2 在共享库里中,函数调用 println 无效(即在 Console Ouput 中没有输出)

println in “call” method of “vars/foo.groovy” works, but not in method in class
printlns in shared library vars classes are ignored

#1 NotSerializableException GitChangeSetList

Error with changeSet in jenkins pipeline (Error:java.io.NotSerializableException: hudson.plugins.git.GitChangeSetList)

(Error:java.io.NotSerializableException: hudson.plugins.git.GitChangeSetList)

Jenkins 可以保存中间执行,但是要求能够序列化。但是原始构建无法被序列化。

所以需要在函数上添加 @NonCPS 注解,形如:

@NonCPS
def showChangeLogs() {
  def changeLogSets = currentBuild.rawBuild.changeSets
  for (int i = 0; i < changeLogSets.size(); i++) {
     def entries = changeLogSets[i].items
     for (int j = 0; j < entries.length; j++) {
          def entry = entries[j]
          echo "${entry.commitId} by ${entry.author} on ${new Date(entry.timestamp)}: ${entry.msg}"
          def files = new ArrayList(entry.affectedFiles)
          for (int k = 0; k < files.size(); k++) {
              def file = files[k]
              echo "  ${file.editType.name} ${file.path}"
          }
      }
  }
}

Annotation Grab cannot be used in the sandbox

问题描述:

...
org.jenkinsci.plugins.workflow.cps.CpsCompilationErrorsException: startup failed:
General error during conversion: Annotation Grab cannot be used in the sandbox.

java.lang.SecurityException: Annotation Grab cannot be used in the sandbox.
	at org.jenkinsci.plugins.scriptsecurity.sandbox.groovy.RejectASTTransformsCustomizer$RejectASTTransformsVisitor.visitAnnotations(RejectASTTransformsCustomizer.java:112)
	at org.codehaus.groovy.ast.ClassCodeVisitorSupport.visitImports(ClassCodeVisitorSupport.java:73)
...

原因分析:
不管是在项目中使用的共享库,还是在 Folder 中使用的共享库,都是在 sanbox 中运行的,所以无法使用 Grab 语法。

解决方案:
在全局中引入该共享库:Manage Jenkins / Global Pipeline Libraries

# 当使用 input 的 booleanParam 选项注入变量时,变量类型是什么?

-「booleanParam in jenkins dsl

软件版本:Jenkins ver. 2.176.1

问题描述

在下面示例中:

input {
	message "Should we continue?"
	id "AAAA"
	parameters {
		booleanParam(name: 'PERSON', defaultValue: false, description: 'Who should I say hello to?')
	}
}

when {
	expression { return PERSON }
}

在构建时,无论选择什么参数,表达式 When 永远为真。

问题原因

经过测试,由inputbooleanParam选项注入的变量,它为String类型。也就是说变量PERSONString类型。根据文档中对When的描述,当类型为String时,等同于true值,这就导致When永远是通过的。

根据「booleanParam in jenkins dsl」的描述,该变量是从env中获取,所以为String类型。

解决办法

当在 When 语句中,需要类型转换。将expression { return PERSON }替换为expression { return PERSON.toBoolean() }即可。

# 构建时创建了过多的子进程

问题描述:
前端开发人员,不知道在 NPM 的构建文件里写了什么,会递归产生子进程。最后把主机的进程耗光,导致服务器宕机。

解决办法:
这个好办,因为 Jenkins 是以jenkins用户运行的,所以「限制允许用户创建的最大进程数」即可。修改方式因系统而异,主要是 SysV init 与 systemd 之间的差异。

当初也不知道谁把NPORC改成了不限制,这你让说什么好。而且,我发现他们特别爱用infinity或者65536这种参数值。

# exception message [Exec timed out or was interrupted after

-「Jenkins Text-finder unable to success my Build

问题描述:
使用 Publish Over SSH 插件时,当命令执行结束后,不能正确退出。一直等到超时之后才退出。

解决办法:
在 Publish Over SSH 的高级设置(Advanced…)中,选中「Exec in pty」选项。

# 某些 Job 不可见

问题描述:
在 Jenkins 中定义的某些 Job 不见了

问题原因:
因为升级了 Jenkins 中的某些插件,但是需要插件需要更新 Jenkins 的版本。在插件管理中一片红。

解决办法:
升级 Jenkins 到新的版本。

# java.lang.NoSuchMethodError: com.google.common.io.Files.asCharSource

-「Use of beta Guava method since deleted: Iterators.skip
-「Upgrade Guava or properly isolate core Guava dependency from plugins
-「Hide core dependencies in plugin classpath

问题原因:
在 Pipeline 的共享库中使用了「Docker Java Parser » 0.2.0」库,该库依赖了「com.google.guava » guava 23.6-jre」库,这都没啥问题。

问题的原因在于,Jenkins 也使用了 Guava 库,版本是 11。旧库的加载覆盖了新库。

解决办法:
还没找到……

# Annotation Grab cannot be used in the sandbox

-「Could not initialize class with \@Grab annotation in shared library #43

目前还不能在 Pipeline 中使用@Grab 注解。解决办法有两个:在共享库里使用@Grab注解来引入第三方共享库;或者换用其他的插件,使用 Jenkins 提供的步骤。

#「jenkinsfile doesn’t recognize \@Grab
在 Pipeline 中不能使用@Grab来引入第三方库。因为在 Pipeline 中,Jenkins 的 CPS 需要源码才能进行 CPS 转换,而@Grab加载的是二进制的库。

# Scripts not permitted to use staticMethod

-「Jenkins CI Pipeline Scripts not permitted to use method groovy.lang.GroovyObject

[Sol.] … RPC failed; curl 56 GnuTLS recv error …


Receiving objects: 49% (27172/55453)
Receiving objects: 50% (27727/55453)
error: RPC failed; curl 56 GnuTLS recv error (-9): Error decoding the received TLS packet.
fatal: the remote end hung up unexpectedly
fatal: early EOF
fatal: index-pack failed

该问题的成因很多,所以在网上会看到各种答案。

针对我们的场景,GitLab 所在服务器已用磁盘空间达到 100%,导致 GitLab 无法正常响应。

最大构建数值 | Max Build Number

integer – Jenkins BUILD_NUMBER limit – maximum build number – Stack Overflow
How to reset build number in jenkins? – Stack Overflow

Thus, the last value that a Jenkins job can be set or built is: 2147483647 (4 bytes here). Setting anything above this number will generate the expected INT limit error.

item = Jenkins.instance.getItemByFullName("your-job-name-here")
//THIS WILL REMOVE ALL BUILD HISTORY
item.builds.each() { build ->
  build.delete()
}
item.updateNextBuildNumber(1)

[Sol.] … Fialed to setup credentials …

检查磁盘空间

常见问题

[WIP] … java.lang.IllegalStateException: trying to open a build log on … after it has completed …

https://stackoverflow.com/questions/65441139/how-to-fix-jenkins-java-lang-illegalstateexception-an-attempt-to-save-the-globa

环境:多分支流水,Jeninsfile