CICD 四(Jenkins jenkins-shared-library 编写)
目录结构

注意 ArgoCDUtils.groovy,BranchUtils.groovy 和 NotifyUtils.groovy 这三个文件保存在 src/cn/edana/jenkins/utils 目录下
ArgoCDUtils.groovy
该代码处理 ArgoCD 相关工作
package cn.edana.jenkins.utils
class ArgoCDUtils {
final Script script
ArgoCDUtils(Script script) {
this.script = script
}
void syncArgoCD(String appName, String prop, String value, String remoteHost, String remoteUsername, String remotePassword) {
// 设置 argocd 操作命令
def setCmd = "argocd app set ${appName} -p ${prop}=${value}"
def syncCmd = "argocd app sync ${appName}"
// 远程 ssh 执行命令
def remote = [:]
remote.name = 'argocd-server'
remote.host = remoteHost
remote.user = remoteUsername
remote.password = remotePassword
remote.allowAnyHosts = true
this.script.sshCommand remote: remote, command: setCmd
this.script.sshCommand remote: remote, command: syncCmd
}
}
BranchUtils.groovy
该代码处理代码分支相关工作
package cn.edana.jenkins.utils
static boolean isMasterBranch(String branchName) {
return "master" == branchName
}
static boolean isReleaseBranch(String branchName) {
return branchName != null && branchName.startsWith("release/")
}
static boolean isAllowAutoDeploy(String branchName) {
return isMasterBranch(branchName) || isReleaseBranch(branchName)
}
NotifyUtils.groovy
该代码处理钉钉通知相关工作
package cn.edana.jenkins.utils
class NotifyUtils {
final Script script
NotifyUtils(Script script) {
this.script = script
}
/**
* 钉钉通知构建成功消息
*
* @param context
*/
void notifySuccess(context) {
def title = "项目【${getJobName()}】构建成功"
notify(title, context)
}
/**
* 钉钉通知构建失败消息
*
* @param context
*/
void notifyFailed(context) {
def title = "项目【${getJobName()}】构建失败,请相关同事注意!"
notify(title, context)
}
/**
* 发送钉钉通知消息
*
* @param context
*/
void notify(String title, context) {
title = title.replace("%2F", "/")
def content = "## [${title}](${getJobUrl()}) \n" +
"--- \n" +
"- **构建仓库**: [${getJobName()}](${context.gitRepo}) \n" +
"- **构建用户**: ${context.username} \n" +
"- **构建分支**: ${context.branchName} \n" +
"- **构建版本**: ${getBuildNumber()} \n" +
"- **构建详情**: [点击查看](${getBuildUrl()})"
this.script.dingtalk(
robot: '7b21fad4-28f7-4fbd-b8df-90bfb0d4f131',
type: 'MARKDOWN',
title: title,
text: [content],
hideAvatar: false
)
}
private String getJobName() {
return this.script.env.JOB_NAME.replace("%2F", "/");
}
private String getJobUrl() {
return this.script.env.JOB_URL;
}
private String getBuildNumber() {
return this.script.env.BUILD_NUMBER
}
private String getBuildUrl() {
return this.script.env.BUILD_URL;
}
}
flaskCI.groovy
该文件在 var 目录下,代码处理 flask 这一类模板代码,
import cn.edana.jenkins.utils.ArgoCDUtils
import cn.edana.jenkins.utils.NotifyUtils
import static cn.edana.jenkins.utils.BranchUtils.isAllowAutoDeploy
import static cn.edana.jenkins.utils.BranchUtils.isMasterBranch
def call(body) {
def config = [
"kAutoDeploy" : false, // 从项目代码 Jenkinsfile 中传入
"dockerRegistry" : "https://registry.cn-shenzhen.aliyuncs.com", // 阿里云 docker 镜像仓库的URL
"dockerNamespace" : "klvchen", // 阿里云 docker 镜像仓库的 名空间
"dingdingId" : "",
"argocdAppName" : "", // 从项目代码 Jenkinsfile 中传入
"argocdTagProp" : "yp-flask.image.tag", // Helm 模板中指定容器 tag 的值
"remoteHost" : "192.168.0.217", // 指定 argocd 命令行所在的IP
"remoteUsername" : "root", // 指定 argocd 命令行所在的用户名
"remotePassword" : "klvchen", // 指定 argocd 命令行所在的密码
]
body.resolveStrategy = Closure.DELEGATE_FIRST
body.delegate = config
body()
def argoCDUtils = new ArgoCDUtils(this);
def notifyUtils = new NotifyUtils(this);
node {
// 是否主分支,只有主分支的包才能部署到Maven,也只有主分支的镜像才能发布到生产环境
def context = [
"gitRepo" : "",
"branchName" : "",
"username" : "",
"projectName": "",
"imageTag" : "",
"gitRepo" : "",
]
def packageJson
// 把 Jenkins 安装 Docker 插件后的命令添加到环境变量中
def dockerHome = tool 'myDocker'
env.PATH = "${dockerHome}/bin:${env.PATH}"
try {
stage('拉取代码') {
checkout scm
print "change git branch: " + env.BRANCH_NAME
// 读取项目代码下的 package.json 到 packageJson 对象
packageJson = readJSON file: 'package.json'
context.projectName = packageJson.name
context.branchName = env.BRANCH_NAME
// 判断分支
if (isMasterBranch(context.branchName)) {
context.imageTag = "${packageJson.version}.${BUILD_NUMBER}"
} else {
context.imageTag = "${packageJson.version}.${BUILD_NUMBER}-test"
}
context.gitRepo = sh(label: '', returnStdout: true, script: 'git config remote.origin.url').trim()
context.username = env.CHANGE_AUTHOR_DISPLAY_NAME
}
if (fileExists("./Dockerfile")) {
// Dockerfile 中包含打包版本
stage("打包镜像: ${context.projectName}") {
def image = docker.build("${config.dockerNamespace}/${context.projectName}")
docker.withRegistry("https://registry.cn-shenzhen.aliyuncs.com") {
if (image != null) {
image.push("${context.imageTag}")
}
}
}
stage('部署到k8s') {
def appName = config.argocdAppName
def branchName = context.branchName
if (appName == null == appName) {
unstable('未配置argocd应用名')
return
}
if (!config.kAutoDeploy) {
unstable('跳过部署')
return
}
if (!isAllowAutoDeploy(branchName)) {
unstable('只有master和release分支允许自动部署')
return
}
try {
// 传入远程 argocd 所在的服务器信息,执行 argocd 命令
argoCDUtils.syncArgoCD(appName, config.argocdTagProp, context.imageTag.toString(), config.remoteHost, config.remoteUsername, config.remotePassword)
} catch (err) { // timeout reached or input Aborted
unstable('部署异常')
print err
}
}
}
// 钉钉通知
notifyUtils.notifySuccess(context)
} catch (e) {
notifyUtils.notifyFailed(context)
throw e
}
}
}

浙公网安备 33010602011771号