精华内容
下载资源
问答
  • 该插件添加了Jenkins管道步骤以与AWS API进行交互。 主要/代理设置 此插件未针对具有主代理和多个代理的设置进行优化。 仅涉及工作空间的步骤在代理上执行,其余步骤在主服务器上执行。 为了获得最佳体验,请确保主...
  • 主要介绍了Jenkins Pipeline 部署 SpringBoot 应用的详细教程,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
  • 主要介绍了使用Jenkins Pipeline自动化构建发布Java项目的方法,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
  • Jenkins Runner可以为给定的Jenkins作业/项目启动任何打开的文件作为Jenkins Pipeline脚本(声明式或脚本式)。 :warning: :warning: :warning: 用于运行脚本的Jenkins作业的配置将被此扩展覆盖。 建议使用暂存/...
  • pipeline-examples-用于常规管道示例。 global-library-examples-有关如何在Jenkins主数据库上编写和使用全局库的示例。 jenkinsfile-examples-有关使用检入存储库的Jenkinsfile的示例。 docs-用于文档,指南和...
  • jenkins pipeline总结-企业实战 jenkins pipeline总结-企业实战
  • Jenkins Pipeline

    2019-01-18 09:37:04
    Jenkins自动化编译 Pipeline流水线设置,语法,提升效率
  • jenkins-devops-libs:通用DevOps软件的Jenkins Pipeline共享库的集合
  • 自从Jenkins2.0版本升级之后,支持了通过代码(Groovy DSL)来描述一个构建流水线,灵活方便地实现持续交付,大大提升JenkinsJob维护的效率,实现从 CI到CD到转变。而在2016JenkinsWorld大会上,Jenkins发布了1.0...
  • jenkinspipeline实战

    2019-02-22 17:14:04
    jenkins pipeline实战代码,入门代码,一看就会代码,喜欢的点个赞
  • 1、传统我们的项目开发模式是产品调研提出需求,开发团队研究决定开发方案选型。然后开始一个周期的开发,模块开发完成之后开始模块间的联调。联调结束之后打包交付给测试团队。测试团队,系统测试或自动化测试,...
  • 前言 根据网上的说法,以及暂时使用过程中的感受,使用自由风格或者maven风格来创建...因此,我目前所知道的很多正式项目在使用jenkins时可能都会使用pipeline流水线,如果要使用pipeline,需要先安装pipeline插件。 p

    前言

    根据网上的说法,以及暂时使用过程中的感受,使用自由风格或者maven风格来创建jenkins item,虽然也能实现自动化部署,但是面对相对复杂的构建需求时可能就不太好实现。
    一般正式的项目,除了基本的拉取代码、编译代码、运行junit、打包、启动或者重启外,可能还会涉及到sonar代码检查、集成测试、关联例如jira或者conflunce等系统。
    因此,我目前所知道的很多正式项目在使用jenkins时可能都会使用pipeline流水线,如果要使用pipeline,需要先安装pipeline插件。
    pipeline看起来好像也不是太难,但是真正自己操作的时候可能会发现很多地方会有小问题。例如可能涉及到ssh问题,可能涉及到容器操作问题,也可能涉及到shell脚本问题。
    以下是我实际操作过程中的一些记录,主要分为两个部分:一部分是我只使用了一台linux虚拟机,jenkins、git、maven、springboot服务都在上边跑;另一部分是我把spirngboot服务单独放到了另一个虚拟机上。
    同一台机的时候,不涉及ssh,但是却会涉及到jenkins杀死java进程的问题,不同机器就涉及到ssh远程调用shell脚本的问题。

    构建步骤

    jenkins pipeline进行构建的时候,根据需求,可以有各种不同的步骤,我这里模拟的只有这样几个基础的:

    拉取git代码;
    maven执行junit并打包;
    推送jar包到服务目录;
    启动或者重启springboot服务。

    那么这里,前两步其实是一样的,后两步略有区别。推送jar包,在jenkins本机实际就是用的cp操作,而其他机器则是使用的scp操作。
    启动和重启spingboot服务,本机直接启动脚本,远程就需要额外的配置。

    部署到jenkins本机

    jenkins的pipeline配置,分为脚本式和声明式两种,语法上不同,但是主要内容是差不多的。
    这里需要注意的是部署到jenkins本机,最后启动服务的操作。
    我一开始写的是sh "/opt/sh/test.sh restart base-springboot.jar",然后如果是把这些内容直接贴到jenkins 的管理界面配置pipeline那里,build的时候都是成功的,服务也都是正常启动。
    但是当我把这些内容写到jenkinsfile文件中,然后和springboot项目代码放在一起,上传到github上,然后jenkins build的时候也都是成功的,可是却发现每次构建结束后springboot服务都没有启动起来,也查不到相关的java进程
    这个地方其实花了好长时间,后来查了各种资料才大概知道了jenkins会杀掉这里启动的java进程,至于为什么,到现在都还没能弄清楚。
    所以需要把上边的内容改成sh "JENKINS_NODE_COOKIE=dontKillMe /opt/sh/test.sh restart base-springboot.jar"
    当然了,在使用其他远程机器部署的时候,就不会有这个问题。

    jenkins本机部署服务-脚本式

    node {
       stage('Print Message') {
          echo "【start build】 workspace: ${WORKSPACE}"
       }
    
       stage('git pull code') {
          echo "【git pull】"
          git branch: 'jenkin-test', credentialsId: '3bdb20f7-1c4f-4a34-98c0-ef1b9202cbe2', url: 'git@github.com:tuzongxun/base-springboot.git'
       }
    
       //mvn打包
       stage('mvn build project') {
          echo "【mvn build】"
          sh 'mvn clean package'
       }
    
       //上传jar
       stage('Push jar') {
          echo "【push jar】"
          sh 'cp /root/.jenkins/workspace/pip-test/target/base-springboot-0.0.1-SNAPSHOT.jar /opt/code/base-springboot.jar'
          sh '''rm -rf  `ls | egrep -v '(Jenkinsfile|start.sh)'` '''
       }
    
       stage('start/restart service') {
            echo "【start/restart service】"
            sh "JENKINS_NODE_COOKIE=dontKillMe /opt/sh/test.sh restart base-springboot.jar"
        }
    
    }
    

    jenkins本机部署服务-声明式

    pipeline {
        agent any
    
        stages {
            //打印信息
           stage('Print Message') {
              steps {
                 echo "【start build】 workspace: ${WORKSPACE}"
              }
           }
    
           stage('git pull code') {
              steps {
                 echo "【git pull】"
                 git branch: 'jenkin-test', credentialsId: '3bdb20f7-1c4f-4a34-98c0-ef1b9202cbe2', url: 'git@github.com:tuzongxun/base-springboot.git'
              }
           }
    
           //mvn打包
           stage('mvn build project') {
              steps {
                 echo "【mvn build】"
                 script {
                    try {
                    //刚开始使用mvn clean package 提示找不到mvn,所以就这样指定地址,指定配置文件
                        sh 'mvn clean package'
                    } catch (err) {
                       echo 'mvn打包失败'
                    }
                 }
              }
           }
    
           //上传jar
           stage('Push jar') {
              steps {
                 echo "【push jar】"
                 dir('/root/.jenkins/workspace/pip-test') { //指定工作目录
                    script {
                       try {
                          sh 'cp ./target/base-springboot-0.0.1-SNAPSHOT.jar /opt/code/base-springboot.jar'
                       } catch (err) {
                          echo "上传jar构建失败"
                       }
                    }
                 }
                 //推送镜像后,删除工作空叫初Jenkinsfile & start.sh 以外所有文件
                 sh '''rm -rf  `ls | egrep -v '(Jenkinsfile|start.sh)'` '''
              }
           }
    
           stage('Deploy to the Target server') {
              steps {
                    sh "JENKINS_NODE_COOKIE=dontKillMe /opt/sh/test.sh restart base-springboot.jar"
              }
           }
    
        }
    }
    

    shell脚本

    在上边的pipeline中调用了shell脚本来重启springboot服务,或者说java进程,对应的shell脚本如下:

    #!/bin/bash
    APP_NAME=$2
    source /etc/profile
    BUILD_ID=dontKillMe
    usage() {
        echo "Usage: sh test.sh [start|stop|restart|status]"
        exit 1
    }
    
    is_exist(){
        pid=0
        javaps=`jps -l |grep base-springboot.jar`
        if [ -n "$javaps" ]; then
          echo ${javaps}
          pid=`echo ${javaps} | awk '{print $1}'`
          echo "bb":${pid}
          return 0
        else
          echo "cc":${pid}
          return 1
        fi
    }
    
    start(){
        is_exist
        if [ $? -eq "0" ]; then
            echo "${APP_NAME} is already running. pid=${pid} ."
        else
            nohup java -jar /opt/code/${APP_NAME} >> /opt/code/test.log 2>&1 &
            echo "${APP_NAME} start success"
        fi
    }
    
    stop(){
        is_exist
        if [ $? -eq "0" ]; then
            echo "aa":${pid}
            kill -9 ${pid}
        else
            echo "${APP_NAME} is not running"
        fi
    }
    
    status(){
        is_exist
        if [ $? -eq "0" ]; then
            echo "${APP_NAME} is running. Pid is ${pid}"
        else
            echo "${APP_NAME} is NOT running."
        fi
    }
    
    restart(){
        stop
        sleep 5
        start
    }
    
    case "$1" in
        "start")
            start
            ;;
        "stop")
            stop
            ;;
        "status")
            status
            ;;
        "restart")
            restart
            ;;
        *)
            usage
            ;;
    esac
    
    exit 0
    

    这里其实也有一个问题,由于对linux和shell脚本不太熟,所以很多东西都是网上找的,一开始根据网上找到的资料,查看相关java进程,使用的是这段代码:

    is_exist(){
        pid=`ps -ef|grep $APP_NAME|grep -v grep|grep -v $SCRIPT|awk '{print $2}'`
        echo $pid
        if [ -z "${pid}" ]; then
            return 1
        else
            return 0
        fi
    }
    

    但是后来发现总在报错,于是又改成了这样:

    is_exist(){
        pid=`ps -ef|grep $APP_NAME|grep -v grep|awk '{print $2}'`
        echo $pid
        if [ -z "${pid}" ]; then
            return 1
        else
            return 0
        fi
    }
    

    但是这样之后又发现每次拿到的pid都不止1个,于是在后边stop的时候一样有问题。所以最终改成了上边脚本示例的这样:

    is_exist(){
        pid=0
        javaps=`jps -l |grep base-springboot.jar`
        if [ -n "$javaps" ]; then
          echo ${javaps}
          pid=`echo ${javaps} | awk '{print $1}'`
          echo "bb":${pid}
          return 0
        else
          echo "cc":${pid}
          return 1
        fi
    }
    

    部署到非jenkins所在机器的pipeline配置

    虽然jenkins本机部署可用了,但是一般真实项目,基本都不会是业务服务和jenkins在同一台机上,所以我又克隆了一台虚拟机作为业务服务器。
    不过,这里暂时只跑通了脚本式的pipeline配置,声明式的没有成功。以下是脚本式配置的代码:

    node {
        def remote = [:]
        remote.name = 'test'
        remote.host = '192.168.19.200'
        remote.user = 'root'
        remote.allowAnyHosts = true
    
       stage('Print Message') {
          echo "【start build】 workspace: ${WORKSPACE}"
       }
    
       stage('git pull code') {
          echo "【git pull】"
          git branch: 'jenkin-test', credentialsId: '3bdb20f7-1c4f-4a34-98c0-ef1b9202cbe2', url: 'git@github.com:tuzongxun/base-springboot.git'
       }
    
       //mvn打包
       stage('mvn build project') {
          echo "【mvn build】"
          sh 'mvn clean package'
       }
    
       //上传jar
       stage('Push jar') {
          echo "【push jar】"
          sh 'scp /root/.jenkins/workspace/pip-test/target/base-springboot-0.0.1-SNAPSHOT.jar root@192.168.19.200:/opt/code/base-springboot.jar'
          sh '''rm -rf  `ls | egrep -v '(Jenkinsfile|start.sh)'` '''
       }
    
       stage('start/restart service') {
            withCredentials([sshUserPrivateKey(credentialsId: '3bdb20f7-1c4f-4a34-98c0-ef1b9202cbe2', keyFileVariable: 'identity', passphraseVariable: '', usernameVariable: 'root')]) {
                echo "【start/restart service】"
                remote.user = 'root'
                remote.identityFile = identity
                sshCommand remote: remote, command: "/opt/sh/test.sh restart base-springboot.jar"
            }
        }
    
    }
    

    这里主要就是上传jar时使用了scp,这里没有出现密码,是因为在另一台机上配置了jenkins所在机的sshkey的公钥。
    然后就是远程调用时配置的credentialsId,我两台机192.168.19.199192.168.19.200,我是需要用jenkins所在的199去调用200机器上的shell脚本。
    一开始以为和scp一样,已经在200配置了199的公钥,那么应该可以直接调用了。但是结果发现并不是想的那样,还需要配置jenkins中配置的credentials的Id。

    总结

    pipeline本身或许不难,但是每一步涉及到的可能都是一个面的知识,例如shell、ssh、jenkins作用域或者工作空间之类的,需要有比较好的综合知识来支持。
    pipeline可以支持的需求和功能很多,基于它相关的插件也有很多,待后续再逐步了解。

    展开全文
  • pipeline { // agent定义了job在哪里执行。此处可以配为any, label, docker, kubernetes等 agent { label "SEQ-AUTOMATION" } /* 变量可以有三种设置方法,parameters,environment, groovy def。 - 其中...

    声明式与脚本式

    jenkins的pipeline主要分声明式和脚本式两种写法。脚本式用groovy语法,一般会包含在script{}里。大部分时候,我们可能会把声明式和脚本式混着用。

    声明式

    pipeline {
        agent {
            label "some_label"
        } 
        stages {
            stage('Build') { 
                steps {
                    echo "Build"
                }
            }
        }
    }
    

    脚本式

    node("some_lable") {  
        stage('Build') { 
            script {
                echo "Build"
            }
            
        }
    }
    

    示例

    下文列出了如下示例,并在jenkins2.2版本执行验证过。

    • agent定义运行job机器。用法
    • 变量定义与使用 parameters, environment, def(groovy)
    • options用于配置一些特定选项
    • triggers 定义了自动触发方式
    • stages,stage, steps主要放置工作流
    • input,用于job运行中进行交互
    • try catch,用于捕获异常
    • when,声明式条件语句
    • if else,脚本式条件语句
    • 常见的jenkins 工具
    • 子目录
    • post用法
    
    pipeline {
        // agent定义了job在哪里执行。此处可以配为any, label, docker, kubernetes等
        agent {
            label "SEQ-AUTOMATION"
        }
    
        /*
        变量可以有三种设置方法,parameters,environment, groovy def。
    
        - 其中parameters,environment设置的都是环境变量,会在Jenkins job机器存活期间放入机器的环境变量中。如果它两设置的某变量值为空,则不存入机器环境变量中。命令printenv可以看到机器上所有变量。
          parameters相对environment的主要区别:parameters设置的变量可在build前动态配置。environment可以放到stage里
        - jenkins的预设全部环境变量可通过如右查看 {jienkins_hostname}/env-vars.html
        - def定义的变量是groovy语法,可以在pipeline{}之外定义全局的,也可以放入script{}中作为局部变量。
        - 这三种变量都需要用【双】引号才可以正确引用.
        - 所有示例见stage('打印变量')
    
        */
    
        // 参数类环境变量,可以在job build时进行配置。可以为string,text,booleanParam,choice,password这几种类型引用如右 "${params.PERSON}"
        parameters {
            string(name: 'PERSON', defaultValue: 'Mr Jenkins', description: 'Who should I say hello to?')
            text(name: 'TEXT', defaultValue: '', description: 'Enter some information about the person')
            booleanParam(name: 'TOGGLE', defaultValue: true, description: 'Toggle this value')
            choice(name: 'CHOICE', choices: ['One', 'Two', 'Three'], description: 'Pick something')
            password(name: 'PWD', defaultValue: 'secret', description: 'Enter a password')
        }
        // 固定类环境变量,可定义为所有步骤的环境变量或阶段特定步骤局部环境变量。引用如右 "${env.CC}" 或者 "${CC}"
        environment {
            SOME_ENV = 'some_env'
        }
    
        /*
        options用于配置一些特定选项。所有选项可参阅https://www.jenkins.io/zh/doc/book/pipeline/syntax/#options
        - 注意,stage上也可以配置部分options如右:timeout,retry,timestaps,skipDefaultCheckout
        */
        options {
            buildDiscarder(logRotator(numToKeepStr: '30')) //保存的job构建记录总数
            disableConcurrentBuilds() //不允许同时执行流水线
            skipStagesAfterUnstable() // 一旦构建状态进入了“不稳定”状态,就跳过阶段
            timeout(time: 30, unit: 'MINUTES') //job超时时间
            //retry(3) //失败后,重试整个Pipeline指定的次数。放在stage里的retry说是会重复指定次数,但没有试验成功
            // skipDefaultCheckout() 跳过默认设置的代码check out
            // checkoutToSubdirectory('children_path') //在工作空间的子目录进行check out
            // skipStagesAfterUnstable() //一旦构建状态变得UNSTABLE,跳过该阶段
    
        }
    
        /*
        triggers 定义了自动触发方式
        */
        triggers {
            pollSCM('H * * * 1-5') // 轮询检查代码库或当代码仓库有更新时触发,如pollSCM('H * * * 1-5')或 pollSCM(),后者需要配置post-commit/post-receive钩子
            cron('H(0-30) H(7-8) * * *') //以指定的时间来运行pipeline
            //upstream(upstreamProjects: "${upstream_list}", threshold: hudson.model.Result.SUCCESS) //利用上游Job的运行状态来进行触发
            //gitlab(triggerOnPush: false, triggerOnMergeRequest: false, branchFilterType: 'All') //gitlab触发
    
        }
        /*
        stages主要放置工作流
        */
        stages {
            stage('例子:打印变量') {
                steps {
                    sh "printenv" // 打印所有环境变量
                    echo "params var: ${params.PERSON}" // 参数类环境变量引用
                    echo "env var: ${env.SOME_ENV}" //固定类环境变量引用
                    echo "defualt env: {env.BUILD_NUM}" //jenkins预置环境变量
                    script {
                        def some_var = "var" // grooy def 定义的在script里的环境变量,作用域只在scripts里
                        echo "def var: ${some_var}"
    
                    }
                }
            }
    
            stage('例子:input') {
               //  input支持在job执行过程中和用户交互。可选继续或者中止。
                input { //input主要参数如下
                    message "Should we continue?" //必须选项
                    ok "Yes, we should." //可选,主要在ok按钮显示文本
                    //submitter "admin,li.liu2" //可选,设置了的用户才能做input操作。不写默认是所有人
                    parameters { //可选,定义全局环境变量
                        string(name: 'myname', defaultValue: 'Li', description: 'who are you?')
                    }
                }
                steps {
                    echo "Hello, ${myname}, nice to meet you." // 注意!此处不能写成${params.myname},并且作用域只在该stage
                }
            }
    
    /*
                     stage("超时例子") {
                       // stage里的超时。超时时会置为abort。如果异常不处理,则会终止整个流水线
                        options {
                            timeout(time: 3, unit: "SECONDS")
                        }
    
                        steps {
                            echo "timeout set 3s and sleep 5s"
                            sleep(time: 5, unit: "SECONDS")
                        }
    
                   }
    
    */
            stage("例:try catch") {
               //  可try catch用来处理异常,使得不中断流水线
                steps {
                    script {
                        try {
                            // timeout触发中断
                            timeout(time: 3, unit: "SECONDS") {
                                echo "timeout set 3s and sleep 5s"
                                sleep(time: 5, unit: "SECONDS")
                            }
    
                            // sh 'exit 1' 触发failure
    
                        } catch (err) {
                            echo "err ${err}"
                        }
                    }
                }
            }
    
            stage("例:声明式条件语句 when") {
               // 条件 when语句,用于决定该stage是否执行。是pipline声明式语法
                when {
                    // environment name: 'SOME_ENV', value: 'SOMENAME' //当环境变量的SOME_ENV=SOMENAME时
                    // equals expected: 2, actual: currentBuild.number //当某变量值相等
                    // tag "release-*" //TAG_NAME满足某条件时
                    // branch "master" //当为某branch,仅对多分支pipline有效
                    // triggeredBy 'TimerTrigger' //可以为SCMTrigger,TimerTrigger,UpstreamCause
                    // changelog '.*^\\[DEPENDENCY\\] .+$' //SCM变更日志包含指定内容时,可和正则一起用
                    // changeset "**/*.js" //SCM chagneset包含指定文件时
                    // changeRequest target: 'master' //变更请求发生时
                    // expression { return params.PERSON == 'li'} //注意return时要显式返回boolean或者null, return "0"还是等价true
    
                    //when里还可以包含not,allOf,anyOf,三者可以嵌套使用
                    not {
                        anyOf {
                            expression {
                                params.PERSON == 'li'
                            }
                            tag "release-*"
                        }
                    }
                }
                steps {
                    echo "本stage满足when的条件"
                }
            }
    
            stage("例:脚本式条件语句 if else") {
               // groovy的if/else
                steps {
                    script {
                        def is_true = false
                        if (is_true == true) {
                            echo '本stage满足的if条件 is true'
                        } else {
    
                            echo '本stage不满足if的条件 is not true'
                            echo "${params.myname}"
                        }
                        // 如果if里要引用params或者env变量,则写成如下
                        if (env.SOME_ENV == 'SOME_ENV') {
                            echo "本stage满足if的条件 ${env.SOME_ENV}"
                        }
                    }
                }
            }
    
            stage('例:获取shell返回') {
                steps {
                    script {
                        //获取执行状态 0表示执行成功
                        def resultStatus = sh(script: "ls", returnStatus: true)
                        echo "获取ls的执行状态 ${resultStatus}"
    
                        //获取标准输出
                        def resultStdout = sh(script: "ls", returnStdout: true).trim()
                        echo "获取ls的标准输出 ${resultStdout}"
                    }
                }
            }
    
            stage('例:jenkins 工具/插件') {
               // jenkins 工具需要在Manage Jenkins → Global Tool Configuration.配置
                steps {
                    echo '主要展示常用工具的用法,只部分试验了相关代码'
                    // git工具
                    // git branch: "${git_branch}", credentialsId: "${git_key}", url: "${git_url}"
    
                    // maven工具
                    // sh 'mvn -Dmaven.test.failure.ignore=true install'
    
                    // allure
                    // allure includeProperties: false, jdk: '', report: 'jenkins-allure-report', results: [
                    //    [path: 'allure-results']
                    // ]
    
                    // jacoco
                    //jacoco(execPattern: 'jacoco-integration.exec', classPattern: "${project_name}/target/classes", sourcePattern: "${project_name}/src/main/java")
    
                }
            }
    
    /*
            stage ('例:子目录'){
                steps{
                    dir("sub_dir") {
                        sh "pwd"
                  }
    
                }
            }
    */
        }
    
        /*
        post定义结束时的操作。
        可以包括always,changed,failure(红),success(绿),unstable(黄),和aborted(灰)等
        */
        post {
            always {
                // 例:结束后发送邮件
                emailext(
                    subject: 'Jenkins mail',
                    body: "${env.JOB_NAME}",
                    attachmentsPattern: '**/results/*.png, **/results/*.csv',
                    to: 'li.liu@XXX.com'
                )
            }
        }
    }
    

    参考

    官方文档 https://www.jenkins.io/zh/doc/book/pipeline/syntax/
    jenkins pipeline基础语法与示例 https://www.jianshu.com/p/f1167e8850cd

    展开全文
  • 可以脚本拆成独立的子阶段,借助 JenkinsPipeline 功能,实现并发处理。从而缩短整个编译打包时间 Jenkins Jenkins 是一个开源软件项目,是基于 Java 开发的一种持续集成工具,用于监控持续重复的工作,旨在提供...

    编译打包脚本

    从源代码管理、使用角度,项目下维护一个编译打包脚本是一个不错的方法

    随着项目规模迭代,会出现编译、打包时间长的问题

    可以脚本拆成独立的子阶段,借助 Jenkins 的 Pipeline 功能,实现并发处理。从而缩短整个编译打包时间

    Jenkins

    Jenkins 是一个开源软件项目,是基于 Java 开发的一种持续集成工具,用于监控持续重复的工作,旨在提供一个开放易用的软件平台,使软件项目可以进行持续集成

    官方网站: https://www.jenkins.io/

    在 Jenkins 中,把一个构建任务称之为 Job

    Jenkins 分布式构建

    Jenkins 可以单机器节点构建 Job ,或者利用多台机器节点共同协作完成一个 Job 的构建

    安装 Pipeline 插件后,会使 Jenkins 具备这种特性

    通常,安装 Jenkins 时,默认选择社区推荐检查安装即可

    安装 Jenkins 的那台主机,称之为 master

    可以通过 Dashboard => 节点列表 => 新建节点,添加从机

    master 需要能 ssh 权限,登录从机

    下图,为添加了一个从节点的图示:
    在这里插入图片描述

    Jenkins Pipeline Job

    Jenkins Pipeline Job 是一种构建任务

    它按照 Pipeline 语法,把整个构建任务拆成多个 stage ,并控制这些 stage 按指定的方式去执行

    比如并发执行、跨机器节点执行等等

    Jenkins Pipeline 相关文档资料:

    Jenkins Pipeline Job 最佳实践是通过 Jenkinsfile 文件方式来编排、定义:

    • 可以纳入版本管理。类似按源代码脚本方式维护、调试
    • 可以在定义 Job 时,使用 Jenkins SCM 插件指定加载

    Jenkinsfile

    Jenkinsfile 是使用 groovy 语法的编排脚本

    比如脚本例子:

    pipeline {
        agent any
    
        stages {
            stage('Hello') {
                steps {
                    sh 'echo "Hello World"'
                }
            }
        }
    }
    

    该脚本实际上包含了 3 种语法:

    语法说明
    groovy 语法即整个脚本书写,使用 groovy 语法
    pipeline job 定义语法例子中的 agent 、 stages 、stage 等等组织方式,是需要符合 pipeline job 的规定方式
    shell 语法通常项目会使用 linux 环境下 shell 脚本来做编译、打包、运行等脚本
    在 pipeline 中,每个 stage 都可以执行些 shell 语句

    如果是 windows 用户, Jenkinsfile 会加入 bat 语法,用来执行 windows 批处理脚本

    Jenkinsfile 实际脚本举例

    下面是实作中的 Jenkinsfile 脚本。去除了项目细节,保留整个框架,读者可以学习,如何编写一个 Jenkinsfile 脚本

    def source_version = ''
    def script_version = ''
    def proto_version = ''
    def cserver_cpp_version = ''
    def final_version = ''
    def build_name = ''
    
    def labels = ['login', 'gateway', 'game']
    
    def get_go_service_stage(label, source_version, script_version, proto_version, cserver_cpp_version, final_version, build_name) { return stage(label) { withEnv(["label=${label }", "source_version=${source_version }", "script_version=${script_version }", "proto_version=${proto_version }", "cserver_cpp_version=${cserver_cpp_version }", "final_version=${final_version }", "build_name=${build_name }"]) { sh '''set -ex
        service=$label
        echo ${service}
        # 编译脚本,略
        '''
    }}}
    
    def get_cserver_cpp_stage(label, source_version, script_version, proto_version, cserver_cpp_version, final_version, build_name) { return stage(label) { withEnv(["label=${label }", "source_version=${source_version }", "script_version=${script_version }", "proto_version=${proto_version }", "cserver_cpp_version=${cserver_cpp_version }", "final_version=${final_version }", "build_name=${build_name }"]) { sh '''set -ex
        # 编译脚本,略
        '''
    }}}
    
    def get_client_zip_stage(label, source_version, script_version, proto_version, cserver_cpp_version, final_version, build_name) { return stage(label) { withEnv(["label=${label }", "source_version=${source_version }", "script_version=${script_version }", "proto_version=${proto_version }", "cserver_cpp_version=${cserver_cpp_version }", "final_version=${final_version }", "build_name=${build_name }"]) { sh '''set -ex
        # 资源打包脚本,略
        '''
    }}}
    
    def get_sdata_zip_stage(label, source_version, script_version, proto_version, cserver_cpp_version, final_version, build_name) { return stage(label) { withEnv(["label=${label }", "source_version=${source_version }", "script_version=${script_version }", "proto_version=${proto_version }", "cserver_cpp_version=${cserver_cpp_version }", "final_version=${final_version }", "build_name=${build_name }"]) { sh '''set -ex
        # 资源打包脚本,略
        '''
    }}}
    
    def get_image_stage(label, source_version, script_version, proto_version, cserver_cpp_version, final_version, build_name) { return stage(label) { withEnv(["label=${label }", "source_version=${source_version }", "script_version=${script_version }", "proto_version=${proto_version }", "cserver_cpp_version=${cserver_cpp_version }", "final_version=${final_version }", "build_name=${build_name }"]) { sh '''set -ex
        service=$label
        echo ${service}
        # docker 镜像制作脚本,略
        '''
    }}}
    
    def get_source_version() {
        return sh (
            script: '''echo "$(# 获取代码版本脚本,略)''',
            returnStdout: true
        ).trim()
    }
    
    def get_script_version() {
        return sh (
            script: '''echo "$(# 获取资源版本脚本,略)"''',
            returnStdout: true
        ).trim()
    }
    
    def get_proto_version() {
        return sh (
            script: '''echo "$(# 获取协议版本脚本,略)"''',
            returnStdout: true
        ).trim()
    }
    
    def get_cserver_cpp_version() {
        return sh (
            script: '''echo "$(# 获取代码版本脚本,略)"''',
            returnStdout: true
        ).trim()
    }
    
    def get_final_version(source_version, script_version, proto_version) {
        return withEnv(["source_version=${source_version }", "script_version=${script_version }", "proto_version=${proto_version }"]) { sh (script: '''
        # 计算最终版本号,略
        ''', returnStdout: true).trim()}
    }
    
    def get_build_name(final_version) {
        return withEnv(["final_version=${final_version }"]) { sh(
            script: '''echo "${BUILD_NUMBER}_${BUILD_USER}_${p4}_${version}_C_${final_version}_TAG_xxx"''',
            returnStdout: true
        ).trim()}
    }
    
    pipeline {
        agent {
            node {
                label 'backend_compiler'
            }
        }
        environment {
            P4PORT = 'xxxxx'
            P4USER = 'xxxxx'
            P4PASSWD = 'xxxxx'
            registryHost = 'xxxxx:5000/'
            GOPATH = sh( script: '''echo ${WORKSPACE}''', returnStdout: true ).trim()
            BRANCH_NAME = sh( script: '''echo ${branch}''', returnStdout: true ).trim()
        }
        stages {
            stage('set_name1') {
                steps {
                    wrap([$class: 'BuildUser']) {
                            sh '''
                            buildName=${BUILD_NUMBER}_${BUILD_USER}_${p4}_${version}_C_xxx
                            touch ${WORKSPACE}/buildName.txt
                            echo ${buildName} >${WORKSPACE}/buildName.txt
                            '''
                    }
                    script {
                        json_file = "${env.WORKSPACE}/buildName.txt"
                        file_contents = readFile json_file
                        currentBuild.displayName = file_contents
                    }
                }
            }
            stage('checkout') {
                failFast true
                parallel {
                    stage('p4_checkOut') {
                        steps {
                            // 拉 P4 代码,略
                        }
                    }
                    stage('check_out_go_code') {
                        steps {
                            // 拉 git 代码,略
                        }
                    }
                }
            }
            stage('get_version') {
                steps {
                    script {
                        source_version = get_source_version()
                        script_version = get_script_version()
                        proto_version = get_proto_version()
                        cserver_cpp_version = get_cserver_cpp_version()
                        final_version = get_final_version(source_version, script_version, proto_version)
                        build_name = get_build_name(final_version)
                    }
                }
            }
            stage('set_name2') {
                steps {
                    script {
                        withEnv(["build_name=${build_name }"]) { sh '''
                            touch ${WORKSPACE}/buildName.txt
                            echo ${build_name} >${WORKSPACE}/buildName.txt
                            '''
                        }
                        json_file = "${env.WORKSPACE}/buildName.txt"
                        file_contents = readFile json_file
                        currentBuild.displayName = file_contents
                    }
                }
            }
            stage('build') {
                steps {
                    script {
                        def builders = [:]
                        builders['cserver_cpp'] = {
                            get_cserver_cpp_stage('cserver_cpp', source_version, script_version, proto_version, cserver_cpp_version, final_version, build_name)
                        }
                        builders['client.zip'] = {
                            get_client_zip_stage('client.zip', source_version, script_version, proto_version, cserver_cpp_version, final_version, build_name)
                        }
                        builders['sdata.zip'] = {
                            get_sdata_zip_stage('sdata.zip', source_version, script_version, proto_version, cserver_cpp_version, final_version, build_name)
                        }
                        for (x in labels) {
                            def label = x
                            builders[label] = {
                                get_go_service_stage(label, source_version, script_version, proto_version, cserver_cpp_version, final_version, build_name)
                            }
                        }
                        builders.failFast = true
                        parallel builders
                    }
                }
            }
            stage('image') {
                steps {
                    script {
                        def builders = [:]
                        builders['tools'] = {
                            get_image_stage('tools', source_version, script_version, proto_version, cserver_cpp_version, final_version, build_name)
                        }
                        builders['all_in_one_test'] = {
                            get_image_stage('all_in_one_test', source_version, script_version, proto_version, cserver_cpp_version, final_version, build_name)
                        }
                        if ("${env.complete}" == 'true') {
                            for (x in labels) {
                                def label = x
                                builders[label] = {
                                    get_image_stage(label, source_version, script_version, proto_version, cserver_cpp_version, final_version, build_name)
                                }
                            }
                            builders['cserver_cpp'] = {
                                get_image_stage('cserver_cpp', source_version, script_version, proto_version, cserver_cpp_version, final_version, build_name)
                            }
                        }
                        builders.failFast = true
                        parallel builders
                    }
                }
            }
            stage('end') {
                steps {
                    script {
                        withEnv(["build_name=${build_name }", "final_version=${final_version }"]) {
                            sh '''
                            # 结束处理
                            '''
                        }
                    }
                }
            }
        post {
            changed {
                echo 'pipeline post changed'
            }
            always {
                echo 'pipeline post always'
            }
            success {
                echo 'pipeline post success'
            }
            unsuccessful {
                script {
                    sh '''
                            notifyUrl=https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=xxxxxx
                            newNotifyUrl=https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=xxxxxx
                            msg="[UGS] dev 编译 【失败】 ${p4}_${version},time=$(date "+%Y-%m-%d %H:%M:%S")"
                            curl $notifyUrl -H \'Content-Type: application/json\' -d "{\\"msgtype\\": \\"text\\",\\"text\\": {\\"content\\": \\"${msg}\\", \\"mentioned_list\\":[\\"xxxxxx\\"]}}"
                            curl $newNotifyUrl -H \'Content-Type: application/json\' -d "{\\"msgtype\\": \\"text\\",\\"text\\": {\\"content\\": \\"${msg}\\"}}"
                        '''
                }
                echo 'pipeline post unsuccess'
            }
        }
    }
    

    脚本说明,可以学习到以下知识点:

    • 公共信息在 stage 间,可以通过环境变量的方式传递
    • 如何动态设置环境变量
    • groovy 中的变量如何传递给 shell
    • 如何并发执行 stage
    • 如何动态生成 stage

    Jenkins Pipeline Job 多节点并发

    上面举的例子,还局限于 Jenkinsfile 在某台从节点上执行

    如果读者需要把多个 stage 编排到不同从节点,还需要考虑:

    • 动态公共信息,如何在多个 stage 中传递
    • 多个 stage 结果如何汇总
    • 拉取的代码源是否多节点共享问题

    因为项目复杂度尚未到单个从节点无法应对的情况(目前以上 Jenkinsfile ,使原执行脚本 30 分钟,缩短至 3 分钟完成

    因此,这里仅提供以下思路:

    • 使用 jenkins pipeline 的 stash 命令,汇总 stage 结果
    • 预处理公共信息,同理可以通过 stash 命令,汇总于一些文件内。其他 stage ,可先 unstash 某文件获得需要的信息
    • git p4 等源代码库拉取操作是否只要公共的定义到 1 个顶级 stage 。其他多节点并发 stage 是否可见?
      • 未实践过,暂无结论。最差的情况,多节点并发 stage 内拉取对应仓库内容

    另外需要注意:并非多节点并发,一定由于单节点并发。。多节点间 stage 交互需要消耗一定资源,这里有个阈值

    一般的,以下情况,可以考虑:

    • 编译打包过程本身跨平台,如需要 windows 、 linux 同时参与
    • 单节点处理能力无法达到预期(这种情况一般不多见)

    以上

    展开全文
  • jenkins pipeline关系

    2018-11-22 00:29:21
    Read more about how to integrate steps into your Pipeline in the Steps section of the Pipeline Syntax page
  • Jenkins pipeline 停止

    2021-06-23 13:45:32
    在执行 Jenkins pipeline时,会执行某一个shell 脚本。 如果shell脚本报错。停止整条pipeline 。 如果shell 脚本正常执行,pipeline不受影响 Solution 在想停止的位置加exit 1 例如: 按照 touchlist.txt的...

    背景

    在执行 Jenkins pipeline时,会执行某一个shell 脚本。

    如果shell脚本报错。停止整条pipeline 。

    如果shell 脚本正常执行,pipeline不受影响

    Solution 

    在想停止的位置加  exit 1

    例如:

    按照 touchlist.txt的内容识别文件是否存在。如果不存在,返回 exit code 1 。使得Pipeline Stage  Finished: FAILURE 

    #!/bin/bash
    for line in `cat /usr/local/software/jason/touchlist.txt`
    do
    if [[ ! -f "$line" ]]; then
     echo "ERROR $line 文件不存在,修改时间戳失败"
     exit 1
     break
    else
     touch $line
     echo "$line 修改时间戳成功"
    fi
    done
    

    一旦识别到文件不存在,pipeline 就会停止。报错Finished: FAILURE   exit code 1

    展开全文
  • jenkins-pipeline-shared-libraries-gradle-plugin:Gradle插件,可帮助构建和测试Jenkins Pipeline共享库(请参阅https:jenkins.iodocbookpipelinelined-libraries)
  • Jenkins pipeline 小技巧

    2021-06-11 17:59:38
    + "_${env.BUILD_ID}" } pipeline { agent any environment { _version = createVersion() } stages { stage ("test") { steps { echo "${_version}" } } } } 简单技巧 3 stage('编译镜像') { // 只要注意包含关系 ...
  • Jenkins pipeline基本用法

    千次阅读 2021-02-05 15:56:39
    文章目录前言一、一个简单的pipeline二、when关键字三、currentBuild.result四、...先说一下自己的感触,之前用jenkins的时候,一直使用的是普通自由风格的project,这种用法简单方便,并且相关的资料也更多,更成
  • Jenkins Pipeline 语法

    2020-06-03 08:29:00
    声明性pipeline Sections agent pipeline与stage中的不同 参数 常用选项 发布 post stages steps Directives environment options 可用选项 stage options parameters 可用参数 triggers stage ...
  • Jenkins Pipeline 概述

    2019-11-23 11:02:24
    概述 这篇概述是...Jenkins Pipeline("Pipeline")是Jenkins的插件,支持运行和集成continuous delivery pipelines. 持续delivery的pipeline实际是进程的一种自动化表达,例如从gith...
  • Jenkins Pipeline的用法

    2020-12-16 22:51:34
    Jenkins Pipeline的简单用法
  • Jenkins pipeline 调用mvn test ,项目中文乱码 安装环境: centos7 、JDK 1.8、tomcat 9、jenkins部署在 Tomcat 中 问题: sh """ mvn clean test -Dtype=1 -DinitDataIP=$IP -DfilePath=${workSvnPath} ...
  • 在运行时,已定义的Yaml格式将转换为Jenkins Pipeline声明式语法。 或任何现有步骤都可以在step或script块中使用。 必须遵循规则。 请参阅下面的用法示例。 用法 管道 要在管道作业中使用Yaml管道,请选择一种可能...
  • Jenkins pipeline 插件

    千次阅读 2019-01-17 15:26:46
    jenkins作为图形化工具操作简单,但是当有较复杂逻辑的时候界面变得异常混乱不方便阅读,再加上一堆插件自己的界面,以及有些插件做不了,写的脚本在里面,总之界面很乱就对了 pipeline相比就是一堆代码一眼便熟悉...
  • jenkins pipeline

    2019-04-16 13:57:00
    https://jenkins.io/zh/doc/book/pipeline/syntax/ https://blog.csdn.net/taishanduba/article/details/61423121 https://www.cnblogs.com/kevingrace/p/6022447.html 通用规则 AgentAgent通常是一个机器或容器...
  • 新建Pipeline 项目 配置Git仓库: 脚本路径是指代码拉下的jenkins_files目录里面的01_eureka文件。· node { def mvnHome def workspace = pwd() def project_name = 'eureka-server-1.0.0.jar' def project_log = ...
  • jenkins pipeline关联钉钉发送消息

    千次阅读 2020-09-10 20:34:21
    钉钉目前支持jenkins发送推送消息,这样就能及时收到jenkins的job执行信息。 首先,在钉钉软件中,注册一个机器人。参照钉钉官网帮助,注册机器人: https://www.dingtalk.com/qidian/help-detail-20781541.html ...
  • pipeline{ #根节点,看见pipeline就知道是声明式语法了,如果是node,则是脚本式语法 agent any #指定流水线的执行位置(jenkins agent),流水线中的每个阶段都必须在某个地方(物理机、虚拟机或docker容器)执行 ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 10,131
精华内容 4,052
关键字:

jenkinspipeline