系列文章目录
文章目录
前言
在云原生与微服务架构日益普及的今天,高效的CI/CD流水线已成为企业提升交付效率的核心引擎。本文将分享一套基于Jenkins与Kubernetes深度集成的企业级CI/CD实践方案,通过 动态Slave Pod调度 、 Harbor镜像全生命周期管理 和 参数化多环境部署 三大核心设计,结合Pipeline+Groovy脚本实现从代码提交到生产部署的分钟级自动化流水线。
架构图
一、环境准备
ip | 部署 |
---|---|
192.168.56.101 | k8s-master(1.28)、harbor、docker、docker-compose |
192.168.56.102 | k8s-node(1.28)、Jenkins(非容器化master) |
二、静态slave
三、动态slave
四、Jenkins部署及相关插件下载
可参考https://blog.csdn.net/weixin_50902636/article/details/143600389 文章进行docker部署
1.部署jenkins2.462+jdk17
登录192.168.56.102机器
代码如下(示例):
[root@k8s-node ~]# wget https://mirrors.tuna.tsinghua.edu.cn/jenkins/redhat/jenkins-2.462-1.1.noarch.rpm
[root@k8s-node ~]# rpm --import https://pkg.jenkins.io/redhat-stable/jenkins.io.key
[root@k8s-node ~]# rpm -ivh jenkins-2.462-1.1.noarch.rpm
[root@k8s-node ~]# systemctl enable --now jenkins
[root@k8s-node ~]# wget https://download.java.net/java/GA/jdk17.0.2/dfd4a8d0985749f896bed50d7138ee7f/8/GPL/openjdk-17.0.2_linux-x64_bin.tar.gz
[root@k8s-node ~]# tar xf openjdk-17.0.2_linux-x64_bin.tar.gz -C /export/
[root@k8s-node ~]# cd /export/jdk-17.0.2/bin/
[root@k8s-node ~]# ln -s /export/jdk-17.0.2/bin/java /usr/bin/java
[root@k8s-node ~]# java -version
openjdk version "17.0.2" 2022-01-18
OpenJDK Runtime Environment (build 17.0.2+8-86)
OpenJDK 64-Bit Server VM (build 17.0.2+8-86, mixed mode, sharing)
2.访问Jenkins下载插件
可参考这篇文章进行插件下载https://blog.csdn.net/weixin_50902636/article/details/143508066
下载汉化插件
下载kubernetes插件
其余pipeline插件、选项插件、git插件等就不一一展示了,详情见这个资源插件包,导入即可
五、Jenkins配置Cloud
1.Jenkins开启agent节点通道
2.配置Cloud
2.1创建凭据
2.2.配置cloud
2.3.配置pod Template
添加harbor仓库凭据
选择对应的凭据
#同时要在k8s集群的default命名空间下创建这个secret
[root@k8s-master ~]# kubectl create secret generic registy-secert --from-file=.dockerconfigjson=/root/.docker/config.json --type=kubernetes.io/dockerconfigjson -n default
2.4.创建流水线项目测试
pipeline {
// 使用k8s拉起slave
agent {
kubernetes {
cloud 'kubernetes' ##此处的名称必须和Jenkins凭据中定义的k8s config 的名称一致
inheritFrom 'jenkins-slave' ##此处必须和cloud配置的名称一致
namespace 'default' ##此处必须和cloud配置的名称一致
}
}
stages {
stage('输出pods名称') {
steps {
sh 'hostname'
}
}
stage('等待时间') {
steps {
sh 'sleep 3'
}
}
}
}
结果示例
至此cloud配置完成
六、Jenkins集成Gitee
gitee插件在插件包中有,此处不再掩饰插件安装过程
1.gitee创建API令牌
提交后,输入gitee密码,然后将显示出来的凭据复制一份
2.Jenkins添加Gitee API凭据
3.Jenkins中配置Gitee
测试出现成功即可
七、Jenkins集成共享库(jenkinslib)
共享库是配合pipeline实现整个构建过程,其封装了pipeline中的一些操作。它以仓库的形式保存于gitee中
1.Jenkins结合gitee配置ssh密钥
在Jenkins服务器的工作目录下创建ssh密钥。默认工作目录是/var/lib/jenkins/
[root@k8s-node .ssh]# ssh-keygen -t ed25519 -C "Gitee SSH Key"
[root@k8s-node .ssh]# ls -l
total 16
-rw------- 1 root root 390 Jan 12 21:25 authorized_keys
-rw------- 1 root root 399 Apr 30 15:09 id_ed25519
-rw-r--r-- 1 root root 95 Apr 30 15:09 id_ed25519.pub
-rw-r--r-- 1 root root 521 Apr 30 17:42 known_hosts
复制公钥id_ed25519.pub内容到gitee
在Jenkins服务验证能否连接到gitee
jenkins凭据添加ssh密钥
2.Jenkins集成共享库配置
八、Jenkins集成邮件通知
1. 创建邮箱服务凭据
授权码获取自行百度
2.Jenkins配置邮箱通知
至此邮件配置完成
九、共享库groovy脚本封装
1.k8s.groovy脚本示例
1、该脚本的作用是在启动构建时,动态的在k8s集群中启动一个pod
2、该脚本封装了maven、jdk、kubectl、docker、nodejs镜像,满足前后端服务打包构建、推送构建好的镜像到harbor仓库
class K8s {
def call(Map config = [:]) {
return """
apiVersion: v1
kind: Pod
metadata:
labels:
jenkins: slave
spec:
securityContext:
runAsUser: 0
containers:
- name: mvn
image: ${config.mavenImage ?: 'harbor.jdicity.local/registry/maven:3.8.6-jdk-8'}
imagePullPolicy: IfNotPresent
command: ["cat"]
tty: true
env:
- name: TZ
value: Asia/Shanghai
- name: LANG
value: en_US.UTF-8
- name: LC_ALL
value: en_US.UTF-8
volumeMounts:
- name: jenkins-home
mountPath: /root/.m2
- name: time
mountPath: /etc/localtime
readOnly: true
- name: docker
image: ${config.mavenImage ?: 'harbor.jdicity.local/registry/docker:19.03'}
imagePullPolicy: IfNotPresent
command: ["cat"]
tty: true
env:
- name: TZ
value: Asia/Shanghai
- name: LANG
value: en_US.UTF-8
- name: LC_ALL
value: en_US.UTF-8
volumeMounts:
- name: dockersocket
mountPath: /run/docker.sock
- name: docker-config
mountPath: /etc/docker/daemon.json
- name: npm
image: ${config.nodejsImage ?: 'harbor.jdicity.local/registry/nodejs:v18'}
imagePullPolicy: IfNotPresent
command: ["cat"]
tty: true
env:
- name: TZ
value: Asia/Shanghai
- name: LANG
value: en_US.UTF-8
- name: LC_ALL
value: en_US.UTF-8
// - name: sonar --环境资源不足
// image: ${config.sonarImage ?: 'harbor.jdicity.local/registry/sonar-scanner:2.3.0'}
// imagePullPolicy: IfNotPresent
// command: ["cat"]
// tty: true
// env:
// - name: TZ
// value: Asia/Shanghai
// - name: LANG
// value: en_US.UTF-8
// - name: LC_ALL
// value: en_US.UTF-8
- name: kubectl
image: ${config.kubectlImage ?: 'harbor.jdicity.local/registry/kubectl:1.28.2'}
imagePullPolicy: IfNotPresent
tty: true
command: ["sleep"]
args: ["infinity"]
env:
- name: TZ
value: Asia/Shanghai
- name: LANG
value: en_US.UTF-8
- name: LC_ALL
value: en_US.UTF-8
volumes:
- name: jenkins-home
persistentVolumeClaim:
claimName: jenkins-home-pvc
- name: dockersocket
hostPath:
path: /run/docker.sock
- name: docker-config
hostPath:
path: /etc/docker/daemon.json
type: File
- name: time
hostPath:
path: /usr/share/zoneinfo/Asia/Shanghai
"""
}
}
pipeline中调用
#!groovy
@Library("jenkinslib") _ #引入共享库
def k8s=new org.devops.k8s()
agent {
kubernetes {
cloud 'kubernetes' // 对应 Jenkins 中配置的 Kubernetes 云名称
inheritFrom 'jenkins-slave' // 继承的 Pod 模板(可选)
namespace 'default' // 命名空间
yaml k8s() // 调用共享库生成 Pod YAML
}
}
十、CI阶段流程
因为电脑资源不足,就省略了代码扫描阶段
1.拉取代码
1.1.k8s集群配置gitee域名解析
[root@k8s-master ~]# kubectl edit configmaps -n kube-system coredns
添加如下部分
gitee.com:53 {
forward . /etc/reslove.conf
}
1.2. 声明式stage
#结合Jenkins流水线项目中的参数化构建-->设置字符参数 SrcURL 然后将其赋值给srcURL参数,实现在pipeline中调用
String srcURL="${env.SrcURL}"
#结合Jenkins流水线项目中的参数化构建-->设置git参数 branchName 然后将其赋值给branch参数,实现在pipeline中调用
String branch="${env.branchName}"
#结合Jenkins流水线项目中的参数化构建-->设置布尔值参数 rollback 然后再pipeline中调用,用于判断是否回滚
Boolean rollback = (env.rollback == 'true')
stage("CheckOut"){
when { expression { !rollback } } #非回滚时执行
steps{
script{
tools.PrintMsg("获取分支: ${branch}","checkout")
checkout([$class: 'GitSCM', branches: [[name: "${branch}"]],
extensions: [],
userRemoteConfigs: [[credentialsId: 'gitee_registry_ssh', url: "${srcURL}"]]])
#此处的'gitee_registry_ssh'就是Jenkins凭据创建的SSH密钥名称
}
}
}
2.代码编译
2.1.声明式stage
build.groovy脚本示例
#调用共享库,实现命令传参调用
def build=new org.devops.build()
#结合Jenkins流水线项目中的参数化构建-->设置字符参数 buildType 然后将其赋值给buildType参数,实现在pipeline中调用
String buildType="${env.buildType}"
#结合Jenkins流水线项目中的参数化构建-->设置字符参数 buildshell 然后将其赋值给buildshell参数,实现在pipeline中调用
String buildshell="${env.buildshell}"
#结合Jenkins流水线项目中的参数化构建-->设置布尔值参数 rollback 然后再pipeline中调用,用于判断是否回滚
Boolean rollback = (env.rollback == 'true')
stage("Build"){
when { expression { !rollback } } // 非回滚时执行
steps{
script{
//集成构建工具
container('mvn') {
tools.PrintMsg("代码打包","build")
build.Build(buildType,buildshell)
}
}
}
}
3.生成镜像tag
3.1.声明式stage
#结合Jenkins流水线项目中的参数化构建-->设置字符参数 imageTag 然后将其赋值给imageTag参数,实现在pipeline中调用
String imageTag="${env.imageTag}"
stage("镜像tag"){
when { expression { !rollback } } // 非回滚时执行
steps{
script{
tools.PrintMsg("获取镜像tag","image_tag")
// 使用 Jenkins 主机的本地时间(绕过容器时钟问题)
TimeZone.setDefault(TimeZone.getTimeZone("Asia/Shanghai"))
env.BUILD_TIME = new Date().format("yyyyMMdd_HHmmss")
// 组合完整Tag
env.FULL_IMAGE_TAG = "${imageTag}"+"_"+env.BUILD_TIME
env.FULL_IMAGE_NAME="${env.HARBOR_URL}/${env.PROJECT_GROUP}/${imageName}:${env.FULL_IMAGE_TAG}"
tools.PrintMsg("生成镜像Tag: ${FULL_IMAGE_TAG}", "image_tag")
tools.PrintMsg("生成镜像地址: ${FULL_IMAGE_NAME}", "image_tag")
}
}
}
4.镜像构建
Harbor.groovy脚本示例
1、通过获取凭据登录harbor仓库
2、通过docker、Dockerfile构建服务镜像
3、推送镜像到harbor仓库中
4、从本地删除镜像,释放服务器资源
4.1.声明式stage
String imageName="${env.imageName}"
stage("镜像构建"){
when { expression { !rollback } } // 非回滚时执行
steps{
script{
container('docker') {
tools.PrintMsg("代码打包","image_build")
harbor.BuildImage(
this,
'HARBOR_ID',
env.HARBOR_URL,
env.PROJECT_GROUP,
"${imageName}",
env.FULL_IMAGE_TAG)
}
}
}
}
5.生成部署模板
支持deployment、statefulset两种类型
5.1.声明式stage
String controllerType="${env.controllerType}"
stage("生成部署模板") {
when { expression { !rollback } }
steps {
container('kubectl') {
script {
tools.PrintMsg("并行生成部署模板","template")
// 根据资源类型选择模板
def templateFile = ("${controllerType}".toLowerCase() == 'statefulset') ?
'statefulset-template.yaml' : 'deployment-template.yaml'
// 并行生成不同类型的模板
parallel(
"生成${controllerType}模板": {
// 读取模板内容
String template = readFile("${templateFile}")
// 定义替换变量
def replacements = [
'${imageName}' : "${imageName}",
'${replicas}' : "${replicas}",
'${FULL_IMAGE_NAME}': env.FULL_IMAGE_NAME,
'${containerPort}' : "${containerPort}",
'${k8s_ns}' : "${k8s_ns}"
]
// 执行替换并写入文件
String yamlContent = replacements.inject(template) {
content, entry -> content.replace(entry.key, entry.value)
}
writeFile file: "${WORKSPACE}/${controllerType}.yaml", text: yamlContent
},
"生成Service模板": {
// 读取模板内容
String templatesvc = readFile('svc-template.yaml')
// 定义替换变量
def replacements = [
'${imageName}' : "${imageName}",
'${containerPort}': "${containerPort}",
'${k8s_ns}' : "${k8s_ns}"
]
// 执行替换并写入文件
String svcYaml = replacements.inject(templatesvc) {
content, entry -> content.replace(entry.key, entry.value)
}
writeFile file: "${WORKSPACE}/svc.yaml", text: svcYaml
},
failFast: true // 任一失败则立即终止
)
}
}
}
}
十一、CD阶段
1.发布服务
k8sdeploy.groovy脚本示例
1、根据选择的发布环境,获取到凭据中导入的k8s config 名称
2、根据选择的发布环境和发布的类型、命名空间等信息,发布对应的yaml文件和svc.yaml文件
3、通过rollout 观察pod 状态running时 继续执行下一步操作,否则返回发布失败
1.1.声明式stage
#!groovy
@Library("jenkinslib") _
//func from sharelibrary调用共享库
def k8sdeploy=new org.devops.k8sdeploy()
def tools=new org.devops.tools()
//调用Jenkins中定义的选项参数 名称和Jenkins中定义的保持一致
//from jenkins 参数化构建变量
String Tenv="${env.Tenv}"
String k8s_ns="${env.k8s_ns}"
String controllerType="${env.controllerType}"
String imageName="${env.imageName}"
String imageTag="${env.imageTag}"
String replicas="${env.replicas}"
String containerPort="${env.ContainerPort}"
Boolean rollback = (env.rollback == 'true')
stage("部署到k8s"){
when { expression { !rollback } } // 非回滚时执行
steps{
script{
container('kubectl') {
tools.PrintMsg("部署到${Tenv}环境","deploy")
k8sdeploy.Deploy(
this,
"${Tenv}",
"${controllerType}",
"${imageName}",
"${env.FULL_IMAGE_NAME}",
"${k8s_ns}"
)
// 在发布阶段将镜像名称保存到 env.FULL_IMAGE_NAME
env.FULL_IMAGE_NAME = "${env.FULL_IMAGE_NAME}"
currentBuild.description = "${env.FULL_IMAGE_NAME}"
}
}
}
}
在下方添加此groovy脚本,实现动态获取k8s集群中的命名空间
try {
// 指定 kubectl 和 kubeconfig 的绝对路径
def cmd = "/usr/bin/kubectl --kubeconfig=/var/lib/jenkins/.kube/config get namespaces -o jsonpath='{.items[*].metadata.name}'"
def process = cmd.execute()
// 捕获标准错误输出
def errorStream = new StringBuffer()
process.consumeProcessErrorStream(errorStream)
// 等待命令完成
process.waitFor()
// 处理输出
def output = process.text.trim().replaceAll("'", "") // 清理单引号
def error = errorStream.toString().trim()
println "✅ 标准输出: ${output}"
println "❌ 错误输出: ${error}"
if (process.exitValue() == 0) {
def namespaces = output.split(/\s+/)
namespaces = namespaces.findAll { !it.startsWith('kube-') && it != 'default' }
return namespaces
} else {
return ["Error: ${error}"]
}
} catch (Exception e) {
return ["Error: ${e.message}"]
}
2.回滚服务
回滚groovy脚本示例
2.1.声明式stage
stage("是否回滚"){
when { expression { rollback } } // 回滚时执行
steps{
script{
container('kubectl') {
tools.PrintMsg("回滚到${Tenv}环境","rollback")
def rollbackImage = k8sdeploy.Rollback(
this,
"${Tenv}",
"${controllerType}",
// 'k8s',
"${imageName}",
"${k8s_ns}"
)
// 保存回滚镜像信息
env.FULL_IMAGE_NAME = rollbackImage // 使用回滚镜像替换 FULL_IMAGE_NAME
// 保存回滚镜像信息
currentBuild.description = "${rollbackImage}"
}
}
}
}
}
十二、构建结果使用邮件发送
toemail.grovy脚本示例
1、不管Jenkins构建成功还是失败,回滚成功/失败,都发送邮件
2、邮件内容包含构建结果、微服务名称、发布的镜像地址(回滚的镜像地址)、仓库地址、仓库分支、构建用户、构建URL、构建日志URL、构建编号、构建时间、构建持续时间
声明式stage
post {
always {
script {
// 获取构建时间和持续时间
TimeZone.setDefault(TimeZone.getTimeZone("Asia/Shanghai"))
env.BUILD_TIME = new Date().format("yyyyMMdd_HHmmss")
def buildTime = env.BUILD_TIME ?: "N/A"
def buildDuration = currentBuild.durationString ?: "N/A"
// 发送邮件
toemail.Email(
currentBuild.currentResult,
"${env.emailUser}",
"${imageName}",
"${branch}",
"${env.BUILD_USER}",
buildTime,
buildDuration,
rollback,
"${k8s_ns}",
currentBuild.description,
"${srcURL}"
)
}
}
}
注意事项
如果需要获取到构建用户名称和时间,则需要安装build user vars plugin插件.然后选择开启
十三、实战:构建springboot项目
1.准备工作
编写一个springboot项目,上传到igtee仓库,如下所示
2.jenkins构建
2.1.构建参数设置
2.2.发布构建过程
引入共享库Jenkinslib
创建动态pod
拉代码
代码编译
生成镜像tag
代码构建、推送到harbor仓库
生成部署模板
发布到指定环境
邮件通知
2.3.回滚过程
只需要勾选rollabck、选择k8s命名空间、回滚环境、服务类型、服务名称即可
回滚示例
回滚邮件发送
十四、完整jenkinsfile示例
groovy脚本+声明式pipeline组合而成
#!groovy
@Library("jenkinslib") _
//func from sharelibrary调用共享库
def build=new org.devops.build()
def k8s=new org.devops.k8s()
def k8sdeploy=new org.devops.k8sdeploy()
def tools=new org.devops.tools()
def harbor=new org.devops.Harbor()
def toemail=new org.devops.toemail()
//调用Jenkins中定义的选项参数 名称和Jenkins中定义的保持一致
//from jenkins 参数化构建变量
String Tenv="${env.Tenv}"
String buildType="${env.buildType}"
String buildshell="${env.buildshell}"
String deployHosts="${env.deployHosts}"
String srcURL="${env.SrcURL}"
String branch="${env.branchName}"
String k8s_ns="${env.k8s_ns}"
String controllerType="${env.controllerType}"
String imageName="${env.imageName}"
String imageTag="${env.imageTag}"
String replicas="${env.replicas}"
String containerPort="${env.ContainerPort}"
Boolean rollback = (env.rollback == 'true')
// 固定配置
env.HARBOR_URL = "harbor.jdicity.local"
env.PROJECT_GROUP = "registry"
pipeline{
agent {
kubernetes {
cloud 'kubernetes' // 对应 Jenkins 中配置的 Kubernetes 云名称
inheritFrom 'jenkins-slave' // 继承的 Pod 模板(可选)
namespace 'default' // 命名空间
yaml k8s() // 调用共享库生成 Pod YAML
}
}
options {
timestamps()
skipDefaultCheckout() // 禁用隐式 Checkout
timeout(time: 1, unit: 'HOURS') //设置流水线超时
}
stages{
stage("CheckOut"){
when { expression { !rollback } } // 非回滚时执行
steps{
script{
tools.PrintMsg("获取分支: ${branch}","checkout")
tools.PrintMsg("获取代码","checkout")
checkout([$class: 'GitSCM', branches: [[name: "${branch}"]],
extensions: [],
userRemoteConfigs: [[credentialsId: 'gitee_registry_ssh', url: "${srcURL}"]]])
}
}
}
stage("Build"){
when { expression { !rollback } } // 非回滚时执行
steps{
script{
//集成构建工具
container('mvn') {
tools.PrintMsg("代码打包","build")
build.Build(buildType,buildshell)
}
}
}
}
stage("镜像tag"){
when { expression { !rollback } } // 非回滚时执行
steps{
script{
tools.PrintMsg("获取镜像tag","image_tag")
// 使用 Jenkins 主机的本地时间(绕过容器时钟问题)
TimeZone.setDefault(TimeZone.getTimeZone("Asia/Shanghai"))
env.BUILD_TIME = new Date().format("yyyyMMdd_HHmmss")
// 组合完整Tag
env.FULL_IMAGE_TAG = "${imageTag}"+"_"+env.BUILD_TIME
env.FULL_IMAGE_NAME="${env.HARBOR_URL}/${env.PROJECT_GROUP}/${imageName}:${env.FULL_IMAGE_TAG}"
tools.PrintMsg("生成镜像Tag: ${FULL_IMAGE_TAG}", "image_tag")
tools.PrintMsg("生成镜像地址: ${FULL_IMAGE_NAME}", "image_tag")
}
}
}
stage("镜像构建"){
when { expression { !rollback } } // 非回滚时执行
steps{
script{
container('docker') {
tools.PrintMsg("代码打包","image_build")
harbor.BuildImage(
this,
'HARBOR_ID',
env.HARBOR_URL,
env.PROJECT_GROUP,
"${imageName}",
env.FULL_IMAGE_TAG)
}
}
}
}
stage("生成部署模板") {
when { expression { !rollback } }
steps {
container('kubectl') {
script {
tools.PrintMsg("并行生成部署模板","template")
// 根据资源类型选择模板
def templateFile = ("${controllerType}".toLowerCase() == 'statefulset') ?
'statefulset-template.yaml' : 'deployment-template.yaml'
// 并行生成不同类型的模板
parallel(
"生成${controllerType}模板": {
// 读取模板内容
String template = readFile("${templateFile}")
// 定义替换变量
def replacements = [
'${imageName}' : "${imageName}",
'${replicas}' : "${replicas}",
'${FULL_IMAGE_NAME}': env.FULL_IMAGE_NAME,
'${containerPort}' : "${containerPort}",
'${k8s_ns}' : "${k8s_ns}"
]
// 执行替换并写入文件
String yamlContent = replacements.inject(template) {
content, entry -> content.replace(entry.key, entry.value)
}
writeFile file: "${WORKSPACE}/${controllerType}.yaml", text: yamlContent
},
"生成Service模板": {
// 读取模板内容
String templatesvc = readFile('svc-template.yaml')
// 定义替换变量
def replacements = [
'${imageName}' : "${imageName}",
'${containerPort}': "${containerPort}",
'${k8s_ns}' : "${k8s_ns}"
]
// 执行替换并写入文件
String svcYaml = replacements.inject(templatesvc) {
content, entry -> content.replace(entry.key, entry.value)
}
writeFile file: "${WORKSPACE}/svc.yaml", text: svcYaml
},
failFast: true // 任一失败则立即终止
)
}
}
}
}
stage("部署到k8s"){
when { expression { !rollback } } // 非回滚时执行
steps{
script{
container('kubectl') {
tools.PrintMsg("部署到${Tenv}环境","deploy")
k8sdeploy.Deploy(
this,
"${Tenv}",
"${controllerType}",
"${imageName}",
"${env.FULL_IMAGE_NAME}",
"${k8s_ns}"
)
// 在发布阶段将镜像名称保存到 env.FULL_IMAGE_NAME
env.FULL_IMAGE_NAME = "${env.FULL_IMAGE_NAME}"
currentBuild.description = "${env.FULL_IMAGE_NAME}"
}
}
}
}
stage("是否回滚"){
when { expression { rollback } } // 回滚时执行
steps{
script{
container('kubectl') {
tools.PrintMsg("回滚到${Tenv}环境","rollback")
def rollbackImage = k8sdeploy.Rollback(
this,
"${Tenv}",
"${controllerType}",
// 'k8s',
"${imageName}",
"${k8s_ns}"
)
// 保存回滚镜像信息
env.FULL_IMAGE_NAME = rollbackImage // 使用回滚镜像替换 FULL_IMAGE_NAME
// 保存回滚镜像信息
currentBuild.description = "${rollbackImage}"
}
}
}
}
}
post {
always {
script {
// 获取构建时间和持续时间
TimeZone.setDefault(TimeZone.getTimeZone("Asia/Shanghai"))
env.BUILD_TIME = new Date().format("yyyyMMdd_HHmmss")
def buildTime = env.BUILD_TIME ?: "N/A"
def buildDuration = currentBuild.durationString ?: "N/A"
// 发送邮件
toemail.Email(
currentBuild.currentResult,
"${env.emailUser}",
"${imageName}",
"${branch}",
"${env.BUILD_USER}",
buildTime,
buildDuration,
rollback,
"${k8s_ns}",
currentBuild.description,
"${srcURL}"
)
}
}
}
}
总结
至此,一套完整的springboot+k8s+jenkins+动态slave+pipeline的CICD流水线项目就完整的落地了,关于代码扫描部分,因服务器资源不足,便再本篇中没有实现!!!