jenkins pipeline改造之实现部署完成通知

在开始之前,我认为你已经完成了,jenkins的搭建已经jenkins pipeline的编写,并能正常的发布项目。

实现的成果

image.png

原理介绍

首先企业中使用的开发语言大部分都是java,既然已经使用上k8s了,相信业务架构是微服务类型的。这种微服务我们部署在k8s中时,最常用的一种资源类型时deployment.

我们来看一下deployment资源
我创建了一个deployment

$ kubectl create deploy web --image=nginx -n gebangfeng-test
deployment.apps/web created

而deployment会使用rs去管理我们的pod

$ kubectl get rs  -n gebangfeng-test
NAME                             DESIRED   CURRENT   READY   AGE
web-96d5df5c8                    1         1         1       4m25s

接着我们查一下启动后的pod

$ kubectl get  pod -n gebangfeng-test
NAME                  READY   STATUS    RESTARTS   AGE
web-96d5df5c8-fmk7r   1/1     Running   0          118s

可以看到pod的名字是由deployment名字+rs名字+随机字符组成的。

我们的目的是想实现服务的部署通知,首先我们要知道怎么才能判断服务有没有部署完成。
首先还是那个deployment


image.png

可以看到在deployment一些信息中有Available 即可用的副本数。本来想着这个值可以利用一下,但是deployment的更新策略是滚动更新,deployment不太好判断服务有没有更新完成。deployment的更新操作都是rs来实现的。
deployment的每次更新操作都会创建一个rs完成更新,比如一个应用的需要的副本数是1 准备好了的副本数为1 这样我们就可以认为更新成功了。

方案如下

给rs增加版本标签,每次更新这个标签都会变更,然后我们通过标签去筛选出这次更新的rs,并取出rs需要副本数,和准备好了的副本数。然后进行循环的判断就可以知道服务有没有更新完成了。
准备服务更新文件

cat nginx-deployment.yaml 
apiVersion: apps/v1
kind: Deployment
metadata:
  annotations:
    deployment.kubernetes.io/revision: "1"
  generation: 1
  labels:
    app: web
  name: web
  namespace: gebangfeng-test
spec:
  replicas: 1
  revisionHistoryLimit: 10
  selector:
    matchLabels:
      app: web
  template:
    metadata:
      creationTimestamp: null
      labels:
        app: web
    spec:
      containers:
      - image: nginx:1.22.1
        imagePullPolicy: Always
        name: nginx
      restartPolicy: Always

创建资源

kubectl apply -f   nginx-deployment.yaml 

模拟更新

添加标签

增加标签 version:1


image.png

获取需要的副本数和准备好了的副本数

kubectl get rs -l appversion=1 -n gebangfeng-test


image.png

-l指定新增加的标签,后面通过这个标签去筛选rs,就能准确获取到这次更新的rs了。

  • 获取需要的副本数:
 kubectl get rs -l appversion=1 -n gebangfeng-test -o jsonpath='{.items[0].status.replicas}'
  • 获取ready状态的副本数
 kubectl get rs -l appversion=1 -n gebangfeng-test -o jsonpath='{.items[0].status.readyReplicas}'
image.png

我们获取到了这两个值,然后写个脚本定期去查询,进行判断,就能知道服务是否更新完成了。

脚本检查

我这里写好了一个脚本

  • 首先是发送到微信的脚本
cat /usr/local/scripts/jenkins-weixin.sh
#!/bin/bash
message=$1
date=$(date +%Y-%m-%d)
time=$(date "+%H:%M:%S")
if [ _"${message}" = _"" ]; then
   message='this is test message...'
fi

webHookUrl="https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=*************"
content='{"msgtype": "markdown","markdown": {"content": "'$message'"}}'
echo "content : $content"
curl --data-ascii "$content" $webHookUrl
echo "over!"

webHookUrl使用时需要替换成自己的企业微信群的地址

  • 检查状态的脚本
[root@base4 ~]# cat /usr/local/scripts/jenkins-check.sh
#!/bin/bash
#!/bin/bash
#项目名
#构建版本号
usage(){
    echo "usage: $0 JOB_NAME ITEM_NAME K8S_NAMESPACE JOB_STATUS BUILD_NUM BUILD_USER BUILD_URL COMMENT"
}



JOB_NAME=$1
ITEM_NAME=$2
K8S_NAMESPACE=$3
JOB_STATUS=$4
BUILD_NUM=$5
BUILD_USER=$6
BUILD_URL=$7
COMMENT=$8
if [ $# -lt 8 ]; then
  usage
  exit 1
fi
declare -A userlist='([gebangfeng]='GeBangFeng')'
SendMessage='/usr/local/scripts/jenkins-weixin.sh'
count=1
APP_LIST=(`echo ${ITEM_NAME//,/\ }`)
AccessApp=()
EerorApp=()


Check() {
while true :
do
for app_id in ${!APP_LIST[@]}
do
app_name=${APP_LIST[$app_id]}
replicas=`kubectl get rs -n ${K8S_NAMESPACE}  -l jenkins-build-id=${BUILD_NUM},k8s-app=${app_name}  -o jsonpath='{.items[0].status.replicas}'`
readyReplicas=`kubectl get rs -n ${K8S_NAMESPACE}  -l jenkins-build-id=${BUILD_NUM},k8s-app=${app_name} -o jsonpath='{.items[0].status.readyReplicas}'`

if [ _"${readyReplicas}" = _"${replicas}" ]; then
  echo "服务:${app_name} 发布成功 需要的副本数量:${replicas} 准备好了的副本数: ${readyReplicas}"
  AccessApp[${#AccessApp[*]}]=$app_name
  unset APP_LIST[$app_id]
  #sh /usr/local/scripts/jenkins-weixin.sh ${JOB_NAME} ${ITEM_NAME} "构建成功 ?" ${BUILD_NUM} ${BUILD_USER} ${BUILD_URL}
  #exit 0
else
  if [ $count -gt 100 ];then
  echo "服务:${app_name} 发布未成功, 需要的副本数量:${replicas} 准备好了的副本数: ${readyReplicas}"
  EerorApp[${#EerorApp[*]}]=$app_name
  #sh /usr/local/scripts/jenkins-weixin.sh ${JOB_NAME} ${ITEM_NAME} "构建失败 ?" ${BUILD_NUM} ${BUILD_USER} ${BUILD_URL}
 #exit 1
  else
  echo "服务:${app_name} 第${count} 次检查,发布未成功,继续检查 需要的副本数量:${replicas} 准备好了的副本数: ${readyReplicas}"
  fi
fi
done
if [ $count -gt 100 ];then
  echo "检查周期结束退出循环"
  echo "发布成功的 ${AccessApp[@]} 发布失败的 ${EerorApp[@]}"
  message="**jenkins构建状态通知**
> 任务名称: **${JOB_NAME}**
> 应用名称: **${ITEM_NAME}**
> 构建环境: **${K8S_NAMESPACE}**
> 构建结果: **部分构建失败**
> 构建成功: **${AccessApp[@]}** 
> 构建失败: **${EerorApp[@]}**
> 当前版本: **${BUILD_NUM}**
> 构建发起: **${BUILD_USER}**
> 构建日志: ${BUILD_URL}console
<@${userlist["$BUILD_USER"]}><@gebangfeng>
"
echo $message
sh ${SendMessage} "${message}"
  exit 0
fi

if [ ${#APP_LIST[*]} -eq '0' ];then
  echo "所有服务发布完成"
  echo "发布成功的 ${AccessApp[@]} 发布失败的 ${EerorApp[@]}"
  message="**jenkins构建状态通知**
> 任务名称: **${JOB_NAME}**
> 应用名称: **${ITEM_NAME}**
> 构建环境: **${K8S_NAMESPACE}**
> 构建结果: **构建成功 ✅**
> 当前版本: **${BUILD_NUM}**
> 更新内容: **${COMMENT}**
> 构建发起: **${BUILD_USER}**
<@${userlist["$BUILD_USER"]}>
"
echo $message
sh ${SendMessage} "${message}"
  exit 0
fi

sleep 5
let count++
done
}

#判断状态
if [ ${JOB_STATUS} -eq '0' ];then
   echo "开始更新"
   message="**jenkins构建状态通知**
> 任务名称: **${JOB_NAME}**
> 应用名称: **${ITEM_NAME}**
> 构建环境: **${K8S_NAMESPACE}**
> 构建结果: **开始更新...**
> 当前版本: **${BUILD_NUM}**
> 构建发起: **${BUILD_USER}**
> 构建日志: ${BUILD_URL}console
<@${userlist["$BUILD_USER"]}>
"
echo "${message}" 
#sh ${SendMessage} "${message}"
Check
elif [ ${JOB_STATUS} -eq '1' ];then
   echo "更新失败"
   message="**jenkins构建状态通知**
> 任务名称: **${JOB_NAME}**
> 应用名称: **${ITEM_NAME}**
> 构建环境: **${K8S_NAMESPACE}**
> 构建结果: **构建失败 ❌**
> 当前版本: **${BUILD_NUM}**
> 构建发起: **${BUILD_USER}**
> 构建日志: ${BUILD_URL}console
<@${userlist["$BUILD_USER"]}>
"
echo "${message}" 
sh ${SendMessage} "${message}"
exit 1
else 
    usage 
    exit 1
fi

需要注意的内容SendMessage 替换 微信脚本的路径
userlist时存放企业微信 userid的数组
执行脚本需要传几个参数
JOB_NAME ITEM_NAME K8S_NAMESPACE JOB_STATUS BUILD_NUM BUILD_USER BUILD_URL COMMENT
JOB_NAME是jenkins项目的名字
ITEM_NAME是项目的名字比如我们例子web
K8S_NAMESPACE 是k8s的命名空间
JOB_STATUS 脚本检查状态0是直接发失败消息,1是执行检查操作,
BUILD_NUM是对应jenkns 的BUILD_NUM,用于识别每个更新任务的,这个id也会以标签的方式写入到deployment部署文件中,保证这个标签每次更新服务都能对于的变更
BUILD_USER 更新者的名字 比如gebangfeng 用户@更新的人和消息展示
BUILD_URL 主要用户展示构建通知,一般填写jenkins任务的url,COMMENT填写这次更新的内容

接下来我们来模拟一次完整的过程。更新服务并给服务添加版本的标签,更新后调用脚本去检查更新状态。
删除之前的web项目

kubeclt delete -f nginx-deployment.yaml 

编写更新deployment文件

 cat nginx-deployment.yaml 
apiVersion: apps/v1
kind: Deployment
metadata:
  annotations:
    deployment.kubernetes.io/revision: "1"
  generation: 1
  labels:
    k8s-app: web
    jenkins-job: gebangfeng-test-web-demo
    jenkins-build-id: "1"
  name: web
  namespace: gebangfeng-test
spec:
  replicas: 1
  revisionHistoryLimit: 10
  selector:
    matchLabels:
      k8s-app: web
  template:
    metadata:
      creationTimestamp: null
      labels:
        k8s-app: web
        jenkins-job: gebangfeng-test-web-demo
        jenkins-build-id: "1"
    spec:
      containers:
      - image: nginx:1.22.1
        imagePullPolicy: Always
        name: nginx
      restartPolicy: Always

jenkins-job 代表了jenkins job的名称
jenkins-build-id 代表了jenkins的构建id

image.png
kubectl apply -f nginx-deployment.yaml 

调用脚本去检查

sh jenkins-check.sh test web gebangfeng-test 0 1 gebangfeng https://baidu.com '测试'

$ sh  jenkins-check.sh test web gebangfeng-test 0 1 gebangfeng https://baidu.com '测试'
开始更新
**jenkins构建状态通知**
> 任务名称: **test**
> 应用名称: **web**
> 构建环境: **gebangfeng-test**
> 构建结果: **开始更新...**
> 当前版本: **1**
> 构建发起: **gebangfeng**
> 构建日志: https://baidu.comconsole
<@GeBangFeng>

服务:web 发布成功 需要的副本数量:1 准备好了的副本数: 1
所有服务发布完成
发布成功的 web 发布失败的 
**jenkins构建状态通知** > 任务名称: **test** > 应用名称: **web** > 构建环境: **gebangfeng-test** > 构建结果: **构建成功 ✅** > 当前版本: **1** > 更新内容: **测试** > 构建发起: **gebangfeng** <@GeBangFeng>
content : {"msgtype": "markdown","markdown": {"content": "**jenkins构建状态通知**
> 任务名称: **test**
> 应用名称: **web**
> 构建环境: **gebangfeng-test**
> 构建结果: **构建成功 ✅**
> 当前版本: **1**
> 更新内容: **测试**
> 构建发起: **gebangfeng**
<@GeBangFeng>
"}}
{"errcode":0,"errmsg":"ok"}over!
image.png

和jenkins集成

       post{
        success{
            sh '''
            /usr/local/scripts/jenkins-check.sh ${JOB_NAME} ${ITEMS} ${K8S_NAMESPACE} '0' ${BUILD_NUMBER} ${BUILD_USER_ID} ${BUILD_URL} "${COMMENT}"
            '''
        }
        failure{
            sh '''
            /usr/local/scripts/jenkins-check.sh ${JOB_NAME} ${ITEMS} ${K8S_NAMESPACE} '1' ${BUILD_NUMBER} ${BUILD_USER_ID} ${BUILD_URL} "${COMMENT}"
            '''
        }
    }

失败和成功传递的参数区别在于第四个参数,如果说在发布流水线已经报失败异常了也就没有必要再去调用脚本执行检查操作,传递1说明直接发送是被消息。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 221,548评论 6 515
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 94,497评论 3 399
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 167,990评论 0 360
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,618评论 1 296
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,618评论 6 397
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 52,246评论 1 308
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,819评论 3 421
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,725评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 46,268评论 1 320
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,356评论 3 340
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,488评论 1 352
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 36,181评论 5 350
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,862评论 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,331评论 0 24
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,445评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,897评论 3 376
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,500评论 2 359

推荐阅读更多精彩内容