• Jenkins集成必会技能——pipeline入门教程


    作者:慧哥

    一、什么是pipeline

    什么是Pipeline?简单来说,就是一套运行于Jenkins上的工作流框架,将原本独立运行于单个或者多个节点的任务连接起来,实现单个任务难以完成的复杂发布流程(实用场景:将多个Jenkins构建任务轻松集成)

    Pipeline的实现方式是一套Groovy DSL,任何发布流程都可以表述为一段Groovy脚本,并且Jenkins支持从代码库直接读取脚本,从而实现了Pipeline as Code的理念。

    使用条件

    要使用Jenkins Pipeline,需要: Jenkins 2.x或更高版本、Pipeline插件

    使用语言

    Pipeline脚本是用Groovy写的 。

    二、pipeline在哪

    首先确保Jenkins上已经有pipeline相关插件。如果想在Jenkins上新建一个pipeline Job,按照下列步骤操作:

    1、单击Jenkins主页上的New Item。

    2、输入Pipeline的名称,选择Pipeline,然后单击确定。

    3、最后点击完成,一个pipeline项目就生成了

    三、一个简单的pipeline脚本

    pipeline项目中实际起作用的就是pipeline 脚本部分,这里写一个HelloWorld,编辑后点击保存,期望执行打印hello world操作。

    由于这个脚本是无参数的,所以直接点击Build Now就可以了,来查看一下构建结果,

    可以看到最后输出了期望的 Hello world!

    这里对语法进行简单介绍

    Example

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

    agent

    在任何可用的agent 上执行Pipeline或stage。例如:agent any

    还有其他的agent后面可跟的参数,例如:none,label,node,docker

    none

    当在pipeline块的顶层使用none时,将不会为整个Pipeline运行分配全局agent ,每个stage部分将需要包含其自己的agent部分。

    label

    使用提供的label标签,在Jenkins环境中可用的代理上执行Pipeline或stage。例如:agent { label 'my-defined-label' }

    node

    agent { node { label 'labelName' } },等同于 agent { label 'labelName' },但node允许其他选项(如customWorkspace)。

    docker

    定义此参数时,执行Pipeline或stage时会动态供应一个docker节点去接受Docker-based的Pipelines。docker还可以接受一个args,直接传递给docker run调用。例如:agent { docker 'maven:3-alpine' }

    stages

    包含一个或多个stage的序列,Pipeline的大部分工作在此执行。建议stages至少包含至少一个stage指令,用于连接各个交付过程,如构建,测试和部署等。

    steps

    steps包含一个或多个在stage块中执行的step序列。

    总结:

    1、Pipeline最基本的部分是“step”。基本上,step告诉Jenkins 要做什么,并且作为Declarative Pipeline和Scripted Pipeline语法的基本构建块。

    2、Pipeline支持两种语法:Declarative Pipeline(在Pipeline 2.5中引入,结构化方式)和Scripted Pipeline,两者都支持建立连续输送的Pipeline。

    3、所有有效的Declarative Pipeline必须包含在一个pipeline块内,例如:

    pipeline { /* insert Declarative Pipeline here */ }

    4、Declarative Pipeline中的基本语句和表达式遵循与Groovy语法相同的规则 ,但有以下例外:

    a.Pipeline的顶层必须是块,具体来说是:pipeline { }

    b.没有分号作为语句分隔符。每个声明必须在自己的一行

    c.块只能包含Sections, Directives, Steps或赋值语句。

    四、pipeline实际实用意义

    前文说了Pipeline是将原本独立运行于单个或者多个节点的任务连接起来

    我们来举两个例子

    1、Git上拉取代码:

    在pipeline中有一个流水线语法,加入想去git上拉代码,可以这么操作,点击图中的流水线语法,选择git

    填写必要参数后,点击成成流水线语法

    然后将生成的流水线脚本粘贴进入steps里面,就可以完成git代码的拉取了

    jenkins会把代码拉到Workspace+项目名+projdir的目录下,当然也可以指定绝对路径.

    2、利用pipeline去执行自动化脚本

    前置条件:我已经有一个job,用来执行我的回归脚本,同时我的jmeter+ant+jenkins也已经集成好了,在那个job中,脚本的调用执行是通畅的

    pipeline {
        agent any
        stages {
         stage ('Test'){
                steps{
                    build job: 'hhh', 
                    parameters: [[ $class: 'StringParameterValue', name:'ScriptName', value: 'hhh']]
                    }
                }
        }
    }

    steps里面的第一行是调用的Job 第二行是我那个job下传输的参数

    来看下执行结果

    ps:pipeline可以结合实际情况,在pipeline语法中直接写打包,部署,执行脚本完成整个流的工作,也可以通过现有的job,去调用job完成持续继承。使用灵活,按需实操。

    最后我们来看一下,如果结合了打包、部署、回归,它的执行效果,有没有感觉跟我们这篇文章的封面有异曲同工之处

    出处:https://cloud.tencent.com/developer/article/1653828

    =======================================================================================

    pipeline的定义

      简而言之,就是一套工作流框架,将原本独立运行于单个或者多个节点的任务连接起来,实现单个任务难以完成的复杂流程编排与可视化。
      目前比较流行的pipeline实践方式如下。

    • gitlabrunner: 是gitlab内置的一套pipeline框架,脚本是yml语言。
    • jenkins: 通过安装插件的形式实现,脚本语言是jenkinsfile。

    由于团队中的代码仓库没有使用gitlab,因此我这边选择了jenkins来实践pipeline。

    什么是jenkinsfile

      jenkinsfile 就是一个脚本文件,放在项目的根目录下,能够被jenkins识别并自动触发pipeline流程,jenkinsfile的编写可以参考jenkins官网:jenkinsfile语法

    pipeline一期目标

      团队第一期目标是:实现开发pod库时提交代码自动触发单元测试,不同分支能执行不同的策略,执行不同的pipeline任务,能够自动发布pod。pipeline失败时能够发送邮件进行通知,pipeline流成如下:
    在这里插入图片描述
    jenkinsfile 脚本如下:

    pipeline {
      agent any
    
      parameters {
         string(name: 'PROJECT_NAME', defaultValue: 'test_rootlib_ios', description:'')
      }
    
      stages {
        stage('prepare') {
          steps {
              sh './ci_prepare.sh' 
          }
          post {
              failure {
                post_email('prepare','fail')
              }
              aborted {
                post_email('prepare','aborted')
              }
          }
        }
    
        stage('unit_test') {
          steps {
            sh './ci_unit_test.sh'
          }
          post {
              failure {
                post_email('unit_test','fail')
              }
              aborted {
                post_email('unit_test','aborted')
              }
          }
        }
    
        stage('lib_lint') {
           when {
              branch 'dev'
           }
           steps {
              sh './lib_lint.sh'
           }
           post {
              failure {
                post_email('lib_lint','fail')
              }
              aborted {
                post_email('lib_lint','aborted')
              }
           }
        }
    
        stage('publish_pod') {
          when {
              branch 'dev'
           }
           steps {
              sh './repo_tag.sh'
           }
          post {
              failure {
                post_email('publish_pod','fail')
              }
              aborted {
                post_email('publish_pod','aborted')
              }
          }
        }
        stage('pipeline_end') {
          when {
              branch 'dev'
          }
          steps {
              echo 'pipeline_end'
          }
          post {
              success {
                post_email('pipeline_end','success')
              }
              failure {
                post_email('pipeline_end','fail')
              }
              aborted {
                post_email('pipeline_end','aborted')
              }
          }
        }
    
      }
    
    }
    
    def post_email(String stage, String status) {
      mail to: '12345678@qq.com',
      subject: "【${PROJECT_NAME}】${stage} ${status}",
      body: "build_id: ${env.BUILD_NUMBER}\nbranch: ${env.GIT_BRANCH}\nstage: ${stage}\nbuild_url: ${env.BUILD_URL}"
    }

    脚本思路:
    1,每次提交时都会触发pipeline,首先执行准备阶段的任务主要是清理环境,pod install之类的操作。然后触发单元测试。测试成功后没有任何提示,测试失败时会通过邮件进行通知
    2,dev分支是发版分支,当pod准备要发布时,将版本号改好,然后先执行prepare阶段的任务,然后执行单元测试,接着执行pod lint的任务,然后执行发版的操作,发版成功后会发送邮件进行通知。ps:后期会执行项目自动集成相关的工作。

    blueOcean

    blueOcean 是jenkins提供的可视化的形式编辑jenkinsfile的一个插件,大家可以体验下,这里就不多说了,感觉刚开始入门的时候可以试试,可视化没有直接在脚本上编辑流程灵活。
    参考网址:blueOcean

    遇到的坑点

    邮箱

      在最开始的实践是,本来打算用公司的邮箱进行通知,后来发现公司的邮箱不支持类似配置。我这边选择了163邮箱配置在jenkins上进行通知。

    bundle exec命令

    由于团队中对组件化进行预编译,实现了二进制形式的集成,在准备阶段执行如下命令的时候一直报错

    bundle config set deployment 'true'
    bundle install
    bundle exec pod install --repo-update

    后来参考网上,在jenkins进行了全局环境变量配置。
    在这里插入图片描述

    内存不足

      最开始时候设置了pipeline的配置,当分支删除时,对应的pipeline构建会被删除,但是由于电脑配置太差,加上分支较多,出现了内存不足的现象。直接造成jenkins坏掉了,为了解决这个问题,我在jenkinsfile上写了一个脚本定期去删除项目中各个分支中的构建。
    在这里插入图片描述

    脚本具体如下:

    #!/bin/bash
    cd ..
    cd ..
    cd jobs
    projects=("项目名字" "项目名字" "项目名字" "项目名字")
    for project in ${projects[*]}
    do
    #进入对应项目目录
      cd $project
      project_dir=$(pwd)
      echo "project dir is:$project_dir"
      cd branches
      pwd=`pwd`
      filelist=`ls $dir`
      for biranch in $filelist:
      do
      #进入对应项目分支目录
        cd biranch
        rm -rf builds
        mkdir builds
        cd ..
      done
      
      cd ..
    
    done

    更多干货文章,扫描下方二维码关注公众号

    出处:https://blog.csdn.net/hanhailong18/article/details/109861471

    =======================================================================================

    持续集成:Jenkins pipeline全局变量

    在编写Jenkins Pipeline脚本时,需要使用到一些全局变量,比如环境变量jenkins URL、项目地址,保存在env变量中(字符串类型),可以在Jenkins Pipeline或者其它Jenkinsfile中使用这些变量。本文介绍jenkins 中env、params、currentBuild和manager这几种全局变量。

    Jenkins 全局变量

    Jenkins平台支持的全局变量可通过地址${JENKINS_URL}/pipeline-syntax/globals 访问。主要包括以下全局变量:

    • env:在groovy代码和 Jenkins pipeline中以 env.VARNAME 或直接以 VARNAME 的形式访问环境变量。
    • params:将构建中定义的所有参数公开为具有不同类型值的只读映射,通过params来访问。
    • currentBuild:顾名思义,它处理Jenkins管道当前正在运行的构建。
    • managerGroovy Postbuild插件提供的全局变量。
    • docker:这是为了在一个Groovy脚本的Jenkins管道中提供方便的访问docker相关函数。

    下面来举例说明如何使用。

    下面的示例中,groovy脚本在Pipeline 共享库中编写,pipeline脚本直接在pipeline工程的pipeline输入框中编写。pipeline共享库的定义可以参考 持续集成:Jenkins Pipeline共享库定义和使用

    env

    查看环境变量

    可通过多种方式查看jenkins可使用的环境变量:

    1. 访问:${JENKINS_URL}/pipeline-syntax/globals
    2. 访问:${JENKINS_URL}/env-vars.html/
    3. 使用windows bat命令:set
    4. 使用Linux/Unix shell命令:printenv

    bat和shell命令可以在pipeline中编写:

    pipeline{
        agent {
            label "master"
            }
        stages{
    		stage('Parallel Stage') {
    		parallel {
    		stage('windows') {
    			agent {
    				label "win_agent"
    			}
    			steps {
    				bat 'set'  
    			}
    		}
    		stage('linux') {
    			agent {
    				label "linux_agent"
    			}
    			steps {
    				sh 'printenv' 
    			}
    		}
    	}    
       }
       }
    }

    由于打印内容较多,这里就不展示结果了。这两个命令除了返回jenkins平台的环境变量外,还会打印对应代理节点的环境变量。

    使用环境变量

    可以以 env.VARNAME 或直接以 VARNAME 的形式访问环境变量。

    pipeline脚本:

    // @Library('pipelinelibs2@main')   // Github库 
    @Library('pipelinelibs@1.0') _   // SVN库
    
    import com.hiyongz.MyLib
    
    def mylib = new MyLib();
    
    mylib.getJenkinsHome();
    
    println "${JENKINS_HOME}";
    println "${env.JENKINS_HOME}";

    MyLib.groovy:

    def getJenkinsHome(){
    	println "${JENKINS_HOME}";
    	println "${env.JENKINS_HOME}";
    }

    构建结果日志:

    [Pipeline] echo
    /var/jenkins_home
    [Pipeline] echo
    /var/jenkins_home
    [Pipeline] echo
    /var/jenkins_home
    [Pipeline] echo
    /var/jenkins_home
    [Pipeline] End of Pipeline
    Finished: SUCCESS

    创建环境变量

    除了读取环境变量外,也可以对环境变量进行赋值或者创建新的环境变量。声明环境变量可以使用以下3种方式:

    1. withEnv(["VARIABLE_NAME=value"]) {} , 脚本式流水线语法,可以覆盖任何环境变量。
    2. env.VARIABLE_NAME :只能覆盖以env.VARIABLE_NAME的方式创建的环境变量。
    3. environment { } ,声明式流水线语法,不能以env.VARIABLE_NAME的方式覆盖。

    pipeline脚本:

    // @Library('pipelinelibs2@main')   // Github库 
    @Library('pipelinelibs@1.0') _   // SVN库
    
    import com.hiyongz.MyLib
    
    def mylib = new MyLib();
    
    env.MY_VERSION = '1.0'
    mylib.myEnv();
    println "MY_VERSION = ${MY_VERSION}";
    println "MY_VERSION = ${env.MY_VERSION}";
    
    pipeline{
        agent {
            label "master"
        }
    	environment {
            ENV1 = "env1"
        }
        stages{	
    	stage("Env Test") {
    		environment {
    			ENV1 = "env1_1" // 覆盖environment{}块创建的环境变量
    			BUILD_NUMBER = "666" // 可以覆盖以`env.VARIABLE_NAME`方式赋值的环境变量。
    			
    		}
    		steps {
    			println "ENV1 = ${env.ENV1}";
    			println "BUILD_NUMBER = ${env.BUILD_NUMBER}";
    			
    			script {
    				env.MY_VERSION = "2.0" // env.MY_VERSION会被覆盖
    				env.ENV1 = "env1_2"		// env.ENV1不会被覆盖
    			}
    			
    			println "ENV1 = ${env.ENV1}";
    			println "MY_VERSION = ${env.MY_VERSION}";
    
    			withEnv(["ENV1=env1_3"]) { // env.ENV1会被覆盖
    				echo "ENV1 = ${env.ENV1}"
    			}
    		}
    	}
    	}
    }

    MyLib.groovy:

    def myEnv(){
    	println "MY_VERSION = ${env.MY_VERSION}";
    	println "MY_VERSION = ${MY_VERSION}";
    }

    构建结果日志:

    MY_VERSION = 1.0
    MY_VERSION = 1.0
    MY_VERSION = 1.0
    MY_VERSION = 1.0
    ENV1 = env1_1
    BUILD_NUMBER = 666
    ENV1 = env1_1
    MY_VERSION = 2.0
    ENV1 = env1_3

    新创建的环境变量在groovy也可以通过如下方式获取:

    def myEnv(){
    	def jobVariables = currentBuild.getBuildVariables();
    	println "${jobVariables.MY_VERSION}";
    }

    在pipeline script中创建的环境变量只能在当前pipeline工程中生效,如果想要设置全局环境变量,可以在jenkins系统配置中进行配置。

    进入【Manage Jenkins】-> 【Configure System】-> 【Global properties】,新增环境变量,这里设置的环境变量是全局生效的。

    params

    对于参数的读取可以使用params来访问,groovy脚本中可以使用params.get()env.getProperty()方法来获取:

    def ParamDemo(){
    	def deploy_env = params.get("DEPLOY_ENV") // or: params."${paramName}"
    	println "DEPLOY_ENV = ${deploy_env}";
    	
    	def debug_build = env.getProperty("DEBUG_BUILD")
    	println "DEBUG_BUILD = ${debug_build}";
    }

    pipeline脚本如下:

    // @Library('pipelinelibs2@main')   // Github库 
    @Library('pipelinelibs@1.0') _   // SVN库
    
    import com.hiyongz.MyLib
    def mylib = new MyLib();
    
    pipeline{
        agent {
            label "master"
        }
        parameters {
            string(name: 'DEPLOY_ENV', defaultValue: 'staging', description: '') 
            text(name: 'DEPLOY_TEXT', defaultValue: 'One\nTwo\nThree\n', description: '') 
            booleanParam(name: 'DEBUG_BUILD', defaultValue: true, description: '')
            choice(name: 'CHOICES', choices: ['one', 'two', 'three'], description: '')
            password(name: 'PASSWORD', defaultValue: 'SECRET', description: 'A secret password')
        }
        stages{	
    	stage("Param Test") {
    		steps {
    		    script {
    			println "DEPLOY_ENV = ${params.DEPLOY_ENV}";
                mylib.ParamDemo();
    		    }			
    		}
    	}
    	}
    }

    构建结果:

    DEPLOY_ENV = staging
    [Pipeline] echo
    DEPLOY_ENV = staging
    [Pipeline] echo
    DEBUG_BUILD = true

    currentBuild

    currentBuild变量可以用来获取当前构建的一些属性,比如absoluteUrl、projectName、result等,更多支持的属性方法可以访问:${JENKINS_URL}/pipeline-syntax/globals

    pipeline{
        agent {
            label "master"
        }
        stages{	
    	stage("Param Test") {
    		steps {
    		    script {
    			    println "build number: ${currentBuild.number}";
    			    println "current result: ${currentBuild.currentResult}";
    			    println "build URL: ${currentBuild.absoluteUrl}";
    		    }			
    		}
    	}
    	}
    }

    manager

    manager是Groovy Postbuild插件提供的全局变量,用于构建后操作,它是在jenkins JVM 中执行groovy脚本。可用来更改构建结果,显示构建摘要信息等,下面来举几个例子。

    1、addShortText方法

    语法:addShortText(text, color, background, border, borderColor)

    pipeline {
        agent {
            label 'master'
        } 
        stages {
            stage('manager usage') {
                steps {
                    script {
                        manager.addShortText("hello world",'black','lightgreen','5px','yellow')
                        currentBuild.description = "Foreground: black\n"
                        currentBuild.description += "Background: lightgreen\n"
                        currentBuild.description += "Border size: 5px\n"
                        currentBuild.description += "Border color: yellow" 
                    }
                }
            }
        }
    }

    效果如下图:

    2、添加徽章图标

    添加删除图标相关方法:

    • addBadge(icon, text)
    • addBadge(icon, text, link)
    • addWarningBadge(text)
    • addErrorBadge(text)
    • addHtmlBadge(html)
    • removeBadges()
    • removeBadge(index)

    还可以设置构建结果:

    • buildUnstable() - 设置构建结果为 UNSTABLE.
    • buildFailure() -设置构建结果为 FAILURE.
    • buildSuccess() - 设置构建结果为 SUCCESS.

    pipeline脚本举例:

    pipeline {
        agent {
            label 'master'
        } 
        stages {
            stage('manager usage') {
                steps {
                    script {
                        echo "buildFailure test"
                    }
                }
            }
        }
        post {
            always {
                script {
                    if(manager.logContains(".*buildFailure.*")) {
                        manager.addWarningBadge("build Failure.")
                        manager.buildFailure()
                    }                
                    if(manager.build.result.isBetterOrEqualTo(hudson.model.Result.UNSTABLE)) {
                        manager.addBadge("success.gif", "success")
                    } else {
                        manager.addBadge("error.gif", "failed")
                    }
                    manager.addBadge("text.gif", "console output","${currentBuild.absoluteUrl}/console")
                }
            }
                
        }
    }

    构建效果图:

    注意Groovy Postbuild 在2.0版本以后引入了 Script Security Plugi,对一些非白名单方法(比如上述脚本使用到的logContains、build方法)需要管理员同意,可以进入【Manage Jenkins】 > 【In-process Script Approval】同意相关方法:

    参考资料:

    1. https://plugins.jenkins.io/groovy-postbuild/
    2. https://javadoc.jenkins-ci.org/index-core.html
    --THE END--

    欲忘忘未得,欲去去无由。——唐·白居易 《寄远》

    出处:https://blog.csdn.net/u010698107/article/details/123307911

    =======================================================================================

    出处:https://blog.csdn.net/u010698107/category_10842276.html

  • 相关阅读:
    关于字符串转义的代码
    JAVA发布aar文件
    apache虚拟主机配置HTTPS
    font-face跨域办法
    Javascript数组方法(译)
    Python动态生成变量
    给AOP的after函数使用原函数局部变量
    stopImmediatePropagation的应用
    IE9或以上的浏览器flash值为空时,导致domready不触发
    html写法对gzip压缩率的影响
  • 原文地址:https://www.cnblogs.com/mq0036/p/16146065.html
Copyright © 2020-2023  润新知