你好,我是悟空。
本文目录如下:
图片
这次我们要接着上面的话题聊下如何通过通过编写代码的方式实现自动化部署 Java 项目。
而用代码方式其实就是使用 Jenkins 强大的 pipeline 功能来实现的。
通过本篇你可以学习到如下内容:
要了解什么是Pipeline,就必须知道什么是流水线。类似于食品工厂包装食品,食品被放到传送带上,经过一系列操作后,包装完成,这种工程就是流水线工程。
在自动化部署中,开发完成的代码经过一系列顺序操作后被部署完成,这个就是部署过程中的流水线,我们通常称作 pipeline。
之前我们的部署步骤都是通过在 Jenkins 的 UI 界面上配置出来的,但其实 Jenkisn 2.x 版本已经可以支持编写代码的方式来启动自动化部署了,通过“代码”来描述部署流水线。
Jenkins pipeline其实就是基于一种声明式语言,用于描述整条流水线是如何进行的。流水线的内容包括执行编译、打包、测试、输出测试报告等步骤。
Pipeline 通过代码来实现,其实就具有很多代码的优势了,比如:
当然 pipeline 的缺点也是有的:
在之前的文章中,我是通过创建一个自由风格的项目来实现自动化部署,其实还可以通过创建一个Pipeline 来实现,如下图所示:
创建 Pipeline 任务
然后就可以在配置流水线的地方编写代码了。如下图所示:
编写流水线代码
Pipeline 基础结构如下所示:
pipeline{//指定运行此流水线的节点agent any//流水线的阶段stages{ //阶段1 获取代码 stage("CheckOut") { steps { script { echo "获取代码" } } }}
以上每一个部分都不能少,否则 Jenkins 会报错。
Jenkins 承担的角色如下图所示:
图片
Jenkins 打包部署原理图
我们项目是 Java 项目,所以通过流水线来部署项目的步骤如下图所示:
流水线部署步骤
Pipeline 的强大之处是可以支持传参以及获取参数,为了让用户可以选择获取不同的分支代码,我在 pipeline 代码中配置了一个参数:获取指定的 Gitlab 分支代码。
在 流水线代码中添加 parameters 节点,指定类型为 string,配置相关的属性。
pipeline { parameters { string ( name: 'GIT_BRANCH', // 参数名,后面 steps 中会用到 defaultValue: 'dev-01.30', // 默认值,会显示在界面上,用户可以改。 description: '请选择部署的分支' // 说明 ) } // 其他代码 ...}
通过参数部分,定义了一个名为GIT_BRANCH的参数,它允许用户在构建过程中选择要构建的分支。默认情况下,分支被设置为dev-01.30,用户可以选择不同的分支。
在脚本中,这个参数可以通过params.GIT_BRANCH 获取到。
保存配置后,需要先运行一次这个项目才能看到参数配置。如下图所示:右边就是参数配置。
接着我们还需要定义一些常用的环境变量信息,比如 Gitlab 的仓库地址,代码如下所示:
pipeline { parameters { // 配置信息 ... } // 环境变量:定义 GitLab 仓库的 URL 和分支 environment { GIT_URL = 'https://xxx/xxx.git' } // 其他代码 ...}
environment 节点为环境变量信息,GIT_URL 变量代表 Gitlab 的仓库地址。在脚本中,这个变量可以通过${GIT_URL}使用。
接下来我们来看下如何在 pipeline 中添加一个获取 gitlab 仓库代码的步骤。
pipeline { agent any parameters { string( name: 'GIT_BRANCH', defaultValue: 'dev-01.30', description: '请选择部署的分支') } // 定义 GitLab 仓库的 URL 和分支 environment { GIT_URL = 'https://XXX/xxx.git' } stages { stage('获取最新代码') { steps { script { // 使用 params 对象获取参数值 def branchName = params.GIT_BRANCH echo "Building branch: ${branchName}" // 使用 git 插件检出仓库的特定分支 checkout([ $class: 'GitSCM', branches: [[name: "${branchName}"]], doGenerateSubmoduleConfigurations: false, extensions: [], submoduleCfg: [], userRemoteConfigs: [[ credentialsId: '211583e9-8ee1-4fa2-9edd-d43a963de8f2', // 在 Jenkins 凭据中定义的 GitLab 凭据 ID url: "${GIT_URL}" ]] ]) } } } }}
注意:获取分支的凭证是一个 ID,这个凭证信息是在 Jenkins 系统配置中加的。可以按照如下页面路径添加凭证:Dashboard->Manage Jenkins->Credentials->System->Add domain。也可以通过如下 URL 访问
http://<你的服务器 IP>:8080/manage/credentials/store/system/
图片
我们可以运行一下这个项目来测试 pipeline 代码。运行结果如下图所示,可以看到右侧的阶段视图,整体耗时和每个步骤的耗时,以及每个步骤的成功与否都显示出来了,非常直观。
图片
本篇主要讲解的是部署 Java 项目,所以编译项目也是采用 Maven 打包的方式。在 pipeline 脚本中执行 mvn 打包命令即可。
stage('编译代码') { steps { script { echo "--------------- 步骤:开始编译 --------------- " bat 'mvn clean package' echo "--------------- 步骤:编译完成 --------------- " } } }
核心代码:bat 'mvn clean package'
因为我的 Jenkins 是部署在 Windows 机器上,所以执行命令用的 windows 自带的 bat 工具来执行的。
关于 maven 工具的配置可以看之前写的第二篇内容:
喝杯咖啡,一键部署完成!(建议收藏)
编译完成后,就可以将 Jenkins 工作空间的 JAR 包上传到服务器的 temp 目录下。
如果你想部署指定的某些微服务,可以通过传参的方式来上传和更新指定的微服务。原理图如下所示:
图片
为了实现可以选择部署哪些微服务,需要安装一个多选插件:Extended Choice Parameter。
图片
Extended Choice Parameter 插件
接下来是编写的参数配置代码:
parameters { extendedChoice ( defaultValue: 'All', description: '需要部署的微服务', multiSelectDelimiter: ',', name: 'SERVICE_NAME', quoteValue: false, saveJSONParameterToFile: false, type: 'PT_CHECKBOX', value:'All, passjava-account, passjava-file', visibleItemCount: 10 )}
配置保存后并运行一次后,就可以在 pipeline 中看到配置选项:
图片
实现的效果如下图右下角所示,可以支持多选。
图片
上传需要使用 sshPublisher 插件,在第二篇文章中已介绍了。
下面上传代码的作用是遍历 filesToCopy 列表中的文件,然后通过 SSH 将这些文件上传到远程服务器的指定目录中。
filesToCopy.eachWithIndex { file, index -> echo "开始上传 JAR 包 ${file} ..." sshPublisher( failOnError: true, publishers: [ sshPublisherDesc( configName: "${SSH_URL}", verbose: true, transfers: [ sshTransfer( execCommand: '', execTimeout: 120000, flatten: false, makeEmptyDirs: false, noDefaultExcludes: false, patternSeparator: '[, ]+', remoteDirectory: 'apps/temp/', remoteDirectorySDF: false, removePrefix: removePrefixs[index], sourceFiles: file ) ] ) ] ) echo "完成上传 JAR 包 ${file}"}
filesToCopy 就是通过用户勾选的服务名转成了对应的本地 JAR 包路径。
switch(service) { case 'passjava-account': filesToCopy.add("passjava-modules/passjava-module-account/passjava-module-account-core/target/passjava-account.jar") removePrefixs.add("passjava-modules/passjava-module-account/passjava-module-account-core/target") break case ... }
备份的思路:逐个处理 serviceNameList 中的服务名称,然后通过 SSH 连接到远程服务器执行备份操作。serviceNameList 就是用户勾选的服务名的集合。原理图如下所示:
备份服务器 JAR 包
核心代码如下:
serviceNameList.each { service -> echo "开始备份微服务 ${service} 包" sshPublisher( failOnError: true, publishers: [ sshPublisherDesc( configName: "${SSH_URL}", verbose: true, transfers: [ sshTransfer( execCommand: "mkdir -p /nfs-data/wukong/apps/bak/${timestamp} && cd /nfs-data/wukong/apps && mv ${service}.jar ./bak/${timestamp}/${service}-${timestamp}.jar" ) ] ) ] )
这段代码的作用是遍历 serviceNameList 列表中的服务名称,然后通过 SSH 连接到远程服务器执行备份操作,将每个服务的 JAR 包移动到指定的备份目录,并根据时间戳进行命名。
更新最新的 JAR 包就是将最新的 JAR 包放到对应的容器映射的目录,后面重启容器的时候,就能用最新的 JAR 包启动了。原理图如下所示:
更新 JAR 包
serviceNameList.eachWithIndex { service, index -> echo "开始更新第 ${index + 1} 个 JAR 包,/nfs-data/wukong/apps/temp/${service}.jar ..." sshPublisher( failOnError: true, publishers: [ sshPublisherDesc( configName: "${SSH_URL}", verbose: true, transfers: [ sshTransfer( execCommand: "cd /nfs-data/wukong/apps && mv -f ./temp/${service}.jar ${service}.jar", execTimeout: 120000 ) ] ) ] ) echo "----- 完成更新 JAR 包 -----"}
这段代码的作用是遍历 serviceNameList 列表中的服务名称,然后通过 SSH 连接到远程服务器执行更新操作,将每个服务在 /nfs-data/wukong/apps/temp/ 目录下的 JAR 包移动到对应的位置,完成更新。
启动服务就是将 docker swarm 管理的服务重启下,原理图如下所示:
图片
后端项目使用 Docker Swarm 部署的,重启服务的命令如下:
sudo docker service update --force <服务名>
我们可以编写远程执行这行命令的代码,pipeline 核心代码如下:
serviceNameList.eachWithIndex { service, index -> echo "开始重启第 ${index + 1} 个微服务,${service} ..." sshPublisher( failOnError: true, publishers: [ sshPublisherDesc( configName: "${SSH_URL}", verbose: true, transfers: [ sshTransfer( execCommand: "sudo docker service update --force ${commands[service]}", execTimeout: 120000 ) ] ) ] ) echo "----- 完成重启微服务 -----"}
这段代码的作用是遍历 serviceNameList 列表中的服务名称,然后通过 SSH 连接到远程服务器执行重启操作,完成微服务的重启。
最后整个执行结果如下图所示:总共耗时 3min41s。
图片
通过本篇的实战内容,我们学习到了通过编写 pipeline 代码来实现部署后端项目。推荐大家都用 pipeline 来部署项目,好处是更加灵活。
另外本篇还没有对 Jenkins pipeline 的版本管理,我们其实可以将 pipeline 代码作为一个文件上传到 Gitlab,然后通过 Jenkins 拉取最新的 jenkins pipeline 文件来执行部署,这样更便于管理 pipeline 文件。
本文链接:http://www.28at.com/showinfo-26-81249-0.html用代码实现流水线部署,像诗一般优雅
声明:本网页内容旨在传播知识,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。邮件:2376512515@qq.com
上一篇: 加速 Rust 编译时间,掌握这个技巧,速度全面提升 30 ~ 40 %
下一篇: 几个祖传代码不遵守就想骂的代码规范