前言

最近不知道写点什么,想着补充一下自己的以前的文档,有时间就补充一下jenkins,nginx。。。
以前个人总结的jenkins文档:

Jenkins官方文档:
https://www.jenkins.io/zh/doc/book/pipeline/

下面介绍一下Jenkins Pipeline的基本用法
由于内容较多,为了讲解编辑了大量的补充性的内容,建议首次看的可以不看补充内容

Pipeline简介



Pipeline是Jenkins 2.x的核心的特性,帮助Jenkins实现从CI到CD与DevOps的转变。其中文翻译为管道,也可以叫做流水线
它是一套运行于Jenkins上的工作流框架,将原本独立运行于单个或者多个节点的任务连接起来,实现单个任务难以完成的复杂流程编排与可视化
简单的来说就是将一套上线或者发布变得流程化和可视化

和传统的扔代码到线上以及使用jenkins简单的调用脚本的上线方式的区别:
更加的流程化和安全。可以清楚的显示在哪个流程中有问题,并自动停止执行。如果是之前文档演示的几种方式,如果出问题了,需要翻整篇的日志,去查询哪个地方有问题。并且最后页面上的显示,只有2种结果,要么最后成功要么最后失败,比较浪费时间
更加的直观显示流程的状态,可视化的界面更加的令人舒适

jenkins上的poll scm怎么用的 jenkins pipeline sh_maven



基本思路



将一个上线的过程进行分解和流程化,分成多个环节。例如:清理空间,拉取代码,发布到环境,备份,重启服务,验证,通知等环节,然后我们需要将这些步骤套用pipeline的语法

按照以前的方式也许一个脚本里就蕴含了这些流程,但是这实际上并不算是配合jenkins实现了流程化,仅仅只算是使用jenkins进行了简单的发布。虽然完成了发布,但是看起来并不”高级“和舒适

直白的说,使用这个的目的不仅是为了方便自己和规范流程,对于部分领导并不喜欢你看上去很闲,简单的认为越复杂越专业。配置时越复杂越看不懂,图形界面越好看才是”他的需求“,效率并不会让他舒服,只会认为你工作不饱和,



Pipeline的内容



实际上Pipeline的语法较多,有很大部分并不一定能用到
因此这里只演示几种常见的配置和创建方式,更多的需要研究官方文档



Pipeline关键概念



Stage  阶段,一个Pipeline可以划分为若干个Stage,每个Stage代表一组操作
       你可以把你在此阶段后要配置的过程进行一个总结,将这个阶段叫做 构建 测试 发布 或者其他
       Stage是一个逻辑分组的概念,可以跨多个Node

Node   节点,一个Node就是一个Jenkins节点,或者是Master,或者是slave,是执行Step的具体运行期环境

Step   步骤,Step是最基本的操作单元,小到创建一个目录,大到构建一个Docker镜像,由各类Jenkins Plugin提供


Pipeline语法



Pipeline支持两种语法:声明式语法(Declarative Pipeline) 和脚本化语法(Scripted Pipeline)

两者都能够使用pipeline内置的插件或者插件提供的steps,两者都可以利用共享库扩展

从官网上来说,声明式流水线相比脚本化的流水线语法,它提供更丰富的语法特性,是为了使编写和读取流水线代码更容易而设计的。其语法更严格,有固定的组织结构,更容易生成代码段,可以Blue Ocean插件进行简单的编排(实际上部分工作者还是喜欢类似于脚本化语法的方法,在声明式流水线中去调用脚本)

但是对于一些使用较老版本jenkins的用户,更习惯使用脚本化的语法。实际上脚本化的语法要更加灵活方便,用户可以根据自己的业务进行灵活的实现和扩展实现其他需求,例如 配合编写的python或其他脚本,完成一些复杂的任务
声明式语法由于语法严格,有固定的,严格的格式

声明式由块,章节,指令,步骤,节点组成;必须包含在固定格式pipeline{}块内;每个声明必须独立一行,行尾无需使用分号

块(blocks{})
由大括号括起来的语句,如pipeline{},Section{},parameters{},script{}

章节(Sections)
通常包含一个或多个指令或步骤。如 agent 、post、stages、steps

指令(Directives)
environment、options、parameters、triggers(触发)、stage、tools、when

步骤(Steps)

agent
必须存在,agent必须在pipeline块内的顶层定义,但stage内是否使用使可选的



Pipeline的配置



预计在这里演示一下Pipeline的创建方法,然后再演示几个常用的配置
实际上还有Blue Ocean的创建pipeline的方法,但是我这边更常用一些老的方法



Pipeline的常见配置



<1>新建一个item 项目

jenkins上的poll scm怎么用的 jenkins pipeline sh_Jenkins_02



<2>根据你的项目的需求选择要创建的格式

由于要演示Pipeline,可以选择流水线 或者自由风格的软件项目

jenkins上的poll scm怎么用的 jenkins pipeline sh_centos_03



<3>设置上线记录和描述(可跳过)

和之前jenkins文档里配置方式没区别
也可省略,到pipeline里配置

jenkins上的poll scm怎么用的 jenkins pipeline sh_maven_04



<4>配置流水线

选择2种语法格式的任意一个即可,点击右侧j进行选择 可以显示jenkins自带的模板

jenkins上的poll scm怎么用的 jenkins pipeline sh_maven_05



可以点击流水线语法,选择想要的步骤,生成流水线脚本

接着页面就会显示这个步骤要使用的语法

jenkins上的poll scm怎么用的 jenkins pipeline sh_Jenkins_06


jenkins上的poll scm怎么用的 jenkins pipeline sh_maven_07

<5>创建dingding机器人的robot

创建dingding机器人
""
钉钉插件网址:
"http://updates.jenkins-ci.org/download/plugins/dingding-notifications/"
实际上从dingding插件的2.0及其以上的版本开始,钉钉通知的设置方式产生了较大的变化,要在系统管理里设置,之后的版本适应了不同的生产环境,通知的配置更加的灵活
建议在jenkins版本允许的基础上,使用2.0以上插件(钉钉2.0插件最低对应jenkins 2.176.4及其以上)

以下演示的是dingding插件2.0及其以上版本的配置方法
演示用的jenkins是2.3.44

jenkins上的poll scm怎么用的 jenkins pipeline sh_Jenkins_08



jenkins上的poll scm怎么用的 jenkins pipeline sh_maven_09



jenkins上的poll scm怎么用的 jenkins pipeline sh_服务器_10



id不用填,让其自动生成(这个就是后面pipeline中的robot)

填入webhook


认证方式(和钉钉创建机器人的设置保持一致)

jenkins上的poll scm怎么用的 jenkins pipeline sh_服务器_11

jenkins上的poll scm怎么用的 jenkins pipeline sh_服务器_12

2.0以前的版本,不能在系统设置中设置dingding
它是在安装后,直接在该项目的 构建后操作 中配置 钉钉通知,根据要求填入即可


声明式Pipeline

pipeline {                                                //首先表明这是一个声明式的pipeline
    agent any                                             //指定整个管道或特定阶段在Jenkins环境中的执行位置,选择在jenkins的哪个节点执行,常见any, none, label, node, docker, dockerfile。此处的意思是 在任意jenkins环境中可用的机器上执行pipeline
也可以单独指定某个节点agent{ label 'slave1'}
    options {                                             //用于配置Jenkins pipeline本身有的选项
        buildDiscarder(logRotator(numToKeepStr: '30'))    //表示保留30次构建历史
        timestamps()                                      //打印日志带上对应时间
        timeout(time: 10, unit: 'MINUTES')                //流水线构建超过10分钟,终止构建
    }
    
#    environment {                                        //设置设置环境变量,可定义在stage或pipeline部分。例如可以设置IP的变量,便于之后的阶段中调用
#        TST = /data/workspace2
#    }

#    triggers{                                            //设置触发器,格式类似Centos计划任务
#        pollSCM('H/5 * * * *')
#    }

    stages {                                              //声明这是一个多个阶段的流水线
        stage('清理工作空间') {                             //声明这是一个什么阶段(根据自己的情况创建不同的阶段) 
            steps {                                       //下面需要填入这个阶段的具体步骤
               script{
                    println env.WORKSPACE
                    dir("${env.WORKSPACE}/"){   
                    	sh "pwd"
                    }
                    sh("ls -al ${env.WORKSPACE}")
                    deleteDir()
                    sh("ls -al ${env.WORKSPACE}")   
            }
        }
        
        stage('拉取代码') {
            steps {
                git credentialsId: '89e62xxxx-xxxxxx', url: 'git@gitlab.xxx.cn:xxxx.git'
            }
        }

        stage('mvn构建'){
           withMaven(maven: 'maven') {
                sh "cd  $WORKSPACE/"
                sh "mvn clean install -Dmaven.test.skip=true"
            }
        } 

        stage(部署){
            steps{
                sh 'scp $WORKSPACE/target/xxx.jar root@业务服务器的ip:/jar_dir_path/'
                sh 'ssh root@你业务服务器的ip "/script/deploy.sh"'    //执行远程服务器上的脚本  
            }
        }
        
      }
    post {                                                 //post指的是构建后操作,success成功后执行,failure失败后执行
        success {
            dingtalk (
                    robot: "你的机器人的id不是token",
                    type:'ACTION_CARD',                    //通知的消息类型,即采用的格式
                    atAll: false,                          //是否@所有人
                    title: "构建成功:${env.JOB_NAME}",      //通知的标题
                    text: [
                            "### xx平台上线 ${env.JOB_NAME} ",
                            '---',
                            "- 任务:[${currentBuild.displayName}](${env.BUILD_URL})",
                            '- 状态:<font color=#00CD00 >上线成功</font>',
                            "- 持续时间:${currentBuild.durationString}".split("and counting")[0],
                            "- 执行人:${BUILD_USER}",
                           
                    ]
            )
        }
        failure{
            dingtalk (
                    robot: "你的机器人的id不是token",
                    type:'ACTION_CARD',
                    atAll: false,
                    title: "构建失败:${env.JOB_NAME}",
                    text: [
                            "### xx平台上线 ${env.JOB_NAME}",
                            '---',
                            "- 任务:[${currentBuild.displayName}](${env.BUILD_URL})",
                            '- 状态:<font color=#EE0000 >上线失败</font>',
                            "- 持续时间:${currentBuild.durationString}".split("and counting")[0],
                            "- 执行人:${BUILD_USER}"
                    ]
            )
        }
    }
}



}

<1>

实际上,上面的示例可根据自己需求决定是否采用

本示例stages下的,

第一个阶段是上线前清理jenkins服务器上该项目的工作空间

WORKSPACE          是这个项目的工作目录的绝对路径,为了避免编译时产生干扰,所以上线前清理旧代码
dir()              改变当前的工作目录,相当于Centos 的 cd(为了演示所以加了一句dir)
deleteDir()        不加参数,默认递归删除WORKSPACE下的文件和文件夹
script             该script步骤需要一个脚本式Pipeline,并在声明性Pipeline中执行。用这个语法,后面可以用当前环境中的命令的执行操作
sh                 用这个方法,后面可以执行shell命令,有时也会经常用来调用jenkins服务器上的脚本;bat是windows命令

<2>

第二个阶段是拉取代码
git的语法可根据需求使用流水线语法生成
可以选择分支,默认是master

<3>

第三个阶段是编译
withMaven需要装一个插件Pipeline Maven Integration,会根据后面填写的变量指定maven,默认读取的是jenkins服务器的环境变量中的maven

如不使用这个语法,去除后,编译命令直接写绝对路径也可以
sh "/data/bin/mvn clean install -Dmaven.test.skip=true"

<4>

第四个阶段是部署
可以用命令行、ansible、调用脚本等方式。构建镜像或k8s的apply都可以
目标是将代码弄到线上环境,并使服务生效
(别忘了产生代码备份,根据需求)


随着需求的不同,方法也不同,所以示例仅列举了部分常用的
#       stage(部署){
#            steps{
#                ansiblePlaybook installation: 'ansible-playbook', inventory: '/etc/ansible/online1/hosts', playbook: '/etc/ansible/online1/project.yml'
#            }
#        }


#       stage(部署){
#            steps{
#                sh "sh $WORKSPACE/../script/online.sh"
#            }
#        }

补充:
实际上通常部署或其他阶段还能细分,使用when和当上线时工作人员手动从web界面填入的变量,产生不同的结果

创建文本或其他格式的环境变量,配置后,在上线时会要求工作人员去填入参数

jenkins上的poll scm怎么用的 jenkins pipeline sh_centos_13

jenkins上的poll scm怎么用的 jenkins pipeline sh_Jenkins_14

stages {
        stage('编译'){
            when {                                           //当下方的条件满足,这个阶段才执行
				environment name: 'GITENV', value: 'uat'     //如果环境变量的值与给定的值相同就执行
			}
            withMaven(maven: 'maven') {                      
                sh "cd  $WORKSPACE/"
                sh "mvn clean package -Puat -Dmaven.test.skip=true"
            }
        }

<5>

第五个阶段是通知
也可以通过python或shell,使用邮箱或钉钉及其他方式,对上线结果进行通知
如果是使用相关插件的,注意jenkins版本和插件版本

补充1
2.0以前的dingding插件,项目如果用pipline的配置方法
post {
		success {
			dingTalk accessToken:'https://oapi.dingtalk.com/robot/send?access_token=你的token', 
			imageUrl:'http:/xxxxxx/success.png',      //要在通知中插入的图片
			jenkinsUrl:'http://localhost/jenkins/',   //要跳转的url
			message:'更新提示: xxxxxxxxx上线成功',      //要发布的通知
			notifyPeople:''
		}
		failure {
			dingTalk accessToken:'https://oapi.dingtalk.com/robot/send?access_token=你的token', 
			imageUrl:'http://xxxxxx/failure.png',     
			jenkinsUrl:'http://localhost/jenkins/', 
			message:'更新提示: xxxxxxxx上线失败', 
			notifyPeople:''
		}
	}


补充2
通过curl或python的请求并发送报警,无需安装钉钉插件
但是这个方式报警需要 符合配置钉钉机器人时 设置的关键字或ip等限制

    stage("钉钉通知"){
    sh """
      curl -H 'Content-Type: application/json'  "https://oapi.dingtalk.com/robot/send?access_token=你的token" \
        -d '
         {
           "actionCard": {
              "title": "上线通知", 
              "text": "xx平台上线 \n\n  ${env.JOB_NAME} 上线成功  \n\n", 
              "hideAvatar": "0", 
              "btnOrientation": "0", 
              "singleTitle" : "查看详情",
              "singleURL" : "http://jenkins.com/"     //你的jenkins地址
              }, 
              "msgtype": "actionCard"
         }'
    """
    }



补充3
如果是一个邮件的脚本,脚本中的报警内容等参数可设置成变量,pipeline在通知这一阶段导入变量,即可实现报警内容的定制
钉钉的pipeline语法
"https://jenkinsci.github.io/dingtalk-plugin/guide/pipeline.html#参数说明"

脚本式pipeline

先创建参数化构建,后面示例的pipelien中有用到

jenkins上的poll scm怎么用的 jenkins pipeline sh_Jenkins_15



node {
    stage("清理工作空间"){
        deleteDir()
    }
}

node("slave1"){                                            //指定整个管道或特定阶段在Jenkins环境中的执行的节点,不填默认是master节点执行
也可以单独指定某个节点agent{ label 'slave1'}                     
   stage('变量配置') {
   		project_work_list=["192.168.1.1","192.168.1.2"]    //要上线的IP
        TOKEN='xxx'                                        //dingding机器人的token
   }
    stage('拉取代码') {    
        checkout([$class: 'GitSCM', branches: [[name: '*/${branch}']], doGenerateSubmoduleConfigurations: false, extensions: [], submoduleCfg: [], userRemoteConfigs: [[credentialsId: 'xxxx', url: 'http://xxxx.git']]])     //和声明式一样,可用流水线语法生成
   }
    stage('构建') {
        sh "cd  $WORKSPACE/"
        sh "mvn clean install -U  -Puat -Dmaven.test.skip=true"
   }
    stage('部署') {
        for (i <project_work_list.size();i++){
            def ip=project_work_list[i]
             if ( "${project_name}" == "bigdata" ){          //这里的project_name需要你去开启参数化构建,创建一个参数project_name。示例含义:当项目是大数据的时候,使用一种上线脚本,当项目是其他的时候,使用其他的上线脚本
		           sh "scp $WORKSPACE/target/xxx.jar root@${ip}:/jar_dir_path/"
		           sh '"ssh root@${ip} "/script/start_project.sh"'
	         }else {
	               sh "scp $WORKSPACE/target/xxx.jar root@${ip}:/jar_dir_path/"
	               sh 'ssh root@${ip} "/script/deploy.sh"'
             }
          
        }
    }
    stage("钉钉通知"){
    sh """
      curl -H 'Content-Type: application/json'  "https://oapi.dingtalk.com/robot/send?access_token=${TOKEN}" \
        -d '
         {
           "actionCard": {
              "title": "上线通知", 
              "text": "xx平台上线 \n\n  ${env.JOB_NAME} 上线成功  \n\n", 
              "hideAvatar": "0", 
              "btnOrientation": "0", 
              "singleTitle" : "查看详情",
              "singleURL" : "http://jenkins.com/"     //你的jenkins地址
              }, 
              "msgtype": "actionCard"
         }'
    """
}
能看懂声明式的,应该能看懂脚本式,基本不用解释
虽然脚本式看着简单,但是如果要深入,用的更花,需要去官方网址再研究

脚本式区别于声明式pipeline的明显的一点是,只支持stage,像stages、steps更复杂的划分则不支持,因此在脚本中仅仅看到了stage,示例中的if和for用着很方便,但是如果要在声明式用循环需要script