• windows下jenkins通过pipeline来部署和回滚maven、npm项目


    目的

    • 实现后台java的maven部署
    • 实现前端npm的部署

    准备

    • 两台服务器,我这边都是windows的:

      • 服务器A,用于安装jenkins等服务
      • 服务器B,待部署机器
    • Jenkins,除了默认插件外,额外需要手动安装插件:

      • Blue Ocean,更方便的展示进度等
      • Publish Over SSH,用于通过ssh来部署远程服务器
      • DingTalk,钉钉机器人通知插件
    • OpenSSH

    • Git

    • 其他的javamavennpm等工具

    安装软件

    • 服务器A中安装jenkins,由于我这边还是旧的windows server 2012,对docker支持不好,所以直接安装的msi文件,具体安装步骤参考官方文档,安装完成后再安装上述的几个插件。
    • 服务器A安装Git,方便从github等代码工具中远程拉取代码,具体安装步骤可以自行网上搜索,由于我们后期会用到sshtar等工具,所以需要将安装目录\Git\usr\bin此路径加入到windows环境变量中,这样就可以用里面的各种工具了,如果是npm项目,需要在服务器B中也要安装,主要是为了用tar打包命令,如果用其他打包方式也可以不安装。
    • 服务器A安装javamavennpm,最好与开发服务上版本保持一致,并将其加入到windows环境变量中,这样的话jenkins就可以直接使用。
    • 服务器B安装openssh,安装流程查看官方文档:Install Win32 OpenSSH,同样需要将此路径加入环境变量,且需要按照文档开启端口、开机自启动等

    ssh密钥联通

    • 整体的流程就是服务器B相当于服务端,服务器A相当于客户端,我们需要用客户端通过ssh链接到服务端,然后传输部署的文件过去,所以需要在客户端中生成私钥和公钥,公钥会给到服务端中,私钥则还是留在客户端,这样ssh链接时通过私钥和公钥验证通过链接到一起就可以传输文件了。

    • 服务器A生成密钥,需要注意的是jenkinsPublish Over SSH不支持最新的密钥格式,只支持旧的pem格式的,所以需要加一些参数才行,在刚安装的git命令工具中输入ssh-keygen -m PEM -t rsa -b 4096,按照提示一步步执行,生成的会放在~/.ssh文件下:

      xxx_rsa     #私钥
      xxx_rsa.pub #公钥
      
    • 服务器B可以先启动一下openssh服务然后关闭,此时会自动生成C:\Program Data\ssh目录,然后我们配置此目录下的sshd_config文件,改动如下:

      PubkeyAcceptedKeyTypes=+ssh-rsa #由于上方说了用的旧的格式密钥,新版本默认已不支持了,所以这里需要额外配置增加支持
      PubkeyAuthentication yes #原先是注释来着,打开并设置为yes,表示开启密钥验证
      PasswordAuthentication no #原先注释来着,打开并设置为no, 关闭密码验证,否则不安全
      
    • 服务器A生产的公钥放到服务B中,这里需要注意,服务器B的用户是管理员用户,则需要放到C:\ProgramData\ssh\administrators_authorized_keys文件中,如果是普通用户,则需要放到C:\Users\用户名\.ssh\authorized_keys文件中,通过这里我们也可以发现密钥实际上是和用户名没有关系的,放到哪个用户名下,是根据位置来的,如果这个用户有权限访问到这个密钥实际上就是可以用这个用户名来登陆的。

    • 测试联通性,可以在服务器A~/.ssh/config中配置:

      Host b_name #服务器B随便起个名字
        HostName 192.168.0.31 #服务器B的IP地址
        IdentityFile ~/.ssh/xxx_rsa #自身生成的私钥
        User administrator #服务器B的登陆用户名
        Port 22 #没改端口的话默认22
        ServerAliveInterval 60
      

      然后可以ssh b_name来测试是否可以联通

    • jenkinsPublish Over SSH插件配置中并测试联通性,位置Manage Jenkins->Configure System->SSH Servers中:

      点击测试,看是否联通成功,如果出现类似Fail Auth等错误,可以参考此解决方法来解决:Jenkins Publish over ssh authentification failed with private key

    git 密钥联通

    • 同上在服务器A中同上创建私钥和公钥,但是github只支持最新版本的,可以不用加那些参数了,具体参考官方文档:新增 SSH 密钥到 GitHub 帐户 - GitHub Docs
    • 以github为例,在个人主页的Setting->SSH AND GPG keys ->SSH keys中新增,将生成的公钥粘贴到github中的字段中就可以了
    • 和上方一样来测试下联通是否OK,其他gitee等原理基本一样

    maven项目部署

    • 如果不熟悉jinkinspipeline相关的话,请先按照官方文档demo操作一遍:Build a Java app with Maven

    • 官方文档demo中都是用的docker,我这边没有,所以不太一样,而且官方文档没有回滚等操作,所以这边给出参考的Jenkinsfile:

      pipeline {
          agent any //没有用docker
          parameters {//这个是参数化构建
              choice choices: ['deploy', 'rollback'], description: '', name: 'action'
              string description: 'rollback ID (only number)', name: 'version'
          }
          stages {
              stage('Build') {
                  when {//如果是部署
                      expression { params.action == 'deploy' }
                  }
                  steps {//maven打包
                      bat 'mvn -B -DskipTests clean package'//linux下是用sh,windows下则bat
                  }
              }
              stage('Archive') {
                  when {//如果是部署
                      expression { params.action == 'deploy' }
                  }
                  steps {//将打包出来的jar包归档,方便回滚时用到
                      archiveArtifacts artifacts: '自身相关路径/target/*.jar', followSymlinks: false, onlyIfSuccessful: true
                  }
              }
              stage('Rollback') {
                  when {//如果是回滚
                      expression { params.action == 'rollback' }
                  }
                  steps {//回滚就不需要打包了,直接将原先版本的归档复制到打包出来的路径
                      bat 'xcopy /s /f /y "%JENKINS_HOME%\\jobs\\%JOB_NAME%\\builds\\%version%\\archive\\自身相关路径\\target" 自身相关路径\\target'
                  }
              }
              stage('Publish') {
                  steps {//publish over ssh插件相关参数,verbose为true,则jenkins_deploy.bat脚本的执行信息会返回
                      sshPublisher(publishers: [sshPublisherDesc(configName: '刚才设置的ssh的名称', sshRetry: [retries: 3, retryDelay: 5000], transfers: [sshTransfer(cleanRemote: false, excludes: '', execCommand: 'cmd /c E:\\服务器B相关部署路径\jenkins_deploy.bat $BUILD_NUMBER', execTimeout: 240000, flatten: false, makeEmptyDirs: false, noDefaultExcludes: false, patternSeparator: '[, ]+', remoteDirectory: '服务器B相关路径', remoteDirectorySDF: false, removePrefix: '自身相关路径/target', sourceFiles: '自身相关路径/target/*.jar')], usePromotionTimestamp: false, useWorkspaceInPromotion: false, verbose: true)])
                  }
              }
          }
      }
      
    • 上方代码一些注解:

      • 上方的参数化构建归档publish over ssh语法都是可以由可视化界面生成的,随便点开一个job后在左侧有流水线语法这个选项,点开后页面在左侧 Declarative Directive Generator中选择parameters:Parameters可以生成参数化构建片段;而左侧片段生成器archiveArtifacts archive the artifacts用来生成归档片段,sshPublishers: Send build artifacts over SSH则用来生成发布的片段,这些具体的使用,可以参考官方文档也可以自行搜索更详细的用法文章。

      • 参数化构建如果在pipeline中写了后,不需要在界面中再配置,只需要运行一次后会自动从pipeline中获取,下次再构建就发现有参数需要填写了,要想回滚则选择rollback然后输入回滚的构建数字运行则会回滚:

      • 一些全局变量,可以参考官方文档:Using a Jenkinsfile,需要注意的是在linux中可以$JENKINS_HOME,但是在windows中就必须%JENKINS_HOME%这样了,需要注意的是publish over sshjenkins_deploy.bat传递参数的 $BUILD_NUMBER则还是用$才行,用%%不起作用,且执行windows脚本时需要用cmd /c开头。

    • 服务器B端的结构及脚本:

      • 项目结构:

        abc:
        ├─backup
        │    └─test_2022_06_27_203000_3.jar #在服务端也备份一份,格式:名称+日期+构建号+jar
        └─prod
            └─test.jar #生产文件
        
      • jenkins_deploy.bat脚本:

        @echo off
        ::设置utf8编码运行
        chcp 65001
        ::移动到当前目录
        cd /d E:\abc
        ::设置时间变量,需要注意的是utf编码和ansi编码所取时间的位数不一样
        set "Ymd=%date:~3,4%_%date:~8,2%_%date:~11,2%_%time:~0,2%%time:~3,2%%time:~6,2%"
        ::将时间的空格用0补齐;将参数可能携带的引号去掉
        set "param=%1"
        ::%Ymd: =0%是将空格转为0,%param:"=%是将"去掉
        set backup_name=%Ymd: =0%_%param:"=%
        ::将现有的移到backup中
        copy prod\test.jar backup\test_%backup_name%.jar
        echo 'prod中的备份到backup中'
        ::关闭服务
        net stop test
        ::将最新的移动到生产目录中
        move /y test.jar prod\test.jar
        echo '最新的移动到prod中'
        ::开启服务
        net start test
        @echo on
        
    • 上方脚本一些注释:

      • jenkins编码没有做设置,所以要用utf8编码来执行bat脚本,否则在jenkins中的信息是乱码。
      • 时间参数在utf8ansi中取值是不一样的,需要注意.
      • 1%是bat语法中第一个参数,就是上方的$BUILD_NUMBER构建号,但传递过来可能后面带引号,例如2",所以要把"也去掉
      • %Ymd: =0%意思是将其中的空格转为0,%param:"=%意思是将其中的"去掉
      • 需要先将test.jar改成用服务的方式运行,最好也要有优雅关闭,可以参考:spring boot不同版本的优雅关闭(graceful shutdown)和在windows下winsw服务方式运行的配置

    npm项目部署

    • 整体流程和maven一样,同样官方也有参考demo,Build a Node.js and React app with npm,这里只给出参考的文件:

    • Jenkinsfile:

      pipeline {
          agent any
          parameters {
              choice choices: ['deploy', 'rollback'], description: '', name: 'action'
              string description: 'rollback ID (only number)', name: 'version'
          }
          stages {
              stage('Install') {
                  when {
                      expression { params.action == 'deploy' }
                  }
                  steps {//install
                      bat 'npm install --registry https://registry.npm.taobao.org'
                  }
              }
              stage("Build"){
                  when {
                      expression { params.action == 'deploy' }
                  }
                  steps {//build
                      bat 'npm run build'
                  }
              }
              stage("Archive"){
                  when {
                      expression { params.action == 'deploy' }
                  }
                  steps {//先打包成压缩文件,再归档,同时也方便传输
                      bat 'tar -zcvf dist.tar.gz -C dist .'
                      archiveArtifacts artifacts: '*.tar.gz', followSymlinks: false, onlyIfSuccessful: true
                  }
              }
              stage('rollback') {
                  when {
                      expression { params.action == 'rollback' }
                  }
                  steps {//将压缩文件拷贝到正常打包后的位置
                      bat 'copy /y "%JENKINS_HOME%\\jobs\\%JOB_NAME%\\builds\\%version%\\archive\\dist.tar.gz" dist.tar.gz'
                  }
              }
              stage("Publish"){
                  steps {
                      sshPublisher(publishers: [sshPublisherDesc(configName: '刚才设置的ssh的名称', sshRetry: [retries: 3, retryDelay: 5000], transfers: [sshTransfer(cleanRemote: false, excludes: '', execCommand: 'cmd /c E:\\服务器B相关部署路径\\jenkins_deploy.bat $BUILD_NUMBER', execTimeout: 120000, flatten: false, makeEmptyDirs: false, noDefaultExcludes: false, patternSeparator: '[, ]+', remoteDirectory: '服务器B相关部署路径', remoteDirectorySDF: false, removePrefix: '', sourceFiles: 'dist.tar.gz')], usePromotionTimestamp: false, useWorkspaceInPromotion: false, verbose: true)])
                  }
              }
          }
      }
      
    • 服务器B的jenkins_deploy.bat脚本,结构和maven项目差不多。

      • 项目结构:

        abc:
        ├─backup
        │    └─test_2022_06_27_203000_3.tar.gz #在服务端也备份一份,格式:名称+日期+构建号+tar.gz
        └─prod
            ├─static
            └─index.html
        
      • jenkins_deploy.bat脚本:

        @echo off
        ::设置utf8编码运行
        chcp 65001
        ::移动到当前目录
        cd /d E:\abc
        ::设置时间变量,需要注意的是utf编码和ansi编码所取时间的位数不一样
        set "Ymd=%date:~3,4%_%date:~8,2%_%date:~11,2%_%time:~0,2%%time:~3,2%%time:~6,2%"
        ::获取第一个参数
        set "param=%1"
        ::将时间的空格用0补齐;将参数可能携带的引号去掉
        set backup_name=%Ymd: =0%_%param:"=%
        ::将现有的打包后移到backup中
        tar -zcvf test_%backup_name%.tar.gz -C prod .
        move test_%backup_name%.tar.gz backup\test_%backup_name%.tar.gz
        echo 'prod中内容打包到backup中'
        ::清空prod文件夹,然后将传递过来的解压到prod中
        del /q prod\*
        for /d %%x in (prod\*) do @rd /s /q "%%x"
        tar -zxvf dist.tar.gz -C prod
        echo '最新的解压到prod中'
        ::删除传递过来的
        del dist.tar.gz
        echo '删除传递过来的文件'
        @echo on
        

    构建通知

    • 目前插件可以通过钉钉和企业微信机器人通知,目前只测试了钉钉的,感觉还可以,目前我这边没有在pipeline中自定义,只是用了通用功能,更多功能可查看官方文档或自行搜索相关文章。

    完工

    • 以上就是整体流程,只是记录了下一些关键点。
  • 相关阅读:
    codeforces 1012C
    openjudge 6045:开餐馆
    openjudge 7624:山区建小学
    codevs 1040 统计单词个数
    openjudge9267:核电站
    openjudge7624:山区建小学
    bzoj3224:普通平衡树
    洛谷1137:旅行计划
    洛谷1095:守望者的逃离
    校内模拟赛:确定小组
  • 原文地址:https://www.cnblogs.com/vishun/p/16422561.html
Copyright © 2020-2023  润新知