手把手带你一块儿从0到1搭建一个企业级的自动化构建流程 网上完整的关于多分支流水线的配置不多,但愿这篇不短的文章能给你带来帮助html
因为公司的Jenkins配置没有部署成功的通知,在我学了几天的Jenkins后终因而对公司的Jenkins配置下手了,结果我刚装完dingtalk
插件自动重启后,发现以前主管配置的构建项目数据都丢失了,害,正好给了我练手的机会,因而就有了如下从0到1的辛酸历程。前端
这里假设你的服务器已经装好了dockerjava
使用的镜像是jenkinsci/blueocean
,这是一个jenkins的稳定及持续维护的镜像源,自己就集成了Blue Ocean等使用插件,很是方便。node
docker pull jenkinsci/blueocean
复制代码
docker run -idt --name kmywjenkins -p 9090:8080 -p 60000:50000 -v jenkins-data:/var/jenkins_home -v /data/web-data/docker.sock:/var/run/docker.sock jenkinsci/blueocean
复制代码
参数解释:linux
-idt
以交互的方式、新建一个模拟终端运行容器git
--name
容器的别名web
-p
指定容器映射宿主机的端口 -> 宿主机端口:容器端口正则表达式
-v jenkins-data:/var/jenkins_home
Jenkins容器在工做的时候,若是要执行Docker的命令(例如 docker ps、docker run等),须要有个途径能链接到宿主机的docker服务,此参数就是用来创建容器和宿主机docker服务的链接的spring
-v /data/web-data/docker.sock:/var/run/docker.sock
将该容器的数据保留在宿主机的目录,这样即便容器崩溃了,里面的配置和任务都不会丢失docker
须要注意的是,docker中默认是以jenkins
用户运行的Jenkins,如需以root用户能够加参数-u root
,本示例未指定root。
有时候须要进入Jenkins容器执行一些命令,能够经过docker exec
命令访问,例如:docker exec -it [containerid] bash
若要手动重启Jenkins,能够执行如下命令:docker restart [containerid]
经过以上步骤,若是正常走到这里,能够经过如下地址访问http://121.41.16.183:9090/
,ip地址为服务器的地址。
输入一下命令获取解锁的token,docker exec kmywjenkins cat /var/jenkins_home/secrets/initialAdminPassword
在浏览器中输入对应的token以解锁:
链接git仓库,ssh链接服务器均须要相应的凭据,能够在凭据管理中先建立好,而后须要使用的地方直接选择凭据便可。这里以链接git、ssh须要的凭据为例:
类型选择Username with password
用户名密码为登陆gitte的帐号密码
ID是凭据的惟一标识,可自定义,后面在JenkinsFile中经过ID去引用凭据
配置后的结果
ssh链接服务器时须要密钥,咱们先在服务器生成一对公私钥,而后复制私钥,填入便可
类型选择SSH Username with private key
Username
是链接服务器的用户名,如jenkins
在Private Key
项选中Enter directly
,点击Add,粘贴刚复制的私钥
配置后的结果
以前的Jenkins任务是FreeStyle的方式建立的,这种方式不够灵活,界面也不够清爽,这里选择使用声明式流水线方式(Declarative Pipeline)建立,能够多分支独立构建,便于之后的扩展。
咱们这里使用 BlueOcean 这种方式来完成此处 CI/CD 的工做,BlueOcean 是 Jenkins 团队从用户体验角度出发,专为 Jenkins Pipeline 从新设计的一套 UI 界面,仍然兼容之前的 fressstyle 类型的 job,BlueOcean 具备如下的一些特性:
若是安装的是jenkinsci/blueocean
镜像,默认是已经集成了BlueOcean,没有的可前往插件管理安装对应的插件。
点击打开Blue Ocean,能够看到已经建立好的两个流水线,分别是前端和后台,须要用到不一样的工具,在后面会提到,如何建立流水线
点击建立流水线
我司用的是gitte,因此选择Git,而后填入要链接的仓库地址,须要链接到Git仓库的凭据,咱们以前已经建立好了,直接选中便可,若是未建立,在下面的表单直接编辑便可,最后点击建立流水线
到这里咱们就建立了一个多分支流水线,Jenkins会扫描仓库,带有JenkinsFile的分支会被检测出来,JenkinFile是多分支流水线的配置文件,使用的是Groovy语法,能够直接点击建立流水线,Jenkins会自动为你的项目建立一个JenkinsFile
如今能够可视化地编辑想要执行的阶段及步骤,这里加了一个打包的阶段,里面有个步骤是提示开始打包
,点击保存
填入提交信息,点击Save & Run
,会讲JenkinsFile上传到git,并根据JenkinsFile执行一个构建任务,目前的构建步骤只有一个,是提示开始打包
我这里不知道为何会卡在这个地方不动,因此我在vscode直接建立并编辑JenkinsFile,这种方式更灵活,我更推荐这种方式,下面我会先简单介绍下JeninsFile的基础语法,仅包含本项目用到的,对于中小企业的构建需求,基本够用了。
只需先了解大体的语法,具体的用法会在后面说明
// 前端项目JenkinsFile配置,后端项目配置稍有不一样,后面会区分说明
pipeline {
agent any
environment {
HOST_TEST = 'root@121.41.16.183'
HOST_ONLINE = 'jenkins@39.101.219.110'
SOURCE_DIR = 'dist/*'
TARGET_DIR = '/data/www/kuaimen-yunying-front'
}
parameters {
choice(
description: '你须要选择哪一个环境进行部署 ?',
name: 'env',
choices: ['测试环境', '线上环境']
)
string(name: 'update', defaultValue: '', description: '本次更新内容?')
}
triggers {
GenericTrigger(
genericVariables: [
[key: 'ref', value: '$.ref']
],
causeString: 'Triggered on $ref',
token: 'runcenter-front-q1w2e3r4t5',
tokenCredentialId: '',
printContributedVariables: true,
printPostContent: true,
silentResponse: false,
regexpFilterText: '$ref',
regexpFilterExpression: 'refs/heads/' + BRANCH_NAME
)
}
stages {
stage('获取git commit message') {
steps {
script {
env.GIT_COMMIT_MSG = sh (script: 'git log -1 --pretty=%B ${GIT_COMMIT}', returnStdout: true).trim()
}
}
}
stage('打包') {
steps {
nodejs('nodejs-12.16') {
echo '开始安装依赖'
sh 'yarn'
echo '开始打包'
sh 'yarn run build'
}
}
}
stage('部署') {
when {
expression {
params.env == '测试环境'
}
}
steps {
sshagent(credentials: ['km-test2']) {
sh "ssh -o StrictHostKeyChecking=no ${HOST_TEST} uname -a"
sh "scp -r ${SOURCE_DIR} ${HOST_TEST}:${TARGET_DIR}"
sh 'echo "部署成功~"'
}
}
}
stage('发布') {
when {
expression {
params.env == '线上环境'
}
}
steps {
sshagent(credentials: ['km-online']) {
sh "ssh -o StrictHostKeyChecking=no ${HOST_ONLINE} uname -a"
sh "scp -r ${SOURCE_DIR} ${HOST_ONLINE}:${TARGET_DIR}"
sh 'echo "发布成功~"'
}
}
}
}
post {
success {
dingtalk (
robot: '77d4c82d-3794-4583-bc7f-556902fee6b0',
type: 'MARKDOWN',
atAll: true,
title: '你有新的消息,请注意查收',
text:[
'# 运营管理系统发布通知',
'---',
'#### **所属:前端**',
"#### **构建任务:${env.BUILD_DISPLAY_NAME}**",
"#### **Git commit:${env.GIT_COMMIT_MSG}**",
"#### **本次更新内容:${params.update}**",
"#### **部署环境:${params.env}**",
'#### **构建结果:成功**'
]
)
}
}
}
复制代码
pipeline
必须在最外层
agent
定义了在哪一个环境里执行,默认any
stages
阶段,标识构建流程的标签块,子节点是stage
steps
执行步骤
post
全部阶段执行完成后执行一些逻辑
when
能够控制该阶段是否执行
environment
环境变量,在这里定义的变量,JenkinsFile的任何地方均可以访问
tools
项目使用到的构建工具,声明系统配置中已经定义好的工具,如maven
parameters
定义参数,能够提供用户输入或者选择
post
构建结束后会执行这里,有success
、failure
、success
,本示例将在success
(构建成功时)发起钉钉通知
因为我司的技术团队较小,CI/CD流程就没那么复杂,不会包含代码检查、自动化测试、Code Review等流程,我将简要说明我所搭建的前端与后端CI/CD流程以及为何这么搭建。
提供两种构建方式,一种是代码上传自动构建,一种是参数化构建,可选择部署到测试环境仍是线上环境。
自动构建默认部署到测试环境,因为线上环境很重要,自动化构建会有必定风险,因此须要人工干预选择参数进行构建。
后端的全部项目都是放在一个git仓库中,因此就没有作自动构建
接下来就每一步做详细说明,以及可能遇到的坑
当咱们提交新的代码到git仓库,Jenkins就会自动开始构建已经配置好的该项目的任务
在git仓库配置一个Jenkins服务器的webhook地址,当git仓库有变更时会请求这个地址,Jenkins就能收到通知而后开始构建任务
咱们须要先安装一个插件Multibranch Scan Webhook Trigger,可进入插件管理搜索进行安装
进入项目的配置界面,勾选Scan by webhook,填入自定义token,须要确保token的惟一性,不会与其它项目的冲突
过滤分支
这是一个多分支流水线,Jenkins默认会检出全部包含Jenkinsfile的分支,若是配置了webhook,就会自动触发相应分支的构建任务;有时候咱们只想master发生变化后才去构建任务,这时就用到了过滤分支的配置,进入项目配置,在分支源git
项找到add
按钮并点击
选择根据名称过滤(支持通配符)
,或者你能够选择根据名称过滤(支持正则表达式)
,效果同样,只是过滤格式不太同样,我这里在相应的地方填入master
,即只检索master
分支,这样就达到咱们想要的效果了。
进入远端仓库(我这里是Gitte),点击Webhooks,接着点击添加 WebHook
填入URL,IP地址为Jenkins部署的服务器,token为咱们刚设置的,/multibranch-webhook-trigger/invoke
是固定地址,点击添加
会自动发起一个请求,即咱们刚填写的,如相应以下则表示配置成功,相应的构建任务也会自动执行
使用了yarn
进行安装依赖及打包,须要先配置nodejs环境
nodejs
进行安装 nodejs-版本号
,该项目用的是yarn
,因此在Global npm package to install
,加入了配置项,构建的时候会自动安装yarn
,若是是npm能够忽略该配置 pipeline {
stage('打包') {
steps {
// 执行环境,nodejs-12.16是咱们刚配置的别名,还有一种方式是在agent中配置执行环境,在tools中配置使用的包,感兴趣的能够自行研究
nodejs('nodejs-12.16') {
echo '开始安装依赖'
sh 'yarn'
echo '开始打包'
sh 'yarn run build'
}
}
}
}
复制代码
pipeline {
tools {
maven 'Maven3.6.3'
}
parameters {
// 提供要部署的服务器选项
choice(
description: '你须要选择哪一个环境进行部署 ?',
name: 'env',
choices: ['测试环境', '线上环境']
)
// 提供构建的模块选项
choice(
description: '你须要选择哪一个模块进行构建 ?',
name: 'moduleName',
choices: ['kuaimen-contract', 'kuaimen-core', 'kuaimen-eureka-server', 'kuaimen-manage', 'kuaimen-member', 'kuaimen-order', 'kuaimen-shop', 'tiemuzhen-manage']
)
booleanParam(name: 'isAll', defaultValue: false, description: '是否须要全量(包含clean && build)')
string(name: 'update', defaultValue: '', description: '本次更新内容?')
}
stages {
stage('全量清除旧数据...') {
when {
expression {
params.isAll == true
}
}
steps {
echo "开始全量清除"
sh "mvn package clean -Dmaven.test.skip=true"
}
}
stage('全量打包应用') {
when {
expression {
params.isAll == true
}
}
steps {
echo "开始全量打包"
sh "mvn package -Dmaven.test.skip=true"
echo '打包成功'
}
}
stage('清除旧数据...') {
when {
expression {
params.isAll == false
}
}
steps {
echo "开始清除${params.moduleName}模块"
sh "cd ${params.moduleName} && mvn package clean -Dmaven.test.skip=true"
}
}
stage('打包应用') {
when {
expression {
params.isAll == false
}
}
steps {
echo "开始打包${params.moduleName}模块"
sh "cd ${params.moduleName} && mvn package -Dmaven.test.skip=true"
echo '打包成功'
}
}
}
}
复制代码
parameters
parameters
中主要是提供参数化构建的选项,在其它地方能够经过"${params.isAll}"
这种形式拿到用户的交互信息,配置后效果以下:
when>expression
表达式中的参数若是未true
,则执行,反之跳过该stage
mvn
在系统配置中默认就已经提供了该环境,进入系统全局工具配置,添加以下配置(相似nodejs)
这种方式引用
tools {
maven 'Maven3.6.3'
}
复制代码
pipeline {
agent any
environment {
HOST_TEST = 'root@121.41.16.183'
HOST_ONLINE = 'jenkins@39.101.219.110'
SOURCE_DIR = 'dist/*'
TARGET_DIR = '/data/www/kuaimen-yunying-front'
}
stage('部署') {
when {
expression {
params.env == '测试环境'
}
}
steps {
sshagent(credentials: ['km-test2']) {
sh "ssh -o StrictHostKeyChecking=no ${HOST_TEST} uname -a"
// 将打包好的文件上传到服务器
sh "scp -r ${SOURCE_DIR} ${HOST_TEST}:${TARGET_DIR}"
sh 'echo "部署成功~"'
}
}
}
stage('发布') {
when {
expression {
params.env == '线上环境'
}
}
steps {
sshagent(credentials: ['km-online']) {
sh "ssh -o StrictHostKeyChecking=no ${HOST_ONLINE} uname -a"
sh "scp -r ${SOURCE_DIR} ${HOST_ONLINE}:${TARGET_DIR}"
sh 'echo "发布成功~"'
}
}
}
}
}
复制代码
environment
定了全局变量,在其它地方可直接引用
sshagent
用于链接服务器,须要先安装插件ssh-agent,credentials
是链接服务器的凭据ID,咱们在一开始已经教你们建立好了
pipeline {
agent any
environment {
HOST_TEST = 'root@121.41.16.183'
TARGET_DIR = '/data/www/kuaimen-auto'
HOST_ONLINE = 'jenkins@39.101.219.110'
}
tools {
maven 'Maven3.6.3'
}
stage('部署应用') {
when {
expression {
params.env == '测试环境'
}
}
steps {
echo "开始部署${params.moduleName}模块"
sshagent(credentials: ['km-test2']) {
sh "ssh -v -o StrictHostKeyChecking=no ${HOST_TEST} uname -a"
// 将打包后的文件上传到服务器
sh "cd ${params.moduleName}/target && scp *.jar ${HOST_TEST}:${TARGET_DIR}/${params.moduleName}"
// 匹配出该Java进程而后杀掉
sh "ssh -o StrictHostKeyChecking=no ${HOST_TEST} \"uname;ps -ef | egrep ${params.moduleName}.*.jar | egrep -v grep | awk '{print \\\$2}' | xargs -r sudo kill -9\""
// 启动该进程
sh "ssh -o StrictHostKeyChecking=no ${HOST_TEST} \"nohup /data/apps/jdk1.8/bin/java -jar ${TARGET_DIR}/${params.moduleName}/${params.moduleName}-0.0.1-SNAPSHOT.jar --spring.profiles.active=test >/dev/null 2>&1 &\""
sh 'echo "部署成功~"'
}
echo '部署成功'
}
}
stage('发布应用') {
when {
expression {
params.env == '线上环境'
}
}
steps {
echo "开始发布${params.moduleName}模块"
sshagent(credentials: ['km-online']) {
sh "ssh -v -o StrictHostKeyChecking=no ${HOST_ONLINE} uname -a"
sh "cd ${params.moduleName}/target && scp *.jar ${HOST_ONLINE}:${TARGET_DIR}/${params.moduleName}"
sh "ssh -o StrictHostKeyChecking=no ${HOST_ONLINE} \"uname;ps -ef | egrep ${params.moduleName}.*.jar | egrep -v grep | awk '{print \\\$2}' | xargs -r sudo kill -9\""
sh "ssh -o StrictHostKeyChecking=no ${HOST_ONLINE} \"nohup /data/apps/jdk1.8/bin/java -jar ${TARGET_DIR}/${params.moduleName}/${params.moduleName}-0.0.1-SNAPSHOT.jar --spring.profiles.active=dev >/dev/null 2>&1 &\""
sh 'echo "发布成功~"'
}
echo '发布成功'
}
}
}
复制代码
须要注意的是,在匹配进程的那段shell中的awk '{print \\\$2}'
,$
符号须要用三个反斜线进行转义,否则会没法执行成功,这里曾卡了很久,但愿大家别踩坑了
咱们这里使用钉钉发起通知,主要原理是在钉钉群建立一个webhook机器人,而后把webhook的地址填入DingTalk插件的配置项,最后在JenkinsFile中进行以下配置便可:
pipeline {
stage('获取git commit message') {
steps {
script {
// 将获取到的git commit赋值给GIT_COMMIT_MSG
env.GIT_COMMIT_MSG = sh (script: 'git log -1 --pretty=%B ${GIT_COMMIT}', returnStdout: true).trim()
}
}
}
post {
success {
dingtalk (
robot: '77d4c82d-3794-4583-bc7f-556902fee6b0',
type: 'MARKDOWN',
atAll: true,
title: '你有新的消息,请注意查收',
text:[
'# 运营管理系统发布通知',
'---',
'#### **所属:后端**',
"#### **构建任务:${env.BUILD_DISPLAY_NAME}**",
"#### **本次更新内容:${params.update}**",
"#### **部署环境:${params.env}**",
'#### **构建结果:成功**'
]
)
}
}
}
复制代码
GIT_COMMIT
这个是Jenkins系统全局变量,得到的是git commit ID,而后经过它拿到具体的提交信息,并赋值给env.GIT_COMMIT_MSG
,全局变量能够经过这种方式访问env.BUILD_DISPLAY_NAME
robot为机器人ID,在系统配置中添加以下配置项
webhook在建立完机器人的时候可以拿到
点击群设置 -> 智能群助手
选择自定义机器人,配置完成后就能够看到webhook的地址了
通过上面的配置,咱们已经完成了前端、后台的自动化构建配置,接下来再说明一下分别是如何触发构建的
Build with Parameters
,选择相应的参数进行构建,线上环境必须经过这种方式,保证必定的安全性 后端只配置了参数化构建,缘由前面已经说了,选择要构建的环境、模块进行构建
点击打开Blue Ocean
选择要构建的分支
弹出参数选择,这和Build with Parameters
差很少,可是界面更好看,更清爽了,选择后点击Run
便可开始构建
构建结果,很直观,根据颜色能够判断构建成功了,若是失败了是红色
在Blue Ocean的活动栏能够看到历史构建,点击以下位置的按钮能够从新构建该历史项,即回滚
到这里终于告一段落了,虽然折腾了很多时间,可是将公司的工程化流程完善了仍是有点小小的成就感的,之后能够愉快得写代码了,自动化的事情就交给Jenkins了。
将这个记录下来一个是方便之后随时查阅,还有一个是但愿能让朋友们少踩些坑,完~
BlueOcean实战多分支pipeline构建(Jenkins)
Complete Jenkins Pipeline Tutorial for Beginners [FREE]