GitLab/GitHub分支合并代码后Jenkins使用Docker无感更新到服务器

效果

代码提交后触发hook,通知jenkins构建,jenkins构建成功后发送镜像到服务器并运行容器,容器运行成功后shell修改nginx配置文件切换到新容器完成服务无感发布。

提交代码到github后,效果如下。可根据不同分支发布到不同环境

基础环境

1、GitHub新建项目、并设置webHook

2、搭建jenkins、并添加基础组件(Generic Webhook Trigger、Send files or execute commands over SSH)

3、nginx搭建并修改初始化配置文件

配置t1.docker.vip域名为所有服务的根域名

t1.docker.vip/saas/指向项目名为saas的服务(对应的.localhost和upstrem由jenkins生成)

t1.docker.vip/event/执行项目名为event的服务(对应的.localhost和upstrem由jenkins生成)

t1.docker.vip.conf文件的内容

#加载对应位置的所有upstream文件(jenkins会生成)
include /etc/nginx/conf.d/*.upstream;


server {
    listen       80;
    listen  [::]:80;
    server_name  t1.docker.vip;

    #加载对应位置的所有localhost文件(jenkins会生成)
    include /etc/nginx/conf.d/*.localhost;
}

构建任务

1、创建自由风格任务,构建出发器勾选:Generic Webhook Trigger,GitHub提交代码后会触发代码构建。

2、GitHub事件参数获取

3、WebHooks过滤

4、执行shell

#!/bin/bash
# 判断是否webHook触发
if [ -z "$repository" ]; then
    echo "非hook触发构建,退出....."
    exit
fi
#set -x 开启调试模式
#set -x
#定义一个全局异常消息变量
shellErrMsg=""

#构建通知:企业微信机器人链接
noteUrl=https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=XXXXXX
#发送企业微信通知方法
sendMsg(){
  curl -X POST \
    -H "Content-Type: application/json" \
    -d "{
          \"msgtype\": \"markdown\",
          \"markdown\": {
              \"content\": \"$1\"
          }
      }" \
    ${noteUrl}
}


#异常事件执行方法
error_handler() {
  shellErrMsg="shell执行异常退出;行:$1."
  echo $shellErrMsg
  exit 1
}
#退出事件执行方法
exit_handler(){
  if [ -n "$shellErrMsg" ]; then
    sendMsg "发布失败:"$shellErrMsg
  else
    sendMsg ${repository}":"$(basename $branch)"."${BUILD_NUMBER}"发布成功"
  fi
}

# 设置 trap 捕获错误
trap 'error_handler $LINENO' ERR
# 捕获退出事件
trap 'exit_handler' EXIT


msg="项目:${repository};分支:$(basename $branch);事件:${x_github_event}\n\n开始构建:\n"

mapfile -t commits_array < <(echo "$commits" | jq -c '.[]')

for obj in "${commits_array[@]}"; do
    message=$(echo "$obj" | jq -r '.message')
    committer=$(echo "$obj" | jq -r '.committer')
    name=$(echo "$committer" | jq -r '.name')
    username=$(echo "$committer" | jq -r '.username')
    #msg+="$(echo "$message" | tr '\n' ' ')-${name}\n"
    
    cleaned_message=$(echo "$message" | sed "s/\\'\''/ /g; s/'//g")
    msg+=$cleaned_message"-"${name}"\n"
done
#发送构建通知到企业微信
escaped_msg=$(printf '%s' "$msg" | sed 's/"/\\\"/g; s/\n/\\n/g')
sendMsg "$escaped_msg"

pwd
#删除原构建信息
rm -rf $repository
ls -l

#git clone制定项目分支的代码
cloneResult=$(git clone -b $(basename $branch) https://[github-Token]@github.com/XXXX/${repository}.git 2>&1)

ls -l

#进入clone的代码
cd $repository
# node项目 运行build编译(不同代码换位不同逻辑即可)
yarn run tar
#打包位docker镜像并推送到阿里云(项目根目录有Dockerfile文件)
docker build -t registry.cn-shanghai.aliyuncs.com/namespace/${repository}:$(basename $branch).${BUILD_NUMBER} .
docker login -p docker仓库密码 --username=docker仓库账号  registry.cn-shanghai.aliyuncs.com
docker push registry.cn-shanghai.aliyuncs.com/namespace/${repository}:$(basename $branch).${BUILD_NUMBER}
docker logout  registry.cn-shanghai.aliyuncs.com
#运行新构建的镜像
containerStr=""
for ((i=1; i<=2; i++)); do
    # 保存容器名到变量,nginx配置文件后续会更新为代理新的容器
	containerStr+="server "${repository}.${i}.${BUILD_NUMBER}":8000;"
    # 容器需与nginx服务器再同一个网络: --network saas-docker-net,只有在同一个网络才可以通过容器名访问,新的容器名为:服务名.容器编号.镜像版本
	docker run --name ${repository}.${i}.${BUILD_NUMBER} --restart always --network saas-docker-net -e RUN_ENV=t1 -d registry.cn-shanghai.aliyuncs.com/namespace/${repository}:$(basename $branch).${BUILD_NUMBER}
done
sleep 5

cd ../
# 将新的容器信息写入upstream文件,后续更新nginx 重新读取该文件
tee ${repository}.upstream <<EOF
upstream ${repository} {
    ${containerStr}
}
EOF
# 将新的容器信息写入location 文件,后续更新nginx 重新读取该文件
tee ${repository}.localhost <<EOF
location ~ ^/${repository}/(.*) {
        proxy_pass  http://${repository}/\$1;
  }
EOF
#移动新的localhost文件和upstream文件到nginx配置文件下
mv -f ${repository}.upstream /var/lib/docker/volumes/nginx_config/_data/conf.d/
mv -f ${repository}.localhost /var/lib/docker/volumes/nginx_config/_data/conf.d/
#更新nginx指向新的容器
docker exec nginx nginx -t
docker exec nginx nginx -s reload
#删除老容器
# 遍历每行输出
docker ps -a|grep ${repository} | while read -r line; do
    containerId=$(echo $line | awk '{print $1}')
    image=$(echo $line | awk '{print $2}')
    if [[ $image == *.${BUILD_NUMBER} ]]; then
        echo "当前运行容器,不删除"
    else
        echo "正在停止并删除服务:"$containerId
        docker stop $containerId
        docker rm $containerId
        echo $containerId" 停止 删除  成功"
    fi
done
#删除老镜像
docker images |grep ${repository}|grep $(basename $branch) | while read -r line; do
    image=$(echo $line | awk '{print $1}')
    tag=$(echo $line | awk '{print $2}')
    imageId=$(echo $line | awk '{print $3}')
    if [[ $tag == *.${BUILD_NUMBER} ]]; then
        echo "当前运行镜像,不删除"
    else
        echo "正在删除容器:"${image}':'${tag}
        docker rmi ${image}':'${tag}
    fi
done

#set +x

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值