- 开发环境搭建
- library工作模式
- groovy项目新建
- ">New Project

- Library代码结构介绍
- Groovy基本语法介绍
- library与Jenkins集成
- library集成镜像构建及推送
- ">先在jenkins上创建仓库登陆凭据,ID为 redential-registry ,为后续调用标识

- 丰富构建通知逻辑
- library集成k8s服务部署
- 开发环境
$ cat devops-config-dev.txt
NAMESPACE=dev
INGRESS_MYBLOG=blog-dev.luffy.com
$ kubectl -n dev create configmap devops-config —from-env-file=devops-config-dev.txt
由于公司内部项目众多,大量的项目使用同一套流程做CICD
- 那么势必会存在大量的重复代码
- 一旦某个公共的地方需要做调整,每个项目都需要修改
因此本章主要通过使用groovy实现Jenkins的sharedLibrary的开发,以提取项目在CICD实践过程中的公共逻辑,提供一系列的流程的接口供公司内各项目调用。
开发完成后,对项目进行Jenkinsfile的改造,最后仅需通过简单的Jenkinsfile的配置,即可优雅的完成CICD流程的整个过程,此方式已在大型企业内部落地应用。
开发环境搭建
#下载安装包
链接:https://pan.baidu.com/s/1YRcBY3vFmn1FO37BeHiluQ
提取码:7hmu
#安装java
安装路径:D:\software\jdk
右键点击我的电脑 > 属性 > 高级系统设置, 新增环境变量:
JAVA_HOME D:\software\jdk
CLASSPATH .;%JAVA_HOME%\lib\dt.jar;%JAVA_HOME%\lib\tools.jar;
PATH %JAVA_HOME%\bin #key(PATH)已存在,添加值即可
#安装groovy
解压路径:D:\software\groovy-3.0.2
环境变量:
GROOVY_PATH D:\software\groovy-3.0.2
PATH D:\software\groovy-3.0.2\bin
#安装idea
安装路径:D:\software\IntelliJ IDEA 2019.2.3
library工作模式
由于流水线被组织中越来越多的项目所采用,常见的模式很可能会出现。 在多个项目之间共享流水线有助于减少冗余并保持代码 “DRY”。
流水线支持引用 “共享库” ,可以在外部源代码控制仓库中定义并加载到现有的流水线中。
@Library('my-shared-library') _
在实际运行过程中,会把library中定义的groovy功能添加到构建目录中:
/var/jenkins_home/jobs/test-maven-build/branches/feature-CDN-2904.cm507o/builds/2/libs/my-shared-library/vars/devops.groovy
使用library后,Jenkinsfile大致的样子如下:
@Library('my-shared-library') _
...
stages {
stage('build image') {
steps {
container('tools') {
devops.buildImage("Dockerfile","192.168.136.10:5000/demo:latest")
}
}
}
}
post {
success {
script {
container('tools') {
devops.notificationSuccess("dingTalk")
}
}
}
}
...
groovy项目新建
New Project

Library代码结构介绍
共享库的目录结构如下:
(root)
+- src # Groovy source files
| +- org
| +- foo
| +- Bar.groovy # for org.foo.Bar class
+- vars
| +- foo.groovy # for global 'foo' variable
| +- foo.txt # help for 'foo' variable
src 目录应该看起来像标准的 Java 源目录结构。当执行流水线时,该目录被添加到类路径下。
vars 目录定义可从流水线访问的全局变量的脚本。 每个 *.groovy 文件的基名应该是一个 Groovy (~ Java) 标识符, 通常是 camelCased。
Groovy基本语法介绍
a)新建项目,名称为 jenkins-shared-library;
b)在项目src目录下新建package,名称为demo,在demo下新建groovy脚本,名为Hello;
c)在项目根目录下新建test目录,在test目录下新建groovy脚本,名为CrabDemo,并在其脚本中调用package(demo)中的函数;
总体结构如下:
#变量
// Defining a variable in lowercase
int x = 5;
// Defining a variable in uppercase
int X = 6;
// Defining a variable with the underscore in it's name
def _Name = "Joe";
println(x);
println(X);
println(_Name);
#方法
- 调用本地方法 ```groovy def sum(int a, int b){ return a + b }
println(sum(1,2))
- 调用类中的方法
```groovy
# Hello.groovy
package demo
def sayHi(String content) {
return ("hi, " + content)
}
# test/Crabdemo.groovy
import demo.Hello
def demo() {
return new Hello().sayHi("devops")
}
println(demo())
# 级联调用
# Hello.groovy
package demo
def init(String content) {
this.content = content
return this
}
def sayHi() {
println("hi, " + this.content)
return this
}
def sayBye() {
println("bye " + this.content)
}
# test/Crabdemo.groovy
import demo.Hello
def demo() {
new Hello().init("devops").sayHi().sayBye()
}
demo()
捕获异常
def exceptionDemo(){ try { def val = 10 / 0 println(val) }catch(Exception e) { println(e.toString()) throw e } } exceptionDemo()计时器与循环 ```groovy import groovy.time.TimeCategory
use( TimeCategory ) { def endTime = TimeCategory.plus(new Date(), TimeCategory.getSeconds(15)) def counter = 0 while(true) { println(counter++) sleep(1000) if (new Date() >= endTime) { println(“done”) break } } }
- 解析yaml文件
#org.yaml.snakeyaml.Yaml文件下载地址: [https://gitee.com/crabluo/jenkins-shared-library/tree/master/src](https://gitee.com/crabluo/jenkins-shared-library/tree/master/src)
```groovy
import org.yaml.snakeyaml.Yaml
def readYaml(){
def content = new File('myblog.yaml').text
Yaml parser = new Yaml()
def data = parser.load(content)
def kind = data["kind"]
def name = data["metadata"]["name"]
println(kind)
println(name)
}
readYaml()
library与Jenkins集成
以下梳理如何使用shared library实现最简单的helloworld输出功能的流程。
a)新建groovy项目(jenkins-shared-library)
- 在src目录下新建包,包名为com.crab.devops
- 在包下新建Hello.groovy脚本
- 在根目录下新建var目录,目录下新建devops.groovy脚本
结构如下:
Hello.groovy
package com.crab.devops
def hello(String content) {
this.content = content
return this
}
def sayHi() {
echo "Hi, ${this.content},how are you?"
return this
}
def answer() {
echo "${this.content}: fine, thank you, and you?"
return this
}
def sayBye() {
echo "i am fine too , ${this.content}, Bye!"
return this
}
vars/devops.groovy
import com.crab.devops.Hello
def hello(String content) {
return new Hello().hello(content)
}
b)在gitlab创建项目jenkins-shared-library,把代码推送到仓库
- gitlab上新建项目jenkins-shared-library
- 在本地项目根目录中新建 .gitignore 文件,文件内容见下文
根据页面提示在本地项目将代码推送到仓库

.gitignore
.idea
out
代表git push的时候忽略.idea和out两个无用文件
c)配置Jenkins
[系统管理] -> [系统设置] -> [ Global Pipeline Libraries ]
- Library Name:crab-devops
- Default Version:master
- Modern SCM
- Source Code Management:Git
d)Jenkinsfile中引用jenkins/pipelines/p11.yaml
@Library('crab-devops') _
pipeline {
agent { label 'jnlp-slave'}
stages {
stage('hello-devops') {
steps {
script {
devops.hello("kazihuo").sayHi().answer().sayBye()
}
}
}
}
post {
success {
echo 'Congratulations!'
}
failure {
echo 'Oh no!'
}
always {
echo 'I will always say Hello again!'
}
}
}
说明:p11.yaml中第10行能直接调用devops是因为项目根目录下有var目录,目录下有devops.groovy脚本
e)结果
提交代码自动触发构建后,查看Blue Ocean,显示正常构建
library集成镜像构建及推送
先在jenkins上创建仓库登陆凭据,ID为 redential-registry ,为后续调用标识

/vars/devops.groovy
import com.crab.devops.Docker
/**
*
* @param repo, harbor.od.com/app/myblog
* @param tag, v1.0
* @param dockerfile
* @param credentialsId
* @param context
*/
def docker(String repo, String tag, String credentialsId, String dockerfile="Dockerfile", String context=".") {
return new Docker().docker(repo, tag, credentialsId, dockerfile, context)
}
/srv/com.crab.devops/Docker.groovy
package com.crab.devops
/**
*
* @param repo
* @param tag
* @param credentialsId
* @param dockerfile
* @param context
* @return
*/
def docker(String repo, String tag, String credentialsId, String dockerfile="Dockerfile", String context="."){
this.repo = repo
this.tag = tag
this.dockerfile = dockerfile
this.credentialsId = credentialsId
this.context = context
this.fullAddress = "${this.repo}:${this.tag}"
this.isLoggedIn = false
return this
}
/**
* build image
* @return
*/
def build() {
this.login()
retry(3) {
try {
sh "docker build ${this.context} -t ${this.fullAddress} -f ${this.dockerfile} "
}catch (Exception exc) {
throw exc
}
return this
}
}
/**
* push image
* @return
*/
def push() {
this.login()
retry(3) {
try {
sh "docker push ${this.fullAddress}"
}catch (Exception exc) {
throw exc
}
}
return this
}
/**
* docker registry login
* @return
*/
def login() {
if(this.isLoggedIn || credentialsId == ""){
return this
}
// docker login
withCredentials([usernamePassword(credentialsId: this.credentialsId, usernameVariable: 'USERNAME', passwordVariable: 'PASSWORD')]) {
def regs = this.getRegistry()
retry(3) {
try {
sh "docker login ${regs} -u $USERNAME -p $PASSWORD"
} catch (Exception exc) {
echo "docker login err, " + ignored.toString()
}
}
}
this.isLoggedIn = true;
return this;
}
/**
* get registry server
* @return
*/
def getRegistry(){
def sp = this.repo.split("/")
if (sp.size() > 1) {
return sp[0]
}
return this.repo
}
Jenkinsfile
@Library('crab-devops') _
pipeline {
agent { label 'jnlp-slave'}
options {
timeout(time: 20, unit: 'MINUTES')
gitLabConnection('gitlab')
}
environment {
IMAGE_REPO = "harbor.od.com/app/myblog"
IMAGE_CREDENTIAL = "credential-registry"
}
stages {
stage('checkout') {
steps {
container('tools') {
checkout scm
}
}
}
stage('docker-image') {
steps {
container('tools') {
script{
devops.docker(
"${IMAGE_REPO}",
"${GIT_COMMIT}",
IMAGE_CREDENTIAL
).build().push()
}
}
}
}
}
post {
success {
echo 'Congratulations!'
}
failure {
echo 'Oh no!'
}
}
}
丰富构建通知逻辑
library集成k8s服务部署
具体步骤过于繁琐,故忽略,此处记载对应的实现流程!
库文件地址:https://gitee.com/crabluo/jenkins-shared-library.git
所有功能已经集成到jenkins-shared-library库中,主要是通过jenkinsfile调用库中的不同功能函数实现对应的功能实现。最重要的是deploy内容部分,此处以此进行说明。
在代码根目录下有目录deploy目录,目录下有yaml资源清单以模板形式存在,即Namespace,images,hostname等等指定内容以变量形式存在,在执行函数的过程中通过读取configmap中的信息而实现对应的内容替换,开发环境cm信息在下文已给出。替换完后apply应用资源清单,再通过代码逻辑实现pod是否正常运行的检测,当检测成功后继续执行下步骤。最后jenkins显示构建成功。
