Jenkins

中文官网:Jenkins
参考书籍:《Jenkins 2.x实践指南》 翟志军
构建伟大,无所不能
Jenkins是开源CI&CD软件领导者, 提供超过1000个插件来支持构建、部署、自动化, 满足任何项目的需要。

一 前言

1.1 生产三要素

在软件工程领域,生产力三要素又分别指的是什么呢?

  • 劳动力:通常将软件开发工程师、测试工程师认为是劳动力。
  • 劳动资料:从硬件、软件的角度对生产工具进行了分类。· 硬件:开发时使用的电脑、机械键盘、灵敏的鼠标、网络速度等。· 软件:IDE(如Eclipse、IntelliJ IDEA)、构建工具(如Webpack、Maven)、协作工具(如Jira)、部署工具(如Ansible、Puppet)等。
  • 劳动对象:不像制造汽车,在开发软件时,劳动对象则是看不见、摸不着的知识。

笑话一则

程序员笑话一则:程序员在椅子上打斗,经理叫他们回去,其中一位说:正在编译呢!经理回答:哦,那你们继续。

1.2 市面上流行的其他工具

参考文章:值得推荐的13个 Jenkins 替代方案
总结一句话,适合自己的才是最好的

1.3 Window 安装

  1. 下载 Jenkins.
  2. 打开终端进入到下载目录.
  3. 运行命令 java -jar jenkins.war --httpPort=8080.
  4. 打开浏览器进入链接 http://localhost:8080.
  5. 按照说明完成安装

这里采用Jar安装,安装完毕之后再设置中设置开机自启就行了,当然还有其他方式主流的是Linux上采用Docker安装

1.4 插件安装

这里的插件可以自己选择安装,在进入系统之前可以默认选择给你推荐的的插件

1.5 系统配置

主界面

image.png 1.5.1 修改密码

image.png

image.png 1.5.2 本地工具配置

Maven,NodeJs,JDK,Git
image.png
image.png
image.png
image.png
image.png

1.5.3 服务器配置

这里主要是我们的文件推送服务器配置,这里可以有多个
image.png

1.5.4 查看系统变量

系统环境变量,在我们的编码中可能会存在编码问题这时候就需要设置系统编码,否则可能会乱码
image.png

1.5.5 钉钉通知配置

钉钉的机器人配置参考网上的文章吧,有很多自行百度吧,这里主要是预警或者消息配置,当然也可以邮件通知
image.png
image.png

二 实战编写

2.1 SpringBoot+Jenkinsfile+Pipeline

新建项目信息

  • 首先我们在Jenkins中新建Item,这里我们采用流水线的配置,填写自己的项目名称

image.png

  • 配置必要信息

image.png

  • 配置轮循方式,这里可以采用两种,定时器和检测代码变更

image.png

  • 仓库配置,我这里以Svn为例,当然也可以Git

image.png
这里我们需要记到是Svn地址或者Git地址,然后添加密码凭证
image.png
注意这个文件的名称我们需要再Svn仓库或者在Git仓库获取到该脚本文件
image.png
好了,我们的项目配置就完毕,接下里我们在项目中配置脚本文件,下面我们来看那可能配置文件的编写

Idea 配置

  • 首先我们需要再Idea中配置Jenkins文件

image.png
编写Jenkins文件,我阿里梳理一下Jenkins脚本文件中作的事情

  • Maven,调用本地Maven来进行打包
stage('Build') {
     steps {
                echo 'begin build'
                bat 'mvn clean install'
            }
 }
  • 开始上传文件到指定服务器中,这里需要SSPublish插件,这里我们可以采用Jenkins自带的Pipeline语法工具

image.png
image.png
image.png

        stage('begin upload') {
            steps {
                sshPublisher(publishers: [sshPublisherDesc(configName: 'ComPany Server', transfers: [sshTransfer(cleanRemote: false, excludes: '', execCommand: '''
               ''', execTimeout: 120000, flatten: false, makeEmptyDirs: false, noDefaultExcludes: false, patternSeparator: '[, ]+', remoteDirectory: '.', remoteDirectorySDF: false, removePrefix: 'target', sourceFiles: 'target/FeedbackSystem-0.0.1-SNAPSHOT.jar')], usePromotionTimestamp: false, useWorkspaceInPromotion: false, verbose: false)])
            }
        }
  • 执行Jar运行,先备份一份文件,在监听端口是否运行,运行jar包,注意这里需要sshCommand插件
 stage('begin run') {
            steps {
                script {
                    def currentDate = new Date().format('yyyy-MM-dd-HH-mm-ss')
                    def remoteBackupsFilePath = "/jar/feedback/backups/FeedbackSystem-0.0.1-SNAPSHOT_${currentDate}.jar"
                    def logFilePath = "/jar/feedback/logs/feedback_${currentDate}.log"
                    def remoteFilePath = "/jar/feedback/FeedbackSystem-0.0.1-SNAPSHOT.jar"
                    sshCommand remote: remote, command: '''
                    if netstat -tln | grep ":9020\\s" &> /dev/null; then
                        process_id=$(lsof -t -i:9020)
                        kill ${process_id}
                    fi
                    '''
                    sshCommand remote: remote, command: "cp ${remoteFilePath} ${remoteBackupsFilePath}"
                    sshCommand remote: remote, command: "nohup /usr/java/jdk1.8.0_131/bin/java -jar ${remoteFilePath} > ${logFilePath} 2>&1 &"
                }
            }
        }
  • 成功或失败通知,注意robot是自己配置的钉钉机器人名称
post {
        success {
            echo 'success'
            wrap([$class: 'BuildUser']) {
                dingtalk(
                        robot: 'FeedBackSystem',
                        type: 'MARKDOWN',
                        title: "success: ${JOB_NAME}",
                        text: ["### 项目信息",
                               '---',
                               "- 项目名称: XXXXXXX",
                               '---',
                               "### 构建信息",
                               '---',
                               "- 构建编号: ${BUILD_ID}",
                               "- 构建状态: **<font color=#008000>${currentBuild.result}</font>**",
                               '---',
                               "### 执行人",
                               '---',
                               "- ${BUILD_USER}",
                               "",
                               '---',
                               "### 持续时间",
                               '---',
                               "- ${currentBuild.durationString}",
                               "",
                               '---'
                        ]
                )
            }
        }
        failure {
            echo 'failure'
            wrap([$class: 'BuildUser']) {
                dingtalk(
                        robot: 'FeedBackSystem',
                        type: 'MARKDOWN',

                        title: "failure: ${JOB_NAME}",
                        text: ["### 项目信息",
                               '---',
                               "- 项目主体: XXXXXXX",
                               '---',
                               "### 构建信息",
                               '---',
                               "- 构建状态: **<font color=#008000>${currentBuild.result}</font>**",
                               '---',
                               "### 执行人",
                               '---',
                               "- ${BUILD_USER}",
                               "",
                               '---',
                               "### 持续时间",
                               '---',
                               "- ${currentBuild.durationString}",
                               "",
                               '---'
                        ]
                )
            }
        }
    }

完整案例

def remote = [:]
remote.name = 'saltm'
remote.host = ''
remote.user = ''
remote.password = ''
remote.allowAnyHosts = true
pipeline {
    agent any
    stages {
        stage('Maven') {
            steps {
                echo 'begin Maven'
                bat 'mvn -version'
            }
        }
        stage('Build') {
            steps {
                echo 'begin build'
                bat 'mvn clean install'
            }
        }
        stage('begin upload') {
            steps {
                sshPublisher(publishers: [sshPublisherDesc(configName: 'ComPany Server', transfers: [sshTransfer(cleanRemote: false, excludes: '', execCommand: '''
               ''', execTimeout: 120000, flatten: false, makeEmptyDirs: false, noDefaultExcludes: false, patternSeparator: '[, ]+', remoteDirectory: '.', remoteDirectorySDF: false, removePrefix: 'target', sourceFiles: 'target/FeedbackSystem-0.0.1-SNAPSHOT.jar')], usePromotionTimestamp: false, useWorkspaceInPromotion: false, verbose: false)])
            }
        }
        stage('begin run') {
            steps {
                script {
                    def currentDate = new Date().format('yyyy-MM-dd-HH-mm-ss')
                    def remoteBackupsFilePath = "/jar/feedback/backups/FeedbackSystem-0.0.1-SNAPSHOT_${currentDate}.jar"
                    def logFilePath = "/jar/feedback/logs/feedback_${currentDate}.log"
                    def remoteFilePath = "/jar/feedback/FeedbackSystem-0.0.1-SNAPSHOT.jar"
                    sshCommand remote: remote, command: '''
                    if netstat -tln | grep ":9020\\s" &> /dev/null; then
                        process_id=$(lsof -t -i:9020)
                        kill ${process_id}
                    fi
                    '''
                    sshCommand remote: remote, command: "cp ${remoteFilePath} ${remoteBackupsFilePath}"
                    sshCommand remote: remote, command: "nohup /usr/java/jdk1.8.0_131/bin/java -jar ${remoteFilePath} > ${logFilePath} 2>&1 &"
                }
            }
        }
    }
    post {
        success {
            echo 'success'
            wrap([$class: 'BuildUser']) {
                dingtalk(
                        robot: 'FeedBackSystem',
                        type: 'MARKDOWN',
                        title: "success: ${JOB_NAME}",
                        text: ["### 项目信息",
                               '---',
                               "- 项目名称: XXXXXX",
                               '---',
                               "### 构建信息",
                               '---',
                               "- 构建编号: ${BUILD_ID}",
                               "- 构建状态: **<font color=#008000>${currentBuild.result}</font>**",
                               '---',
                               "### 执行人",
                               '---',
                               "- ${BUILD_USER}",
                               "",
                               '---',
                               "### 持续时间",
                               '---',
                               "- ${currentBuild.durationString}",
                               "",
                               '---'
                        ]
                )
            }
        }
        failure {
            echo 'failure'
            wrap([$class: 'BuildUser']) {
                dingtalk(
                        robot: 'FeedBackSystem',
                        type: 'MARKDOWN',

                        title: "failure: ${JOB_NAME}",
                        text: ["### 项目信息",
                               '---',
                               "- 项目主体: XXXXXX",
                               '---',
                               "### 构建信息",
                               '---',
                               "- 构建状态: **<font color=#008000>${currentBuild.result}</font>**",
                               '---',
                               "### 执行人",
                               '---',
                               "- ${BUILD_USER}",
                               "",
                               '---',
                               "### 持续时间",
                               '---',
                               "- ${currentBuild.durationString}",
                               "",
                               '---'
                        ]
                )
            }
        }
    }
}

  • 查看运行日志

image.png

  • 机器人

image.png

2.2 Vue+Jenkinsfile+Pipeline

前面的新建项目的步骤我就不多说了,与上面一样,我们来看看脚本文件的编写

def remote = [:]
remote.name = 'saltm'
remote.host = ''
remote.user = ''
remote.password = ''
remote.allowAnyHosts = true
pipeline {
		agent any
		stages {
			stage('Npm Install') {
				steps {
					bat 'node -v'
					bat 'npm install'
				}
			}
			stage('Npm Build') {
				steps {
					bat 'npm run build:prod'
				}
			}
			stage ("Linux Clear Dist") {
            steps {
							 script {
								sshCommand remote: remote, command: 'rm -rf /jar/html/dist/'
							 }
            }
        }
			stage ("Upload Dist") {
						steps {
							sshPublisher(publishers: [sshPublisherDesc(configName: 'FeedBackWeb', transfers: [sshTransfer(cleanRemote: false, excludes: '', execCommand: '', execTimeout: 120000, flatten: false, makeEmptyDirs: false, noDefaultExcludes: false, patternSeparator: '[, ]+', remoteDirectory: 'dist', remoteDirectorySDF: false, removePrefix: 'dist', sourceFiles: 'dist/**')], usePromotionTimestamp: false, useWorkspaceInPromotion: false, verbose: false)])
						}
				}
		}
		post {
        success {
            echo 'success'
            wrap([$class: 'BuildUser']) {
                dingtalk(
                        robot: 'FeedBackSystem',
                        type: 'MARKDOWN',
                        title: "success: ${JOB_NAME}",
                        text: ["### 项目信息",
                               '---',
                               "- 项目名称: xxxxxx",
                               '---',
                               "### 构建信息",
                               '---',
                               "- 构建编号: ${BUILD_ID}",
                               "- 构建状态: **<font color=#008000>${currentBuild.result}</font>**",
                               '---',
                               "### 执行人",
                               '---',
                               "- ${BUILD_USER}",
                               "",
                               '---',
                               "### 持续时间",
                               '---',
                               "- ${currentBuild.durationString}",
                               "",
                               '---'
                        ]
                )
            }
        }
        failure {
            echo 'failure'
            wrap([$class: 'BuildUser']) {
                dingtalk(
                        robot: 'FeedBackSystem',
                        type: 'MARKDOWN',
                        title: "failure: ${JOB_NAME}",
                        text: ["### 项目信息",
                               '---',
                               "- 项目主体: xxxxx",
                               '---',
                               "### 构建信息",
                               '---',
                               "- 构建状态: **<font color=#008000>${currentBuild.result}</font>**",
                               '---',
                               "### 执行人",
                               '---',
                               "- ${BUILD_USER}",
                               "",
                               '---',
                               "### 持续时间",
                               '---',
                               "- ${currentBuild.durationString}",
                               "",
                               '---'
                        ]
                )
            }
        }
    }
}

当然上面只是一种方式,实现的方式还有多种,下面我们来介绍一些基本的概念

三 Pipeline语法基本知识

3.1 Groovy知识

参考网站:初探Groovy——无缝兼容Java的脚本语言

3.2 pipeline的组成

Jenkins pipeline其实就是基于Groovy语言实现的一种DSL(领域特定语言),用于描述整条流水线是如何进行的,流水线的内容包括执行编译、打包、测试、输出测试报告等步骤。

pipeline {
    agent any
    
    stages {
        stage('Build') {
            steps {
                sh 'mvn clean package' // 使用 Maven 构建项目
            }
        }
        
        stage('Test') {
            steps {
                sh 'mvn test' // 运行单元测试
            }
        }
        
        stage('Deploy') {
            steps {
                sh 'mvn deploy' // 部署构件到远程仓库或服务器
            }
        }
    }
}

  • pipeline:代表整条流水线,包含整条流水线的逻辑
  • stage部分:阶段,代表流水线的阶段,每个阶段都必须有名称。本例中,build就是此阶段的名称。
  • stages部分:流水线中多个stage的容器。stages部分至少包含一个stage。
  • steps部分:代表阶段中的一个或多个具体步骤(step)的容器。steps部分至少包含一个步骤,本例中,echo就是一个步骤。在一个stage中有且只有一个steps。
  • agent部分:指定流水线的执行位置(Jenkins agent)。流水线中的每个阶段都必须在某个地方(物理机、虚拟机或Docker容器)执行,agent部分即指定具体在哪里执行。
  • 以上每一个部分(section)都是必需的,少一个,Jenkins都会报错。

3.3 Post部分

post部分包含的是在整个pipeline或阶段完成后一些附加的步骤,post部分是可选的,所以并不包含在pipeline最简结构中。但这并不代表它作用不大,根据pipeline或阶段的完成状态,post部分分成多种条件块,包括:

  • always:不论当前完成状态是什么,都执行。
  • changed:只要当前完成状态与上一次完成状态不同就执行。
  • fixed:上一次完成状态为失败或不稳定(unstable),当前完成状态为成功时执行。
  • regression:上一次完成状态为成功,当前完成状态为失败、不稳定或中止(aborted)时执行。•
  • aborted:当前执行结果是中止状态时(一般为人为中止)执行。
  • failure:当前完成状态为失败时执行。
  • success:当前完成状态为成功时执行。
  • unstable:当前完成状态为不稳定时执行。
  • cleanup:清理条件块。不论当前完成状态是什么,在其他所有条件块执行完成后都执行。
pipeline {
    agent any
    
    stages {
        // 定义流水线的阶段
    }
    
    post {
        success {
            // 当流水线成功完成时执行的操作
            // 例如发送邮件通知或触发其他流水线
        }
        
        failure {
            // 当流水线失败时执行的操作
            // 例如发送错误报告或执行回滚操作
        }
        
        always {
            // 无论流水线成功还是失败,都会执行的操作
            // 例如清理临时文件或更新报告
        }
    }
}

3.4 Post支持的指令

  1. agent:指定在哪个节点上运行流水线,可以是任意节点或特定的代理节点。
  2. stages:定义流水线的阶段,每个阶段可以包含一个或多个步骤。
  3. steps:在阶段中定义具体的步骤,用于执行构建、测试、部署等操作。
  4. stage:定义流水线的一个阶段,用于逻辑上划分流水线,并可在 Jenkins 界面中显示可视化进度。
  5. script:在流水线中执行一段 Groovy 脚本代码,可以用于编写自定义逻辑。
  6. input:在流水线中暂停执行,等待用户输入或批准继续执行。
  7. environment:定义环境变量,可以在流水线中传递和使用数据。
  8. parameters:定义流水线的参数,允许用户在执行时提供输入。
  9. options:定义流水线的选项,如超时设置、并行度控制等。
  10. when:根据条件控制流水线的执行路径,可以基于环境变量、构建状态等条件进行条件判断。
  11. post:定义在流水线执行完成后执行的操作,如成功、失败、始终执行等。
  12. parallel:在流水线中并行执行多个步骤或阶段,提高执行效率。

在使用指令时,需要注意的是每个指令都有自己的“作用域”。如果指令使用的位置不正确,Jenkins将会报错。

3.5 环境变量

环境变量可以被看作是pipeline与Jenkins交互的媒介,比如,可以在pipeline中通过BUILD_NUMBER变量知道构建任务的当前构建次数。环境变量可以分为Jenkins内置变量和自定义变量,比如在上面我们发送邮件的时候就用到了jenkins的环境变量

  • BUILD_NUMBER:构建号,累加的数字。在打包时,它可作为制品名称的一部分,比如server-2.jar。BRANCH_NAME:多分支pipeline项目支持。当需要根据不同的分支做不同的事情时就会用到,比如通过代码将release分支发布到生产环境中、master分支发布到测试环境中。
  • BUILD_URL:当前构建的页面URL。如果构建失败,则需要将失败的构建链接放在邮件通知中,这个链接就可以是BUILD_URL。
  • GIT_BRANCH:通过git拉取的源码构建的项目才会有此变量。

这里可以参考全局变量参考
image.png

3.6 拆分条件

自动化是指pipeline按照一定的规则自动执行,而这些规则被称为pipeline触发条件。

时间触发

时间触发是指定义一个时间,时间到了就触发pipeline执行。在Jenkins pipeline中使用trigger指令来定义时间触发。tigger指令只能被定义在pipeline块下,Jenkins内置支持cron、pollSCM,upstream三种方式

Jenkins trigger cron语法

  • MINUTE:一小时内的分钟,取值范围为0∼59。
  • HOUR:一天内的小时,取值范围为0∼23。
  • DOM:一个月的某一天,取值范围为1∼31。
  • MONTH:月份,取值范围为1∼12。
  • DOW:星期几,取值范围为0∼7。0和7代表星期天。
  • *:匹配所有的值• M-N:匹配M 到N 之间的值。
  • M-N/X or*/X:指定在M 到N 范围内,以X值为步长。
  • A,B,· · ·,Z:使用逗号枚举多个值。

轮询代码仓库:pollSCM

轮询代码仓库是指定期到代码仓库询问代码是否有变化,如果有变化就执行。
image.png

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

长安不及十里

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值