Jenkins ShareLib
Jenkins Shared Library 是一种复用流水线逻辑的机制,允许在多个 Pipeline 中共享常用的 Step、函数和变量,提高代码复用性和一致性。
目录结构
@libs
├── vars/
│ ├── buildApp.groovy # 全局变量(可直接调用 buildApp())
│ ├── buildApp.txt # 文档(可选)
│ ├── deployToK8s.groovy
│ ├── sendNotification.groovy
│ └── notifySlack.groovy
├── src/
│ └── com/
│ └── example/
│ ├── ServiceUtils.groovy # 类(package com.example)
│ ├── DockerUtils.groovy
│ └── K8sUtils.groovy
└── resources/
└── templates/
└── email-template.html
全局变量(Vars)
基础全局变量
// vars/buildImage.groovy
def call(String imageName, String tag, String registry = 'registry.example.com') {
pipeline {
agent any
}
steps {
script {
def fullImage = "${registry}/${imageName}:${tag}"
echo "Building image: ${fullImage}"
sh '''
docker build -t ${fullImage} .
docker push ${fullImage}
'''
return fullImage
}
}
}
带参数的全流程构建
// vars/buildAndDeploy.groovy
def call(Map config) {
def imageName = config.imageName ?: 'myapp'
def registry = config.registry ?: 'registry.example.com'
def branch = config.branch ?: env.BRANCH_NAME
def environment = config.environment ?: 'staging'
def credentialsId = config.credentialsId ?: 'docker-hub'
pipeline {
agent { label 'docker' }
options {
timeout(time: 30, unit: 'MINUTES')
buildDiscarder(logRotator(numToKeepStr: '10'))
}
stages {
stage('Checkout') {
steps {
checkout scm
}
}
stage('Build') {
steps {
script {
def image = buildImage(imageName, branch, registry)
env.IMAGE_FULL = image
}
}
}
stage('Test') {
steps {
sh 'make test'
}
post {
always {
junit '**/test-results/*.xml'
}
}
}
stage('Deploy') {
when {
branch 'main'
}
steps {
script {
deployToK8s(image: env.IMAGE_FULL, environment: environment)
}
}
}
}
post {
success {
notifySlack("✅ Build succeeded: ${env.IMAGE_FULL}")
}
failure {
notifySlack("❌ Build failed: ${env.JOB_NAME} ${env.BUILD_NUMBER}")
}
}
}
}
src 目录下的类
DockerUtils
// src/com/example/DockerUtils.groovy
package com.example
class DockerUtils implements Serializable {
private static String registry
private static String credentialsId
DockerUtils(String registry, String credentialsId) {
this.registry = registry
this.credentialsId = credentialsId
}
String buildAndPush(String context, String tag) {
def image = "${registry}/${context}:${tag}"
sh "docker build -t ${image} ${context}"
docker.withRegistry("https://${registry}", credentialsId) {
sh "docker push ${image}"
}
return image
}
void pull(String image) {
docker.withRegistry("https://${registry}", credentialsId) {
sh "docker pull ${image}"
}
}
String generateTag(String branch, String commitSha) {
def timestamp = new Date().format('yyyyMMddHHmmss', TimeZone.getTimeZone('UTC'))
if (branch == 'main') {
return "latest"
}
return "${branch}-${commitSha[0..7]}-${timestamp}"
}
}
K8sUtils
// src/com/example/K8sUtils.groovy
package com.example
import com.cloudbees.groovy.cps.NonCPS
class K8sUtils implements Serializable {
private String context
private String namespace
K8sUtils(String context, String namespace) {
this.context = context
this.namespace = namespace
}
void applyYaml(String yamlPath) {
sh "kubectl --context=${context} apply -f ${yamlPath} -n ${namespace}"
}
void rolloutStatus(String deployment) {
sh "kubectl --context=${context} rollout status deployment/${deployment} -n ${namespace}"
}
void setImage(String deployment, String container, String image) {
sh "kubectl --context=${context} set image deployment/${deployment} ${container}=${image} -n ${namespace}"
}
void rollback(String deployment) {
sh "kubectl --context=${context} rollout undo deployment/${deployment} -n ${namespace}"
}
Map getPodStatus(String label) {
def output = sh(
script: "kubectl --context=${context} get pods -n ${namespace} -l ${label} -o json",
returnStdout: true
)
return new groovy.json.JsonSlurper().parseText(output)
}
}
在 Pipeline 中使用
Jenkinsfile
@Library('shared-library@main') _
// 使用全局变量
buildImage('myapp', 'v1.0.0')
// 使用类
def dockerUtils = new com.example.DockerUtils('registry.example.com', 'docker-hub')
def image = dockerUtils.buildAndPush('myapp', 'main')
带参数的 Pipeline
@Library('shared-library@main') _
pipeline {
agent any
parameters {
string(name: 'IMAGE_TAG', defaultValue: 'latest', description: 'Docker image tag')
choice(name: 'ENVIRONMENT', choices: ['dev', 'staging', 'production'], description: 'Deploy environment')
booleanParam(name: 'SKIP_TESTS', defaultValue: false, description: 'Skip test stage')
}
options {
timeout(time: 1, unit: 'HOURS')
buildDiscarder(logRotator(numToKeepStr: '30'))
}
stages {
stage('Build') {
steps {
script {
def dockerUtils = new com.example.DockerUtils('registry.example.com', 'docker-hub')
env.FULL_IMAGE = dockerUtils.buildAndPush('myapp', params.IMAGE_TAG)
}
}
}
stage('Test') {
when {
expression { params.SKIP_TESTS == false }
}
steps {
sh 'make test'
}
}
stage('Deploy') {
steps {
script {
def k8s = new com.example.K8sUtils('production', params.ENVIRONMENT)
k8s.applyYaml('k8s/deployment.yaml')
k8s.rolloutStatus('myapp')
}
}
}
}
}
共享库配置
Global Pipeline Libraries(全局)
在 Manage Jenkins → Configure System → Global Pipeline Libraries:
- Name:
shared-library
- Default version:
main
- Repository URL:
https://github.com/example/jenkins-shared-library
- Credentials: SSH Key 或 Username/Password
Folder-level Libraries
在文件夹配置中添加共享库,仅对该文件夹内的 Job 可见。
测试共享库
使用 JenkinsPipelineUnit 测试
// test/com/example/DockerUtilsTest.groovy
class DockerUtilsTest extends Specification {
@Shared
def jenkinsRule = new JenkinsRule()
def "test build and push"() {
setup:
def pipeline = jenkinsRule.createProject(WorkflowJob)
pipeline.script = '''
@Library('shared-library') _
def dockerUtils = new com.example.DockerUtils('registry.example.com', 'docker-hub')
def image = dockerUtils.buildAndPush('myapp', 'test')
echo "Image: ${image}"
'''
when:
def build = pipeline.scheduleBuild2(0).get()
then:
build.result == Result.SUCCESS
build.logFile.text.contains('Image: registry.example.com/myapp:test')
}
}
文档生成
为全局变量创建 .txt 文件,Jenkins 会自动生成文档:
// vars/buildImage.txt
## buildImage
Builds a Docker image and pushes to registry.
### Parameters
- `imageName` (String): Name of the image to build
- `tag` (String): Image tag
- `registry` (String, optional): Registry URL, defaults to 'registry.example.com'
### Example
buildImage('myapp', 'v1.0.0')
### Notes
- Requires Docker daemon access
- Uses Kaniko for Kubernetes builds
版本管理
使用 Git Tag 管理版本
@Library('shared-library@1.2.0') _
Changelog 策略
# v1.2.0
- Added: `buildImage()` global variable
- Fixed: K8sUtils.rolloutStatus() timeout issue
- Changed: Default registry to registry.example.com
# v1.1.0
- Added: DockerUtils class
- Added: K8sUtils class
最佳实践
- 版本锁定:生产环境使用固定版本
@Library('shared-library@v1.0.0')
- 文档完整:为每个全局变量编写
.txt文档
- 测试覆盖:使用 JenkinsPipelineUnit 编写单元测试
- 幂等性:Step 应可重复执行
- 错误处理:明确异常信息,提供回滚机制
- 最小权限:共享库不持有敏感信息,通过参数传入
下一步
- Jenkins 自动化构建 — Jenkins 基础与进阶
- GitOps 实践 — GitOps 部署模式
- DevOps 标准化 — 共享库治理