zoukankan      html  css  js  c++  java
  • jenkins使用+pipeline

    参考:CI/CD:Jenkins Pipeline 实践_遇事不决 可问春风-CSDN博客

    一、安装jenkins

    1.1 下载 rpm 包

    清华大学镜像站下载:

    https://mirrors.tuna.tsinghua.edu.cn/jenkins/redhat-stable/
    

    1.2 安装并启动

    sudo yum install jenkins-2.204.3-1.1.noarch.rpm
    

    1.3 下载 war包

    https://mirrors.tuna.tsinghua.edu.cn/jenkins/war-stable/
    比如:
    wget https://mirrors.tuna.tsinghua.edu.cn/jenkins/war-stable/2.277.4/jenkins.war
    

    1.4 扔进 tomcat启动

    通过tomcat启动:http://192.168.8.129:8200/jenkins/

    启动时需要输入秘钥,在cat /root/.jenkins/secrets/initialAdminPassword里面

    输入秘钥后,需要下载插件。根据需要选择下载(比较慢)

    安装失败,两种解决方式,一种是手动安装,另一种是更换源

    https://mirrors.tuna.tsinghua.edu.cn/jenkins/updates/current/update-center.json
    

    二、安装 maven

    地址

    http://maven.apache.org/download.cgi
    

    解压

    tar -zxvf apache-maven-3.6.1-bin.tar.gz
    

    设置环境变量(得先有jdk)

    vi /etc/profile
    
    export MAVEN_HOME=/usr/local/maven/apache-maven-3.8.1
    export PATH=$MAVEN_HOME/bin:$PATH 
    
    source /etc/profile
    

    三、配置私钥公钥,拉取代码

    3.1 服务器端生成公钥私钥

    公钥私钥生成 - dongye95 - 博客园 (cnblogs.com)

    3.2 gitlab端


    3.3 jenkins端


    可以页面拉取

    四、Pipeline

    教程:https://www.w3cschool.cn/jenkins/jenkins-epas28oi.html

    4.1 CI/CD

    	持续集成 (Continuous integration)是一种软件开发实践,即团队开发成员经常集成它们的工作,通过每个成员每天至少集成一次,也就意味着每天可能会发生多次集成。每次集成都通过自动化的构建(包括编译,发布,自动化测试)来验证,从而尽早地发现集成错误。
    
    	持续部署(continuous deployment)是通过自动化的构建、测试和部署`循环`来快速交付高质量的产品。某种程度上代表了一个开发团队工程化的程度,毕竟快速运转的互联网公司人力成本会高于机器,投资机器优化开发流程化相对也提高了人的效率,让 engineering productivity 最大化。
    

    4.2 pipeline 简介

    	pipeline,即流水线,是jenkins2.X的新特性,是jenkins官方推荐使用的持续集成方案。与传统的自由风格项目不同,它是通过 `jenkins DSL` 编写代码来实现。相比于之前用户只能通过Web界面进行配置的方式来定义Jenkins任务,现在通过使用 `jenkins DSL` 和 `Groovy` 语言编写程序,用户可以定义流水线并执行各种任务。
    

    4.3 Jenkinsfile

    那么重点来了,流水线代码写在哪里呢?
    答案就是 Jenkinsfile

    	在 jenkins 2 中,流水线配置可以从 jenkins 中剥离出来。在自由风格等项目中,任务的配置都是以配置文件的形式保存在 jenkins 的服务器上的,这意味这所有的配置的变更都依赖于 jenkins 的web界面。当配置中使用了许多插件时,去维护他人构建的配置就十分繁琐。在流水线项目中,可以在Web界面中编写流水线脚本,也可以将脚本以文本形式保存在外部的版本控制系统中,这个文本就是 Jenkinsfile。
    
    	对于 git 项目,推荐使用多分支流水线。将任务配置和流水线信息保存在Jenkinsfile 中,把 jenkinsfile 保存在项目的根目录下。不同的项目和分支都会有自己的 Jenkinsfile,其内容各不相同。这样一个多分支流水线 project 可以对不同的分支代码进行持续集成和持续部署。
    
    	使用 Jenkinsfile 可以像管理项目中代码一样通过文件的形式来管理jenkins任务,支持历史追溯和差异对比等功能。
    

    4.4 流水线语法

    	流水线语法有两种:一种是脚本式流水线,另一种是声明式流水线。下面对两种语法进行简单介绍。更详细的内容请查阅[官方文档](https://jenkins.io/zh/doc/book/pipeline/syntax/)。
    

    4.4.1 脚本式流水线

    	流水线代码就是 Groovy 脚本,其中插入了部分针对jenkins的DSL步骤。这种方式几乎没有结构上的约束,程序流程也基于Groovy语法结构实现。这种方式更加灵活,但是需要会使用Groovy。
    
    Jenkinsfile (Scripted Pipeline)
        
    node {
    	stage('Example') {
    		if (env.BRANCH_NAME == 'master') {
                echo 'I only execute on the master branch'
            } else {
                echo 'I execute elsewhere'
            }
        }
    }
    

    4.4.2 声明式流水线

    	相对于脚本式流水线的灵活,声明式流水线比较严谨。它的结构更加清晰,更加接近自由风格类型的项目。同时,清晰的结构有助于错误检查,上手简单,对Blue Ocean(下面会讲到)的支持也好。官方推荐使用这种语法格式。
    	通过下面的示例,可以看到一个stage就是一个阶段,每个阶段内是步骤和相关配置。agent 标识了阶段在哪个节点上卖弄执行。相关语法会在下面结合实际项目进行讲解。
    	如果声明式流水线不能满足我们的需求,那么我们可以在声明式脚本中使用脚本式流水线,具体方法在下一章中。
    
    Jenkinsfile (Declarative Pipeline)
        
      pipeline {
        agent none 
        stages {
            stage('Example Build') {
                agent { docker 'maven:3-alpine' } 
                steps {
                    echo 'Hello, Maven'
                    sh 'mvn --version'
                }
            }
            stage('Example Test') {
                agent { docker 'openjdk:8-jre' } 
                steps {
                    echo 'Hello, JDK'
                    sh 'java -version'
                }
            }
        }
    }
    

    在本文的实践环节中,会使用声明式语法来演示一个多分支流水线的project。

    4.5 Blue Ocean

    Blue Ocean 是 jenkins2 中全新的可视化界面(需要安装Blue Ocean插件)。它为流水线的每一个阶段都添加了图形化展示,可以查看每一个阶段的状态和进展,对每个阶段、每个任务都有点选式日志查看的功能,十分清晰。

    优势

    1. 灵活性:通过脚本的方式要比只依赖于WEB界面配置的方式要灵活。
    2. 可追溯性:jenkinsfile管理在源码下,可对配置进行历史追溯和差异比对。
    3. 清晰性:结构清晰,便于排错。
    4. 可恢复性:可以基于某一个版本的配置进行重新运行。

    五、多分支流水线实践

    5.1 配置简述

    已经安装pipeline相关插件。实践的对象是一个git项目。一共三个分支:maste、test、script。`每个分支下都有一个Jenkinsfile`
    

    三个分支的配置基本相同,主要步骤如下:
    拉取代码—>maven打包—>构建镜像—>测试—>推送harbor仓库—>部署发布

    上述基本完成了一个项目的持续集成和持续部署

    5.2 新建 project

    	新建一个多分支流水线project,源码管理选择git,然后填上项目的git地址。如果权限正常的话,在保存后Jenkins会扫描项目的所有分支下的Jenkinsfile,自动创建流水线并执行。
    


    	查看新增的多分支流水线(这里为了测试,只在pipeitest分支下写了Jenkinsfile,所以显示只有一个)。
    

    	点击左侧的打开Blue Ocean进入可视化界面。
    

    5.3 脚本编写

    5.3.1 代码拉取

    stages {
    	stage('Git Pull') {
    		steps {
    			git(url: 'git@192.168.8.79:ub/ub-user.git', branch: 'pipetest',credentialsId: '2c9193b1-0a5e-4bf9-9d6f-c7b503637bc6')
                echo 'pull seccess'
    		}
    	}
    }
    
    • url: 源代码地址
    • branch:git分支
    • credentialsId:凭证(username and password)

    5.3.2 Maven打包

    项目是一个SpringBoot的Java项目,通过maven构建jar包。

    stage('Maven Build') {
    	steps {
    		sh 'mvn clean install'
    	}
    }
    

    sh 就是执行shell 命令
    注意:在test分支中做了testNG测试,此时执行 ‘mvn clean install’ 会在打包时进行测试。如果test分支此阶段不想做测试,则打包时忽略测试

    stage('Maven Build') {
    	steps {
    		sh 'mvn clean install -Dmaven.test.skip=true'
    	}
    }
    

    此时打包完成,最终的包已经在 workspace 里面有了

    可以将打包文件保存为“制品”(即归档文件)

    假设我们想保存script分支构建得到的jar包,那么可以通过

    stage('Maven Build') {
    	steps {
    		sh 'mvn clean install -Dmaven.test.skip=true'
    		echo 'maven打包成功'
    		sh 'tar -zcvf user-app.tar.gz user-app/target/user-app'
    		echo 'tar包打成功'
    		archive 'user-app.tar.gz'
    	}
    }
    

    但是这样每次打包都有归档文件,不会自动删除,需要谨慎,防止磁盘空间不够

    5.3.3 设置环境变量

    在进行下一阶段前,先解决一个比较重要的问题,在流水线中如何配置环境变量。

    environment {
            registryUrl= "192.168.1.110:5000"       //搭建docker私有仓库(Harbor)或者 用DockerHub 又或者用云平台的“容器镜像服务”
            registry_user= "xxx"
            registry_pass= "xxx"
      IMAGE_NAME = 'image_neme'
      CONTAINER_NAME = 'container_name'
    }
    

    声明式流水线的环境变量配置是声明在environment块中。这里我声明了两个环境变量,一个是镜像名称,一个是容器名称。这两个变量在后面的阶段中会反复使用。
    environment 可以声明在pipeline块下作用于整个配置,也可以声明在一个stage下只作用于一个阶段。
    环境变量的调用方式与shell一样,如:${CONTAINER_NAME}

    5.3.4 构建镜像

    pipeline 针对docker做了分装,其自己定义了一套语法规则来进行容器的操作。
    例如:

    build(image[,args])
    

    使用当前目录的Dockerfile,运行docker build来创建一个镜像并打上标签。

    Image.run([args,command])
    

    使用docker run来运行一个镜像,同时返回一个容器。

    Image.pull()
    

    运行 docker pull

    除了以上列出的几个,还有其他的许多方法。但是我并不愿意使用这些方法。原因有两个,一个是docker 命令本身就不复杂,使用起来就比较方便。另一个原因是使用docker命令比二次分装的方法更加灵活。

    下面正式开始进行镜像的构建

    stage('Build Image') {
      steps {
        sh '''VERSION=$(date +%Y%m%d%H%M%S)
              echo "$(date +%Y%m%d%H%M%S)" > ${WORKSPACE}/VERSION
              echo "building image: ${IMAGE_NAME}_${BRANCH_NAME}:${VERSION}"
              docker build -t ${IMAGE_NAME}_${BRANCH_NAME}:${VERSION} .'''
    	}
    }
    

    镜像由镜像名称和镜像TAG构成。
    对于镜像名称,由于是多分支流水线,这里采用基础镜像名称+分支名称组合的形式。
    tag的作用就是表明版本,此处采用构建时间,精确到秒。将构建时间保存在文件中,之后所有的阶段都读取该文件来获取版本。当然我们还可以选择构建号或自定义等变量作为tag(如下),但是这种方式在唯一性方面不如时间方式。此处可根据实际业务进行选择。

    sh ' docker build -t ${IMAGE_NAME}_${BRANCH_NAME}:${BUILD_NUMBER} .'
    

    5.3.5 测试

    在每次构建后,我们都应该对当前版本的代码做自动化测试,通过冒烟等测试来评估当前版本的质量。保证我们要发布版本的质量是过关的,如果任何一个测试步骤失败则后续阶段不会继续,应用也不会发布。这也是持续集成的重要思想。

    5.3.5.1 启动服务以及环境容错处理

    严格的说,服务的启动不应该和测试放在一个阶段,应该在一个单独的阶段中执行,此处为了方便进行了简写。
    了解docker就会知道,同名的容器没有被删除,那么容器是无法启动的。如果由于上次构建失败或其他原因导致目标容器名称的容器存在,那么在容器启动前进行环境清理就很有必要。

    steps {
      script {
        try {
          sh '''environmental_clean(){
                docker_ps=`docker ps | grep ${CONTAINER_NAME}_${BRANCH_NAME}`
                docker_psa=`docker ps -a | grep ${CONTAINER_NAME}_${BRANCH_NAME}`
    
    			# -eq是判断是否等于的意思,$docker_ps执行成功为0,失败为1
                if [[ 0 -eq $docker_ps ]];  
                then
                    #容器未启动
                    echo "容器${CONTAINER_NAME}_${BRANCH_NAME}未启动"
                else
                    echo "停止容器"
                    docker stop ${CONTAINER_NAME}_${BRANCH_NAME}
                fi
    
                if [[ 0 -eq $docker_psa ]];
                then
                    echo "容器${CONTAINER_NAME}_${BRANCH_NAME}不存在"
                else
                    echo "删除容器"
                    docker rm ${CONTAINER_NAME}_${BRANCH_NAME}
                fi
                }
                #docker 环境清理
                environmental_clean'''
        }
        catch (exc) {
            echo '环境不需要清理'
        }
    }
    

    脚本很简单,通过判断docker进程是否存在来停止或删除容器。
    重点是通过script块在声明式代码中引用了脚本式的代码。为什么要这样做呢?
    前面已经讲过了这是一个容错处理,如果环境不干净就清理,但如果环境中无目标容器名称的容器从在,在‘docker_ps=docker ps | grep ({CONTAINER_NAME}_){BRANCH_NAME}’执行完后会返回-1,与shell脚本不同,pipeline规定当返回结果不是表示成功时,流水线就会终止,此处为了流水线可以继续走下去,用try catch做异常处理。
    如果不借助脚本式语法,声明式流水线可以在sh步骤开始加入 ‘set +e’,则在出现错误后不会停止。此处主要是为了演示如何在声明式代码中引用脚本式的代码。

    启动容器

    sh '''VERSION=$(cat ${WORKSPACE}/VERSION)
    docker run -dit --name=${CONTAINER_NAME}_${BRANCH_NAME} ${IMAGE_NAME}_${BRANCH_NAME}:${VERSION}'''
    

    5.3.5.2 测试

    流水线不仅可以串行也可以并行。在测试阶段我们就可以进行并行操作。

    如图所示,在test分支的Test阶段,ui自动化、接口自动化、性能测试、单元测试等都可以并行执行。
    在pipeline脚本中 parallel 块内的 stage 块会并行执行。

    stage('Test') {
        parallel {
            stage('接口自动化测试') {
                    steps {
                        sh  '''echo "进行接口自动化测试"
                            mvn clean test
                            echo "自动化测试完成" '''
                    }
                }
    
            stage('UI自动化测试') {
                steps {
                echo 'ui test'
                }
            }
        }
    }
    

    5.3.5.3 发布 HTML 报告

    将html报告进行发布。
    在testNG执行完后会在项目test-output目录下生成report.html,将报告发布。安装 HTML Publisher plugin 插件。

    post {
      always {
        publishHTML([
          allowMissing: false,
          alwaysLinkToLastBuild: false,
          keepAll: true,
          reportDir: "test-output",
          reportFiles: "report.html",
          reportName:"testNg report"
      ])
        }
      }
    

    post块的作用是在所有步骤最后执行,可以作用于整个pipeline或一个阶段内。always表示不管是成功还是失败都执行。

    同样在制品中查看

    点击报告查看(出现样式问题点击这里

    5.3.6 推送镜像到仓库

    代码测试完成后就可以将镜像推送到远程仓库了。
    仓库是我自己搭建的harbor。

    stage('Push to Harbor') {
      steps {
        withCredentials(bindings: [usernamePassword(credentialsId: 'e8dc0fa7-3547-4b08-8b7b-d9e68ff6c18f', passwordVariable: 'password', usernameVariable: 'username')]) {
          sh 'docker login -u $username -p $password harbor.guojiaxing.red'
        }
    
        sh '''export VERSION=$(cat ${WORKSPACE}/VERSION)
          echo "docker push ${IMAGE_NAME}_${BRANCH_NAME}:${VERSION}"
          docker push ${IMAGE_NAME}_${BRANCH_NAME}:${VERSION}'''
      }
    

    pipeline中的鉴权方式是withCredentials(),这需要事先在jenkins配置中保存凭据。(如果不用鉴权方式,就必须写上用户名和密码的明文,不安全)

    5.3.7 pipeline 调用不同凭证的方法

    5.3.7.1 使用SSH私钥文件

    withCredentials([file(credentialsId: 'secret', variable: 'FILE')]) {
        sh 'use $FILE'
    }
    

    5.3.7.2 使用以冒号分隔的帐号密码

    withCredentials([usernameColonPassword(credentialsId: 'gitlab', variable: 'USERPASS')]) {
    	sh '''
    	  git clone https://$USERPASS@********
    	'''
    }
    

    5.3.7.3 使用字符串类型密钥

    withCredentials([string(credentialsId: “CRET-ID”, variable: "varName")]){
        sh "echo $varName"
    }
    

    5.3.7.4 获取用户名密码

    withCredentials([usernamePassword(credentialsId: “CRET-ID”, usernameVariable: "username", passwordVariable: "password")]){
        sh "echo $username $password"
    }
    

    5.3.8 部署到远程机器上

    安装 SSH Pipeline Steps 插件。配置username and password 凭据。

    stage('ssh deploy') {
      steps {
        script {                 
            def remote = [:]
            remote.name = 'gjx_server'
            remote.host = 'www.guojiaxing.red'
            remote.allowAnyHosts = true
            withCredentials([usernamePassword(credentialsId: 'gjx-server', passwordVariable: 'password', usernameVariable: 'username')]) {
                remote.user = "${username}"
                remote.password = "${password}"
            }
            sshCommand remote: remote, command: "docker pull ${IMAGE_NAME}_${BRANCH_NAME}:${BUILD_NUMBER}"            
        }
    }
    

    ssh pipeline 更多的操作请查阅官方文档

    5.3.9 构建后操作

    5.3.9.1 环境清理

    在作用于pipeline全局的post中进行环境清理

    always {
          script {
            try{
                sh '''environmental_clean(){
                    docker_ps=`docker ps | grep ${CONTAINER_NAME}_${BRANCH_NAME}`
                    docker_psa=`docker ps -a | grep ${CONTAINER_NAME}_${BRANCH_NAME}`
    
                    if [[ 0 -eq $docker_ps ]];
                    then
                        #容器未启动
                        echo "容器${CONTAINER_NAME}_${BRANCH_NAME}未启动"
                    else
                        echo "停止容器"
                        docker stop ${CONTAINER_NAME}_${BRANCH_NAME}
                    fi
    
                    if [[ 0 -eq $docker_psa ]];
                    then
                        echo "容器${CONTAINER_NAME}_${BRANCH_NAME}不存在"
                    else
                        echo "删除容器"
                        docker rm ${CONTAINER_NAME}_${BRANCH_NAME}
                    fi
                    }
                    #docker 环境清理
                    environmental_clean
                    export BUILD_NUMBER=$(cat ${WORKSPACE}/BUILD_NUMBER)
                    docker rmi ${IMAGE_NAME}_${BRANCH_NAME}:${BUILD_NUMBER}'''
            }
             catch (exc) {
                  echo '镜像不需要删除'
              }
          }
    
    

    5.3.9.2 发送邮件

    安装 Email Extension Plugin 插件并完成邮件配置
    在作用于pipeline全局的post中编写邮件配置

    failure {
           emailext (
           subject: "FAILED: Job '${env.JOB_NAME} [${env.BUILD_NUMBER}]' 自动化测试结果",
           body: '''<body leftmargin="8" marginwidth="0" topmargin="8" marginheight="4" offset="0">
                       <table width="95%" cellpadding="0" cellspacing="0"
                       style="font-size: 11pt; font-family: Tahoma, Arial, Helvetica, sans-serif">
                           <tr>
                                   <td><br />
                                   <b><font color="#0B610B">构建信息</font></b>
                                   <hr size="2" width="100%" align="center" /></td>
                               </tr>
                               <tr>
                                   <td>
                                       <ul> 
                                           <li>构建名称:${JOB_NAME}</li>
                                           <li>构建结果: <span style="color:red"> ${BUILD_STATUS}</span></li> 
                                           <li>构建编号:${BUILD_NUMBER}</li>
                                           <li>构建地址:<a href="${BUILD_URL}">${BUILD_URL}</a></li>                   
                                           <li>GIT 分支:${BRANCH_NAME}</li>
                                           <li>变更记录: ${CHANGES,showPaths=true,showDependencies=true,format="<pre><ul><li>提交ID: %r</li><li>提交人:%a</li><li>提交时间:%d</li><li>提交信息:%m</li><li>提交文件:<br />%p</li></ul></pre>",pathFormat="         %p <br />"}
                                       </ul>
                                   </td>
                               </tr>
                           </table>
                       </body>
                       </html>
                       ''',
           to: "XXX802003@qq.com",
           from: "XXX34093915@163.com",
           attachLog: true,
           compressLog: true
       )
    }
    success {
        emailext (
        subject: "SUCCESSFUL: Job '${env.JOB_NAME} [${env.BUILD_NUMBER}]' 自动化测试结果",
        body: '''<body leftmargin="8" marginwidth="0" topmargin="8" marginheight="4" offset="0">
                    <table width="95%" cellpadding="0" cellspacing="0"
                    style="font-size: 11pt; font-family: Tahoma, Arial, Helvetica, sans-serif">
                        <tr>
                                <td><br />
                                <b><font color="#0B610B">构建信息</font></b>
                                <hr size="2" width="100%" align="center" /></td>
                            </tr>
                            <tr>
                                <td>
                                    <ul> 
                                        <li>构建名称:${JOB_NAME}</li>
                                        <li>构建结果: <span style="color:green"> ${BUILD_STATUS}</span></li> 
                                        <li>构建编号:${BUILD_NUMBER}</li>
                                        <li>构建地址:<a href="${BUILD_URL}">${BUILD_URL}</a></li>                   
                                        <li>GIT 分支:${BRANCH_NAME}</li>
                                        <li>变更记录: ${CHANGES,showPaths=true,showDependencies=true,format="<pre><ul><li>提交ID: %r</li><li>提交人:%a</li><li>提交时间:%d</li><li>提交信息:%m</li><li>提交文件:<br />%p</li></ul></pre>",pathFormat="         %p <br />"}
                                    </ul>
                                </td>
                            </tr>
                        </table>
                    </body>
                    </html>
                    ''',
        to: "XXX802003@qq.com",
        from: "xxx34093915@163.com",
        attachLog: true,
        compressLog: true
        )
    }
    

    5.3.10 配置

    options {
        timestamps()    //设置在项目打印日志时带上对应时间
        disableConcurrentBuilds()   //不允许同时执行流水线,被用来防止同时访问共享资源等
        timeout(time: 5, unit: 'MINUTES')   // 设置流水线运行超过n分钟,Jenkins将中止流水线
        buildDiscarder(logRotator(numToKeepStr: '20'))   // 表示保留n次构建历史
        disableConcurrentBuilds()      //表示多分支不允许同时构建
    }
    

    webhook触发器

    //gitlab  webhook触发器
    //聚合项目,代码发生以下动作后,所有子项目将被触发构建,可选择使用(前提需要gitlab配置 webhook)
    triggers {
        pollSCM('H/15 * * * *') //表示每15分钟 轮询扫描源代码,如果有修改则构建,无修改则不构建。
    }
    
    triggers{     //方法一,为All时
        gitlab( triggerOnPush: true,       //代码有push动作就会触发job
        triggerOnMergeRequest: true,       //代码有merge动作就会触发job
        branchFilterType: "All")           //为All时(只有符合条件的分支才会触发构建 “All/NameBasedFilter/RegexBasedFilter”)
    }
    
    triggers{    //方法二,为branchFilterType时
        gitlab( triggerOnPush: true,                       
            triggerOnMergeRequest: true,                  
            branchFilterType: "branchFilterType",          //为branchFilterType时
            includeBranchesSpec: "dev")                  //基于branchFilterType值,输入期望包括的分支的规则
    }
    

    六、完整的Jenkinsfile

    pipeline {
      agent any
      stages {
        stage('Git Pull') {
          steps {
            git(url: 'https://guojx@git.citycloud.com.cn:3000/shenzq/data-show-mobile', branch: 'feature/ding-11-28-test',credentialsId: 'guojx')
            echo 'pull seccess'
          }
        }
      
        stage('NPM Build') {
          steps {
            sh '''mkdir ../data-show-mobile
            cp -r * ../data-show-mobile
            mv ../data-show-mobile ./
            cat>${WORKSPACE}/Dockerfile<<EOF
    FROM node:8.12.0
    WORKDIR /opt/data-show-mobile/
    COPY data-show-mobile /opt/data-show-mobile
    RUN npm install -g nrm && nrm add cci http://10.12.102.194:4873/ && nrm use cci && npm install && npm run build:dingtest
    EOF
            docker build -t ${IMAGE_NAME} .
            docker run --name ${CONTAINER_NAME} -itd ${IMAGE_NAME}
            docker cp ${CONTAINER_NAME}:/opt/data-show-mobile/dist ${WORKSPACE}/
            mv dist/ h5/'''
          }
          post {
            always {
              sh 'rm -rf data-show-mobile'
            }
          }
        }
       
        stage('SSH') {
          steps {
            script {                 
                def remote = [:]
                remote.name = '241'
                remote.host = '10.12.102.241'
                remote.allowAnyHosts = true
                withCredentials([usernamePassword(credentialsId: '243IP', passwordVariable: 'password', usernameVariable: 'username')]) {
                    remote.user = "${username}"
                    remote.password = "${password}"
                }
                sshPut remote: remote, from: 'h5', into: '/usr/local/nginx/html'
    
            }
          }
        }
      }
      environment {
        IMAGE_NAME = 'dingding:hztc'
        CONTAINER_NAME = 'hztc_h5'
        PROJECT_NAME = 'data-show-mobile'
      }
      post {
        always {
              sh '''set +e
                    environmental_clean(){
                    docker_ps=`docker ps | grep ${CONTAINER_NAME}`
                    docker_psa=`docker ps -a | grep ${CONTAINER_NAME}`
                    
                    if [[ 0 -eq $docker_ps ]];
                    then
                    #容器未启动
                    echo "容器${CONTAINER_NAME}未启动"
                    else
                    echo "停止容器"
                    docker stop ${CONTAINER_NAME}
                    fi
                    
                    if [[ 0 -eq $docker_psa ]];
                    then
                    echo "容器${CONTAINER_NAME}不存在"
                    else
                    echo "删除容器"
                    docker rm ${CONTAINER_NAME}
                    fi
                    }
                    #docker 环境清理
                    environmental_clean
                    docker rmi ${IMAGE_NAME}'''
        }
      }
      options {
        disableConcurrentBuilds()
        timeout(time: 1, unit: 'HOURS')
      }
    }
    
  • 相关阅读:
    强行删除带点的文件夹
    如何设置让iis服务器支持.apk文件的下载
    纯CSS下拉导航菜单
    <UL>中<li>标签前编号图片的简单调用
    滑动门效果【鼠标滑过鼠标单击两种】
    SQL Server中,NumricDecimalMoney三种字段类型的区别
    SQL Server 20个最常用的时间格式
    Gridview------Set BackgroundColor
    c# 中is 和 as 运算符
    SQL LEFT JOIN 关键字 SQL RIGHT JOIN 关键字 fulljoin
  • 原文地址:https://www.cnblogs.com/dongye95/p/14759618.html
Copyright © 2011-2022 走看看