如果你想实现以下内容,请看此文:

1、代码一提交,就自动发布测试环境  ---jenkins触发器实现
2、可以指定版本号、分支名,拉取代码  ---git命令实现
3、部署生产之前,发一份邮件给老板,请他审核同意发布  --jenkins的邮件功能实现
4、不依赖harbor,加快镜像的io传输速度 ---scp和ssh命令实现

前提

1、部署好你的jenkins
https://www.jenkins.io/zh/doc/book/installing/
2、容器内安装好maven
3、下载好下图的红框的插件
4、配置好ssh、email插件,配置好git凭证

下载好以下插件

在这里插入图片描述

设置构建时输入的参数

发布模式参数

在这里插入图片描述

分支参数

在这里插入图片描述

代码提交的版本号

在这里插入图片描述

部署的测试机器列表参数

在这里插入图片描述

部署的生产机器列表参数

在这里插入图片描述

审核人邮件参数

其实建议审核人邮件写死,但为了快速测试,所有使用手填
在这里插入图片描述

构建页面展示

配置好上面这些构建参数后,你的界面应该如下所示:
在这里插入图片描述

流水线jenkinsfile文件

我自己写的jenkinsfile,仅供参考

def skipProd = true   //是否跳过生产部署
def timeout_mins = 5 //超时时间
def input_message   //提示语
def randomToken    //发布秘钥

//系统个人信息
def Applier_id
def Applier_name
def Applier_mail
// 项目信息
def project_name = "test"
def version = "0.1.0"

// 系统凭证
def git_auth = "git_auth"


pipeline{
    agent any
    options { //调用颜色插件
        ansiColor('xterm')
        skipDefaultCheckout(true)
    }
    environment {
       Applier_name = ""
       Applier_mail = ""
       Operator_mail = ""
       input_message = ""
   }
    stages{
        stage('构建初始化') {
            parallel {
                stage("拉取代码"){
                    steps{
                       withCredentials([usernamePassword(credentialsId: "${git_auth}", usernameVariable: 'USERNAME', passwordVariable: 'PASSWORD')]) {
                          echo "\033[32m ******开始拉取代码${branch}分支代码,revision为${commit}的代码(revision为空时拉取该分支最新代码)****** \033[0m"
                          sh "rm -rf zzw; mkdir zzw;cd zzw;rm -rf test;git clone https://${USERNAME}:${PASSWORD}@gitee.com/mylittlebrother/test.git;cd test;git pull origin ${branch};git reset --hard  ${commit} "
                       }
                    }
                }
                stage("是否发送token邮件"){
                    steps{
                        wrap([$class: 'BuildUser']) {
                           script {
                           //获取当前登录用户账户、姓名、邮箱
                           Applier_id = "${BUILD_USER_ID}"
                           Applier_name = "${env.BUILD_USER}"
                           Applier_mail = "${env.BUILD_USER_EMAIL}"
                           }
                        }
                        script{
                            //  判断是否需要审批
                            if ("$Mode" == "test" || "$Mode" == "" ){
                                echo "\033[32m ******发布测试操作无需审批,待自动执行测试****** \033[0m"
                                skipProd = true
                            }else{
                                skipProd = false
                                echo "\033[32m ******发布生产操作需审批,待自动执行测试环境后,同时还将执行生产审批流程****** \033[0m"
                                randomToken = sh (script: "echo \$RANDOM" , returnStdout: true).trim()
                                input_message = " $Applier_name 申请发布生产"
                                emailext(
                                    subject:"【请审批】${env.JOB_NAME}(#${env.BUILD_NUMBER})生产部署任务",
                                    body:"""$input_message,随机验证码是:${randomToken}!!! <br> <a href="${BUILD_URL}input">请点击该链接登录后审批填入token发布</a><br><h3>或者将token值${randomToken}告诉${Applier_name},让其输入token</h3>""",
                                    to:"${emails}"
                                )
                                echo "\033[32m ******申请邮件已经发送,待$adminUser 审批****** \033[0m"
                            }
                        }
                    }
                }
            }
        }
        stage('编译测试镜像') {
            steps{
                sh "source /etc/profile;java -version;mvn -v;cd zzw/test; mvn  clean package -P test  dockerfile:build  -Dmaven.test.skip=true"
            }
        }
        stage('上传测试镜像') {
            steps{
                script{
                   def imageName = "${project_name}-test:${version}"
                   sh "docker tag ${project_name}:latest  ${imageName}"
                   try {  //删除镜像
                      sh "docker images|grep none|awk '{print \$3 }'|xargs docker rmi"
                   }catch(err) {
                        echo "\033[31m 警告!!!该镜像可能不存在  \033[0m"
                   }

                   sh "pwd; docker save -o ${project_name}-test.tar ${imageName};ls"  //生成测试镜像
                   echo "\033[32m ******测试机器输入是 ${testMachines}****** \033[0m"
                   def  host = "$testMachines".split('@')
                   echo "\033[32m ******测试机器ip是 ${host}****** \033[0m"
                   for (machine in host){
                        if(machine!=null && machine !=''){
                            def ip = machine.split(':')[0]
                            sh " scp -r ${project_name}-test.tar  root@${ip}:/opt/"
                            echo "\033[32m ******${ip}拷贝镜像文件${project_name}-test.tar完成****** \033[0m"
                        }
                    }
                }
            }
        }
        stage('发布测试') {
            steps{
                script{
                    def imageName = "${project_name}-test:${version}"  //测试镜像
                    def delete_running_container = "docker rm  -f \$(docker ps | grep  ${project_name}-test | awk '{print \$1}')"  //删除指定镜像的容器
                    def delete_iamge = "docker rmi  -f \$(docker images | grep  ${project_name}-test | awk '{print \$3}')"  //删除指定镜像

                    def load_image = "cd /opt; docker load -i ${project_name}-test.tar "  //加载指定image
                    def run_test = "docker run -di  -p 1993:1993  ${imageName} "
                    try {  //停止镜像
                       sshPublisher(publishers: [sshPublisherDesc(configName: 'node01', transfers: [sshTransfer(cleanRemote: false, excludes: '', execCommand: "${delete_running_container}", execTimeout: 60000, flatten: false, makeEmptyDirs: false, noDefaultExcludes: false, patternSeparator: '[, ]+', remoteDirectory: '', remoteDirectorySDF: false, removePrefix: '', sourceFiles: '')], usePromotionTimestamp: false, useWorkspaceInPromotion: false, verbose: false)])
                    }catch(err) {
                         echo "\033[31m 警告!!!该容器可能不存在  \033[0m"
                    }
                    try { //停止镜像
                       sshPublisher(publishers: [sshPublisherDesc(configName: 'node01', transfers: [sshTransfer(cleanRemote: false, excludes: '', execCommand: "${delete_iamge}", execTimeout: 60000, flatten: false, makeEmptyDirs: false, noDefaultExcludes: false, patternSeparator: '[, ]+', remoteDirectory: '', remoteDirectorySDF: false, removePrefix: '', sourceFiles: '')], usePromotionTimestamp: false, useWorkspaceInPromotion: false, verbose: false)])
                    }catch(err) {
                         echo "\033[31m 警告!!!该镜像可能不存在  \033[0m"
                    }
                    try { // 加载镜像
                       sshPublisher(publishers: [sshPublisherDesc(configName: 'node01', transfers: [sshTransfer(cleanRemote: false, excludes: '', execCommand: "${load_image}", execTimeout: 60000, flatten: false, makeEmptyDirs: false, noDefaultExcludes: false, patternSeparator: '[, ]+', remoteDirectory: '', remoteDirectorySDF: false, removePrefix: '', sourceFiles: '')], usePromotionTimestamp: false, useWorkspaceInPromotion: false, verbose: false)])
                    }catch(err) {

                    }
                     echo "******开始发布测试环境*****"
                     sshPublisher(publishers: [sshPublisherDesc(configName: 'node01', transfers: [sshTransfer(cleanRemote: false, excludes: '', execCommand: "${run_test}", execTimeout: 60000, flatten: false, makeEmptyDirs: false, noDefaultExcludes: false, patternSeparator: '[, ]+', remoteDirectory: '', remoteDirectorySDF: false, removePrefix: '', sourceFiles: '')], usePromotionTimestamp: false, useWorkspaceInPromotion: false, verbose: false)])
                }
            }
        }
        stage("请输入生产token"){
            when { expression {!skipProd}}
            steps{
                script{
                   def isAbort  = false   //取消按钮
                   timeout(timeout_mins){  //等待审批人审批,并通过timeout设置任务过期时间,防止任务永远挂起
                        try {
                           def userInput = input(
                               id: 'inputap', message: "$input_message", ok:"确认token", submitter:"$adminUser", parameters: [
                               [$class: 'StringParameterDefinition',defaultValue: "", name: 'token',description: '请输入发布的秘钥' ]
                               ])
                           if (userInput == randomToken) {
                               skipProd = false
                           } else {
                               skipProd = true
                               echo "\033[31m 秘钥错误  \033[0m"
                           }
                            echo "\033[31m 当前输入秘钥为: ${userInput}  \033[0m"
                       }catch(err) { // input false
                           echo "******主动拒绝*****"
                           skipProd = true
                       }
                   }
                }
            }
        }
        stage('编译生产镜像') {
            when { expression {!skipProd} }
            steps{
                sh "source /etc/profile;java -version;mvn -v;cd zzw/test; mvn  clean package -P prod    dockerfile:build  -Dmaven.test.skip=true"
            }
        }
        stage("上传生产镜像"){
            when { expression {!skipProd} }
            steps{
                script{
                      def imageName = "${project_name}-prod:${version}"
                      sh "docker tag ${project_name}:latest  ${imageName}"
                      try {  //删除镜像
                         sh "docker images|grep none|awk '{print \$3 }'|xargs docker rmi"
                      }catch(err) {
                           echo "\033[31m 警告!!!该镜像可能不存在  \033[0m"
                      }

                      sh "pwd; docker save -o ${project_name}-prod.tar ${imageName};ls"  //生成生产镜像
                      def  host = "$prodMachines".split('@')
                      echo "\033[32m ******测试机器ip是 ${host}****** \033[0m"
                      for (machine in host){
                           if(machine!=null && machine !=''){
                               def ip = machine.split(':')[0]
                               sh " scp -r ${project_name}-prod.tar  root@${ip}:/opt/"
                               echo "\033[32m ******${ip}拷贝镜像文件${project_name}-prod.tar完成****** \033[0m"
                           }
                       }
                }
            }
        }
        stage("发布生产"){
            when { expression {!skipProd} }
            steps{
                script{
                    def imageName = "${project_name}-prod:${version}"  //测试镜像
                    def delete_running_container = "docker rm  -f \$(docker ps | grep  ${project_name}-prod | awk '{print \$1}')"  //删除指定镜像的容器
                    def delete_iamge = "docker rmi  -f \$(docker images | grep  ${project_name}-prod | awk '{print \$3}')"  //删除指定镜像

                    def load_image = "cd /opt; docker load -i ${project_name}-prod.tar "  //加载指定image
                    def run_prod = "docker run -di  -p 1999:1999  ${imageName} "
                    try {  //停止镜像
                       sshPublisher(publishers: [sshPublisherDesc(configName: 'node01', transfers: [sshTransfer(cleanRemote: false, excludes: '', execCommand: "${delete_running_container}", execTimeout: 60000, flatten: false, makeEmptyDirs: false, noDefaultExcludes: false, patternSeparator: '[, ]+', remoteDirectory: '', remoteDirectorySDF: false, removePrefix: '', sourceFiles: '')], usePromotionTimestamp: false, useWorkspaceInPromotion: false, verbose: false)])
                    }catch(err) {
                         echo "\033[31m 警告!!!该容器可能不存在  \033[0m"
                    }
                    try { //停止镜像
                       sshPublisher(publishers: [sshPublisherDesc(configName: 'node01', transfers: [sshTransfer(cleanRemote: false, excludes: '', execCommand: "${delete_iamge}", execTimeout: 60000, flatten: false, makeEmptyDirs: false, noDefaultExcludes: false, patternSeparator: '[, ]+', remoteDirectory: '', remoteDirectorySDF: false, removePrefix: '', sourceFiles: '')], usePromotionTimestamp: false, useWorkspaceInPromotion: false, verbose: false)])
                    }catch(err) {
                         echo "\033[31m 警告!!!该镜像可能不存在  \033[0m"
                    }
                    try { // 加载镜像
                       sshPublisher(publishers: [sshPublisherDesc(configName: 'node01', transfers: [sshTransfer(cleanRemote: false, excludes: '', execCommand: "${load_image}", execTimeout: 60000, flatten: false, makeEmptyDirs: false, noDefaultExcludes: false, patternSeparator: '[, ]+', remoteDirectory: '', remoteDirectorySDF: false, removePrefix: '', sourceFiles: '')], usePromotionTimestamp: false, useWorkspaceInPromotion: false, verbose: false)])
                    }catch(err) {

                    }
                     echo "******开始发布生产环境*****"
                     sshPublisher(publishers: [sshPublisherDesc(configName: 'node01', transfers: [sshTransfer(cleanRemote: false, excludes: '', execCommand: "${run_prod}", execTimeout: 60000, flatten: false, makeEmptyDirs: false, noDefaultExcludes: false, patternSeparator: '[, ]+', remoteDirectory: '', remoteDirectorySDF: false, removePrefix: '', sourceFiles: '')], usePromotionTimestamp: false, useWorkspaceInPromotion: false, verbose: false)])

                }
            }
        }
    }

}

执行情况

在这里插入图片描述

在这里插入图片描述

Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐