1987WEB视界-分享互联网热门产品和行业

您现在的位置是:首页 > WEB开发 > 正文

WEB开发

Jenkins多分支流水线

1987web2023-10-06WEB开发94

Jenkins+Docker+git实现多环境快速交付-compose优化升级一文中我们使用docker-compose对项目的环境校验、发版/回滚/重启、操作校验等步骤进行了优化。但是由于job使用的是自由风格项目或mvn项目,因此都是一个分支对应一个job,虽然也可以通过参数化构建方式实现一个job对应多个分支,常此以往一个项目需要建立很多job,管理非常不便。

解决方案:

Jenkin多分支流水线,允许Jenkinsfile与需要 Jenkins 构建的应用程序代码放在一起,然后 Jenkins 从源代码管理系统中检出 Jenkinsfile 文件作为流水线项目构建过程的一部分并接着执行你的流水线。

下面我们就来体验下Jenkins多分支的构建过程吧。

Jenkinsfile

Jenkins流水线的定义通常需要写入到一个文本文件(称为 Jenkinsfile )中,该文件可以被放入项目的源代码版本库中。

注意:Jenkinsfile放到项目版本库的根路径下。

在此我们还是延续使用helloworld的java项目。

Jenkinsfile的代码如下:

vim Jenkinsfile
pipeline {
    options {
        ansiColor(xterm)
        timestamps()
    }
    agent {
        labeldocker-slave-java}
    triggers {
      GenericTrigger (causeString:Generic Cause, genericVariables: [[defaultValue:deploy, key:deploy_env, regexpFilter:, value:]], regexpFilterExpression:, regexpFilterText:, token:123456)
    }

    environment {
        APP_NAME ="helloworld"IMAGE_NAME ="helloworld/helloworld"MONITOR_URL ="http://127.0.0.1:8080"JAVA_OPTS ="-Xmx128m -Xms128m -Dspring.profiles.active=branch"PORT ="9080:8080"}
    parameters {
        choice choices: [deploy,rollback,restart], description:deploy:发布
    rollback:回滚
    restart:重启
    注意:restart 参数只适用与docker环境, name:deploy_envstring defaultValue:0, description:回滚版本号,发版时忽略
    注意:
    版本号为git commitid,如7e2c56522188c98f6294d91c8568dfcedf994e42。, name:version, trim: false
    }

    stages {
        stage(操作校验) {
            steps {
                sh label:, script:echo ${APP_NAME}
                操作校验
                if [ "${deploy_env}" = "deploy" ];then
                    echo -e "\\033[34mstart ${deploy_env}\\033[0m"
                    echo ${GIT_PREVIOUS_SUCCESSFUL_COMMIT}
                    echo ${GIT_COMMIT}
                    [ "${GIT_PREVIOUS_SUCCESSFUL_COMMIT}" != "${GIT_COMMIT}" ] && echo -e "\\033[34mstart maven package\\033[0m" || {
                        版本未更新,停止发版
                        echo -e "\\033[31mRepositories not update, stop ${deploy_env}\\033[0m"
                        exit 1
                    }

                    /usr/local/maven/bin/mvn clean package docker:build -DdockerImageTags=${GIT_COMMIT} -Dmaven.test.skip=true -DpushImageTag

                    [ $? -eq 0 ] && echo -e "\\033[32mmaven package success\\033[0m" || {
                        echo -e "\\033[31mmaven package fail\\033[0m"
                        exit 1
                    }
                elif [ "${deploy_env}" = "rollback" ];then
                    echo -e "\\033[34mstart ${deploy_env}\\033[0m"
                    echo ${GIT_PREVIOUS_SUCCESSFUL_COMMIT}
                    echo ${GIT_COMMIT}
                    查看远程分支是否有此版本
                    git branch -r --contains $version
                    [ $? -eq 0 ] && echo -e "\\033[34mstart docker steps\\033[0m" || {
                        echo -e "\\033[31mverison is wrong,please check version\\033[0m"
                        exit 1
                    }
                fi}
        }
        stage(开发部署) {
            when {
                branchdevelop}
            steps {
                sshPublisher(publishers: [sshPublisherDesc(configName:test-3.63, transfers: [sshTransfer(cleanRemote: false, excludes:, execCommand:"""
                !/bin/bash
                IN_FACE=`/sbin/route -n |awk \{if(\$4~/UG/){print \$8}}\|head -n 1`
                LOCAL_IP=`/sbin/ip addr show \"\${IN_FACE}\" | grep -w \inet\ | awk \{print \$2}\`

                CONTAINER_NAME=`echo ${IMAGE_NAME} | awk -F/ \{print \$2}\`
                删除老镜像
                DEL_IMAGE() {
                    echo -e "\\033[34mrm image ${IMAGE_NAME}:\$1\\033[0m"
                    sudo docker image rm harbor.cityre.cn/${IMAGE_NAME}:\$1 --no-prune
                    [ \$? -eq 0 ] && echo -e "\\033[32mrm ${IMAGE_NAME}:\$1 succss \\033[0m" || {
                        echo -e "\\033[31mrm ${IMAGE_NAME}:\$1 fail \\033[0m"
                        exit 1
                    }
                }

                健康检查
                HEALTHCHECK() {
                    timeout=180
                    echo -e "\\033[34mhealth check\\033[0m"
                    for (( i=1;i<=\$timeout;i++ ))
                    do
                        status=\$(sudo docker inspect --format=\{{json .State.Health}}\ \${CONTAINER_NAME}|grep -Po \"Status[":]+\\K[^"]+\)
                        echo \$status
                        if [ \$status = \healthy\ ];then
                           echo -e "\\033[32m\${LOCAL_IP} \${CONTAINER_NAME}  status is \${status}\\033[0m"
                           [ ${deploy_env} != "restart" ] && DEL_IMAGE \${OLD_VERSION}
                           exit 0
                        elif [ \$status = \starting\ ];then
                           sleep 23
                        else
                           echo -e "\\033[31m\${LOCAL_IP} \${CONTAINER_NAME} status is \${status}\\033[0m"
                           exit 1
                        fi
                    done
                }


                定义docker-compose变量,注意第一步清空env,后续追加env
                INIT_VAR() {
                    echo -e "\\033[34minit docker-compose variable\\033[0m"
                    echo "IMAGE_NAME=${IMAGE_NAME}" > .env
                    echo "CONTAINER_NAME=\${CONTAINER_NAME}" >> .env
                    echo "APP_NAME=${APP_NAME}" >> .env
                    echo "MONITOR_URL=${MONITOR_URL}" >> .env
                    echo "PORT=${PORT}" >> .env
                    echo "JAVA_OPTS=\$(echo ${JAVA_OPTS}|sed s/branch/test/)" >> .env
                }

                进入项目目录
                cd /App/java_app_tmp/${APP_NAME}
                提前读取env文件中的老版本号,用于删除老镜像
                [ -f .env ] && OLD_VERSION=\$(grep VERSION .env|awk -F= \{print \$2}\)

                case ${deploy_env} in
                deploy)
                    echo -e "\\033[34mstart ${deploy_env} steps\\033[0m"
                    INIT_VAR
                    echo "VERSION=${GIT_COMMIT}" >> .env
                    sudo docker-compose up -d --build
                    HEALTHCHECK
                    ;;
                rollback)
                    echo -e "\\033[34mstart ${deploy_env} steps\\033[0m"
                    INIT_VAR
                    echo "VERSION=${version}" >> .env
                    sudo docker-compose up -d --build
                    HEALTHCHECK
                    ;;
                restart)
                    sudo docker-compose restart
                    HEALTHCHECK
                    ;;
                *)
                    exit 1
                    ;;
                esac""", execTimeout:120000, flatten: false, makeEmptyDirs: false, noDefaultExcludes: false, patternSeparator:[, ]+, remoteDirectory:, remoteDirectorySDF: false, removePrefix:, sourceFiles:)], usePromotionTimestamp: false, useWorkspaceInPromotion: false, verbose: false)])
            }
        }
        stage(测试部署) {
            when {
                branchdevelop}
            steps {
                shuname -a}
        }
    }
    post {
        unstable {
            emailext (
                body:"""项目名称:${JOB_NAME}\n构建编号:${BUILD_NUMBER}\n构建日志:${BUILD_URL}console""",
                subject:【Jenkins构建通知】:$JOB_NAME - Build  $BUILD_NUMBER - Unstable!,
                to:test@test.cn,from:jenkins@test.cn)
        }
        success {
            emailext (
                body:"""项目名称:${JOB_NAME}\n构建编号:${BUILD_NUMBER}\n构建日志:${BUILD_URL}console""",
                subject:【Jenkins构建通知】:$JOB_NAME - Build  $BUILD_NUMBER - Successful!,
                to:test@test.cn,from:jenkins@test.cn)
        }
        failure {
            emailext (
                body:"""项目名称:${JOB_NAME}\n构建编号:${BUILD_NUMBER}\n构建日志:${BUILD_URL}console""",
                subject:【Jenkins构建通知】:$JOB_NAME - Build  $BUILD_NUMBER - Failure!,
                to:test@test.cn,from:jenkins@test.cn)
        }
    }
}

我们在git版本中分了dev、test、master三个分支,分别对应开发、测试、生产三个环境,Jenkinsfile中通过when+branch来分别匹配不同的分支执行的操作。如下:

when{branchdevelop}

本次实验我们设置:

  1. 开发部署实现开发分支的docker构建。
  2. 测试部署实现测试分支的输出内核信息。
  3. 邮件通知实现失败/成功/不稳定等3个维度的邮件通知。

Jenkins构建

Jenkins流水线使用Blue Ocean效果更佳哦。

  1. 新建多分支流水线项目

我们的项目为docker-test-java3

  1. 配置多分支流水线

我们只需配置git代码库即可,此时会自动检测分支。如果代码库中没有Jenkinsfile会提示报错。

我们只需在对应分支直接构建即可。

  1. 构建

总结

从以上过程我们可以看出,多分支流水线的重点在于Jenkinsfile文件,但是由于多分支流水线需要Jenkins放在版本库中,因此运维也要像开发一样维护Jenkinsfile,容易导致版本冲突。

因此对于此种情况,我认为还是需要扩展共享库的,这样可以进一步优化为多个项目使用同一套流水线,运维只需维护扩展共享库即可。