• Jenkins pipeline 自动部署实践


    最近为公司做Jenkins部署改造,本文为我这几天的研究结果

    之前断断续续学过Jenkins,但从未成功过,原因在于他们都是简单的使用普通项目,我怎么就看不懂,各种配置之间没有逻辑让我有点晕

    此次机会,我重新翻阅了一遍《Jenkins2.x实践指南》,不得不说,带着问题的看书让我效率非常高,一个小时左右我就明白该怎么做了

    这次我使用的是pipeline方式实现,因为这种方式更具逻辑性,前后连贯,容易理解。不过我们得考虑到团队内其他成员的知识储备,所以pipeline文件内的我加满了必要的注释,帮助其他人员快速理解学习

    以下是我编写的pipeline脚本,基于其他项目的改造,各位根据需要进行自己开发,请不要直接使用(每个项目有每个项目的特性,需要结合自己的情况编写),明白我的意思即可。

    要想成功运行SSH,需要安装插件 

    插件名称: SSH Pipeline Steps
    使用说明: https://github.com/jenkinsci/ssh-steps-plugin#pipeline-steps

    1. // 代表整条流水线
    2. pipeline {
    3. agent any
    4. parameters {
    5. gitParameter(name: 'branch', defaultValue: 'origin/master', type: 'PT_BRANCH')
    6. choice(name: '请选择操作', choices: [ "拉取代码-编译-打包-运行", "重启", "启动", "停止" ])
    7. }
    8. // 设置环境变量
    9. environment {
    10. ACTION = "${params.请选择操作}"
    11. // ========== 远程服务器信息 ================
    12. REMOTE_HOST = "${REMOTE_LOCAL_HOST_27}"
    13. REMOTE_USER = "${REMOTE_LOCAL_USER_27}"
    14. REMOTE_PASSWORD = "${REMOTE_LOCAL_PASSWORD_27}"
    15. // 需要传输的文件路径
    16. FILE_NAME = ""
    17. SOURCE_FILE_PATH = ""
    18. // 传输到目标服务器的位置
    19. TARGET_PATH = ""
    20. // jar包备份路径
    21. BACKUP_PATH = ""
    22. // 运行,启动位置
    23. RUN_PATH = ""
    24. }
    25. // pipeline选项
    26. options {
    27. // 保存最近历史构建记录数量
    28. buildDiscarder(logRotator(numToKeepStr: '10'))
    29. // 禁止pipeline同时执行
    30. disableConcurrentBuilds()
    31. // 失败时重试总次数
    32. // retry(2)
    33. // pipeline执行时间过长,超过timeout时间就停止掉pipeline
    34. timeout(time: 3, unit: 'MINUTES')
    35. }
    36. // 阶段容器
    37. stages {
    38. // 阶段:重新构建
    39. stage('build and run') {
    40. when {
    41. environment name: 'ACTION', value: '拉取代码-编译-打包-运行'
    42. }
    43. steps {
    44. script {
    45. echo "==================== 开始重新构建项目 ========================"
    46. echo "====================== 项目打包 ============================"
    47. sh "mvn clean package -DskipTests -Dmaven.compile.fork=true -U -B -pl motionplus-visual/motionplus-codegen -am -amd"
    48. echo "================= 将jar包发送到远程服务器 ====================="
    49. def remote = [:]
    50. remote.name = "${REMOTE_HOST}"
    51. remote.host = "${REMOTE_HOST}"
    52. remote.user = "${REMOTE_USER}"
    53. remote.password = "${REMOTE_PASSWORD}"
    54. remote.allowAnyHosts = true
    55. sshPut remote: remote, from: "${SOURCE_FILE_PATH}" , into: "${TARGET_PATH}"
    56. echo "备份"
    57. sshCommand remote: remote, command: "cp ${RUN_PATH}${FILE_NAME}.jar ${BACKUP_PATH}${FILE_NAME}-" + '$(date +%Y-%m-%d-%H%M%S).jar'
    58. echo "关闭"
    59. try {
    60. sshCommand remote: remote, command: "jps -l | grep ${FILE_NAME}.jar | cut -d' ' -f1 | xargs kill"
    61. } catch(err) {
    62. echo "关闭失败:${FILE_NAME}没有启动"
    63. }
    64. echo "替换新包"
    65. sshCommand remote: remote, command: "cp ${TARGET_PATH}${FILE_NAME}.jar ${RUN_PATH}"
    66. // 睡眠5秒,等待应用停止完毕再启动
    67. sleep(5)
    68. echo "启动"
    69. sshCommand remote: remote, command: "java -javaagent:/usr/local/skywalking/agent/skywalking-agent.jar -Dskywalking.agent.service_name=${FILE_NAME} -Dskywalking.collector.backend_service=127.0.0.1:11800 -jar ${RUN_PATH}${FILE_NAME}.jar --spring.profiles.active=test >" + '/logs/${FILE_NAME}/log-$(date +%Y%m%d).txt 2>&1 &'
    70. }
    71. }
    72. }
    73. // 阶段:启动
    74. stage('start') {
    75. when {
    76. environment name: 'ACTION', value: '启动'
    77. }
    78. steps {
    79. script {
    80. echo "====================== 启动项目 =========================="
    81. def remote = [:]
    82. remote.name = "${REMOTE_HOST}"
    83. remote.host = "${REMOTE_HOST}"
    84. remote.user = "${REMOTE_USER}"
    85. remote.password = "${REMOTE_PASSWORD}"
    86. remote.allowAnyHosts = true
    87. sshCommand remote: remote, command: "java -javaagent:/usr/local/skywalking/agent/skywalking-agent.jar -Dskywalking.agent.service_name=${FILE_NAME} -Dskywalking.collector.backend_service=127.0.0.1:11800 -jar ${RUN_PATH}${FILE_NAME}.jar --spring.profiles.active=test >" + '/logs/${FILE_NAME}/log-$(date +%Y%m%d).txt 2>&1 &'
    88. }
    89. }
    90. }
    91. // 阶段:停止
    92. stage('stop') {
    93. when {
    94. environment name: 'ACTION', value: '停止'
    95. }
    96. steps {
    97. script {
    98. echo "====================== 停止项目 =========================="
    99. def remote = [:]
    100. remote.name = "${REMOTE_HOST}"
    101. remote.host = "${REMOTE_HOST}"
    102. remote.user = "${REMOTE_USER}"
    103. remote.password = "${REMOTE_PASSWORD}"
    104. remote.allowAnyHosts = true
    105. try {
    106. sshCommand remote: remote, command: "jps -l | grep ${FILE_NAME}.jar | cut -d' ' -f1 | xargs kill"
    107. } catch(err) {
    108. echo "关闭失败:${FILE_NAME}没有启动"
    109. }
    110. }
    111. }
    112. }
    113. // 阶段:重启
    114. stage('restart') {
    115. when {
    116. environment name: 'ACTION', value: '重启'
    117. }
    118. steps {
    119. script {
    120. echo "====================== 重启项目 =========================="
    121. echo "关闭"
    122. def remote = [:]
    123. remote.name = "${REMOTE_HOST}"
    124. remote.host = "${REMOTE_HOST}"
    125. remote.user = "${REMOTE_USER}"
    126. remote.password = "${REMOTE_PASSWORD}"
    127. remote.allowAnyHosts = true
    128. try {
    129. sshCommand remote: remote, command: "jps -l | grep ${FILE_NAME}.jar | cut -d' ' -f1 | xargs kill"
    130. } catch(err) {
    131. echo "关闭失败:${FILE_NAME}没有启动"
    132. }
    133. // 睡眠5秒,等待应用停止完毕再启动
    134. sleep(5)
    135. sshCommand remote: remote, command: "java -javaagent:/usr/local/skywalking/agent/skywalking-agent.jar -Dskywalking.agent.service_name=${FILE_NAME} -Dskywalking.collector.backend_service=127.0.0.1:11800 -jar ${RUN_PATH}${FILE_NAME}.jar --spring.profiles.active=test >" + '/logs/${FILE_NAME}/log-$(date +%Y%m%d).txt 2>&1 &'
    136. }
    137. }
    138. }
    139. }
    140. // 整个pipeline完成后
    141. post {
    142. // 状态为失败执行
    143. failure {
    144. echo "====================== 运行失败 =========================="
    145. }
    146. // 状态为成功执行
    147. success {
    148. echo "====================== 运行成功 =========================="
    149. // mail subject: '关于xxx日的构建反馈-成功', body: '构建成功了', from: 'xxx@163.com',, to: 'to@163.com' // 可以邮件通知或者webhook
    150. }
    151. }
    152. }

    由于我不怎么会groovy,所以代码有大量冗余,如果各位能够告诉我怎么抽出来,不胜感激。

    另外我也将groovy书籍加入了我的书架,偶尔翻翻,由于是英文的,学起来还是有点吃力,不过当初也看在可以练习阅读能力倒也挺好

    没有花太多时间在这个上面,是因为这也不是我的主业,慢慢优化吧

    这是第二个的

    这个项目的特性就是用SSH做的,还是非MAVEN项目,所以使用了ANT打包,然后使用Tomcat运行

    1. // 代表整条流水线
    2. pipeline {
    3. agent any
    4. parameters {
    5. choice(name: 'branch', choices: ['master', 'dev', 'test'], description: '请选择构建分支')
    6. }
    7. // 设置环境变量
    8. environment {
    9. // 安装Jenkins的操作系统类正在停止tomcat型:可选值 windows / linux
    10. OS = "linux"
    11. // 本机:ant自动生成打包配置文件位正在停止tomcat置(不带文件后缀)
    12. ANT_GENERATE_BUILD_PATH = "/usr/lib/jenkins/generate-build"
    13. // 本机:ant位置
    14. ANT_HOME = "/usr/lib/jenkins/apache-ant-1.9.16"
    15. // 本机:tomcat home目录路径
    16. TOMCAT_HOME = "/usr/lib/jenkins/apache-tomcat-8.5.75"
    17. // 项目部署类型 local(本地) remote(远程服务器)
    18. DEPLOY_TYPE = "remote"
    19. /// ========== 如果部署到远程服务器 就填写下面的内容 ============
    20. // windows / linux
    21. REMOTE_OS = "linux"
    22. REMOTE_HOST = ""
    23. REMOTE_USER = ""
    24. REMOTE_PASSWORD = ""
    25. // windows 路径示例:/D:/developer/apache-tomcat-8.5.75 注意前面要加个/
    26. REMOTE_TOMCAT_HOME = ""
    27. // 如果部署的是远程windows,就填写下面tomcat服务名称
    28. REMOTE_WINDOWS_TOMCAT_SERVICE_NAME = "Tomcat"
    29. }
    30. // pipeline选项
    31. options {
    32. // 保存最近历史构建记录数量
    33. buildDiscarder(logRotator(numToKeepStr: '10'))
    34. // 禁止pipeline同时执行
    35. disableConcurrentBuilds()
    36. // 失败时重试总次数
    37. // retry(2)
    38. // pipeline执行时间过长,超过timeout时间就停止掉pipeline
    39. timeout(time: 3, unit: 'MINUTES')
    40. }
    41. // 阶段容器
    42. stages {
    43. // 流水线的阶段
    44. // 1.拉取代码
    45. stage("check out"){
    46. // 步骤
    47. steps {
    48. echo "========================== 拉取代码 ============================="
    49. git branch: 'master', credentialsId: '', url: ''
    50. echo "======================== 拉取代码完毕 ============================="
    51. }
    52. }
    53. // 2.打包项目(本机windows环境打包) |||||||||||未测试
    54. stage('build-windows') {
    55. // 当条件满足了才执行当前 stage
    56. when {
    57. // 环境变量的OS变量需要 等于 windows
    58. environment name: 'OS', value: 'windows'
    59. }
    60. steps {
    61. echo "====================== Windows下开始打包项目 ============================"
    62. echo "开始生成ant打包配置文件"
    63. // 生成配置文件
    64. // 第一个参数tomcat安装目录:将目录传入ant build.xml里,到时候将打包出来的包复制到tomcat/webapp下
    65. // 第一个参数项目名称:打包出来的文件名
    66. // 第三个参数源码路径:将生成的配置文件放到源码根目录下
    67. bat "${ANT_GENERATE_BUILD_PATH}.bat ${TOMCAT_HOME} ${JOB_NAME} ${WORKSPACE}"
    68. echo "开始执行ant打包命令."
    69. // 开始打包
    70. bat "${ANT_HOME}/bin/ant -buildfile ${WORKSPACE}/build.xml"
    71. echo "=========================== 项目打包完毕 =============================="
    72. }
    73. }
    74. // 2.打包项目(本机linux环境打包)
    75. stage('build-linux') {
    76. when {
    77. environment name: 'OS', value: 'linux'
    78. }
    79. steps {
    80. echo "====================== Linux下开始打包项目 ============================="
    81. echo "开始生成ant打包配置文件"
    82. sh "JENKINS_NODE_COOKIE=dontKillMe sh ${ANT_GENERATE_BUILD_PATH}.sh ${TOMCAT_HOME} ${JOB_NAME} ${WORKSPACE}"
    83. echo "开始执行ant打包命令"
    84. sh "JENKINS_NODE_COOKIE=dontKillMe sh ${ANT_HOME}/bin/ant -buildfile ${WORKSPACE}/build.xml"
    85. echo "=========================== 项目打包完毕 =============================="
    86. }
    87. }
    88. // 3.启动项目:远程windows上启动
    89. stage('run-remote-windows') {
    90. when {
    91. // 当部署类型是远程服务器 并且 远程服务器是windows才执行
    92. environment name: 'DEPLOY_TYPE', value: 'remote'
    93. environment name: 'REMOTE_OS', value: 'windows'
    94. }
    95. steps {
    96. script {
    97. echo "=============== 部署到远程服务器[Windows] ============================="
    98. def remote = [:]
    99. remote.name = "remote-windows"
    100. remote.host = "${REMOTE_HOST}"
    101. remote.user = "${REMOTE_USER}"
    102. remote.password = "${REMOTE_PASSWORD}"
    103. remote.allowAnyHosts = true
    104. try {
    105. sshCommand remote: remote, command: "net stop ${REMOTE_WINDOWS_TOMCAT_SERVICE_NAME}"
    106. } catch(err) {
    107. echo "停止失败:Tomcat没有启动"
    108. }
    109. sshPut remote: remote, from: "${WORKSPACE}/target/war/${JOB_NAME}.war" , into: "${REMOTE_TOMCAT_HOME}/webapps/"
    110. echo "====================== 打包文件上传成功 ============================="
    111. sshCommand remote: remote, command: "net start ${REMOTE_WINDOWS_TOMCAT_SERVICE_NAME}"
    112. echo "====================== Tomcat启动成功 ============================="
    113. }
    114. }
    115. }
    116. // 3.启动项目:远程linux上启动
    117. stage('run-remote-linux') {
    118. when {
    119. // 当部署类型是远程服务器 并且 远程服务器是linux才执行
    120. environment name: 'DEPLOY_TYPE', value: 'remote'
    121. environment name: 'REMOTE_OS', value: 'linux'
    122. }
    123. steps {
    124. script {
    125. echo "=============== 部署到远程服务器[Linux] ============================="
    126. def remote = [:]
    127. remote.name = 'remote-linux'
    128. remote.host = "${REMOTE_HOST}"
    129. remote.user = "${REMOTE_USER}"
    130. remote.password = "${REMOTE_PASSWORD}"
    131. remote.allowAnyHosts = true
    132. try {
    133. sshCommand remote: remote, command: "sh ${REMOTE_TOMCAT_HOME}/bin/shutdown.sh"
    134. } catch(err) {
    135. echo "停止失败:Tomcat没有启动"
    136. }
    137. sshPut remote: remote, from: "${WORKSPACE}/target/war/${JOB_NAME}.war", into: "${REMOTE_TOMCAT_HOME}/webapps/"
    138. echo "====================== 打包文件上传成功 ============================="
    139. sshCommand remote: remote, command: "sh ${REMOTE_TOMCAT_HOME}/bin/startup.sh"
    140. echo "====================== Tomcat启动成功 ============================="
    141. }
    142. }
    143. }
    144. // 3.启动项目:本地windows上启动 |||||||||||未测试
    145. stage('run-local-windows') {
    146. when {
    147. // 环境变量的OS变量需要 等于 windows
    148. environment name: 'DEPLOY_TYPE', value: 'local'
    149. environment name: 'OS', value: 'windows'
    150. }
    151. steps {
    152. echo "============ 将打包文件复制到Tomcat Webapps下 ==============="
    153. sh "cp ${WORKSPACE}/target/war/${JOB_NAME}.war ${TOMCAT_HOME}/webapps/"
    154. echo "===================== 开始启动项目 ========================="
    155. echo "开始运行项目"
    156. echo "正在停止tomcat"
    157. bat '${TOMCAT_HOME}/bin/shutdown.bat'
    158. echo "停止成功"
    159. echo "正在启动tomcat"
    160. bat '${TOMCAT_HOME}/bin/startup.bat'
    161. echo "启动成功"
    162. echo "====================== 启动成功 =========================="
    163. }
    164. }
    165. // 3.启动项目:本地linux上启动
    166. stage('run-local-linux') {
    167. when {
    168. environment name: 'DEPLOY_TYPE', value: 'local'
    169. environment name: 'OS', value: 'linux'
    170. }
    171. steps {
    172. script {
    173. echo "============ 将打包文件复制到Tomcat Webapps下 ==============="
    174. sh "cp ${WORKSPACE}/target/war/${JOB_NAME}.war ${TOMCAT_HOME}/webapps/"
    175. echo "===================== 开始启动项目 ========================="
    176. echo "开始运行项目"
    177. echo "正在停止tomcat"
    178. try {
    179. sh 'JENKINS_NODE_COOKIE=dontKillMe sh ${TOMCAT_HOME}/bin/shutdown.sh'
    180. } catch (err) {
    181. echo "停止失败:Tomcat没有启动"
    182. }
    183. echo "正在启动tomcat"
    184. sh 'JENKINS_NODE_COOKIE=dontKillMe sh ${TOMCAT_HOME}/bin/startup.sh'
    185. echo "启动成功"
    186. echo "====================== 启动成功 =========================="
    187. }
    188. }
    189. }
    190. }
    191. // 整个pipeline完成后
    192. post {
    193. // 状态为失败执行
    194. failure {
    195. echo "====================== 部署失败 =========================="
    196. }
    197. // 状态为成功执行
    198. success {
    199. echo "====================== 部署成功 =========================="
    200. // mail subject: '关于xxx日的构建反馈-成功', body: '构建成功了', from: 'xxx@163.com',, to: 'to@163.com' // 可以邮件通知或者webhook
    201. }
    202. }
    203. }

    说几个注意点

    pipeline的${} 变量必须写在 双引号" " 字符串里面才能被解析

    pipeline里运行tomcat会启动不起来 需要前面加 JENKINS_NODE_COOKIE=dontKillMe 具体看上面代码

  • 相关阅读:
    双版本数据加载的系统设计
    第十九节——vue内置组件
    C++内存管理
    腾讯云服务器CVM和轻量应用服务器区别全方位对比
    图像处理之图像的几何变换
    关于JavaScript 异步方案 async/await
    MacOs 删除第三方软件
    架构:微服务网关(SIA-Gateway)简介
    天津工业大学计算机考研资料汇总
    dubbo之配置文件
  • 原文地址:https://blog.csdn.net/weixin_42195284/article/details/125605856