Jenkins 对接 Nexus 私服:Vue 制品的构建、上传与多环境部署

前端 Vue 项目的发布链路:开发把代码提交到 Git/SVN,每个发布版本更新 package.json 里的版本信息,然后 npm publish 把构建产物推到 Nexus 的 npm 私服;Jenkins 通过插件拿到每个版本的下载地址,再用 shell 脚本把制品拉下来部署到各个环境节点。整条链的核心思路是「一次构建,多环境分发同一个包」,开发环境负责编译和上传,测试、生产环境只负责下载解包。

构建一致性要提前处理:webpack 打包时构建时间会参与哈希值计算,同一份代码在两台机器上编译出来的文件名不一致,多环境部署的文件就对不上。做法是注释掉 vue.config.js 里 process.env.VUE_APP_BUILD_TIME 相关的哈希计算参数。但文件名哈希同时是解决浏览器缓存的手段,注释掉之后前端更新可能不被浏览器刷新,这个参数建议保留——两种方案取决于你要一致性还是要缓存,想清楚再选。

Nexus 端准备

先创建 npm 类型的私服仓库,建立 hosted 仓库并配置部署/浏览权限:

nexus01
nexus02
nexus03
nexus04
nexus05
nexus06

然后添加 Realms(安全域),这一步不加,后面上传制品会直接报 401 无权限:

nexus07

在 Jenkins 执行节点上用 npm login 登录私服,成功后当前用户家目录生成 .npmrc,存了私服地址和账号密码(多个 Repository 的地址都可以写进同一个 .npmrc):

[deploy@jenkins-slave1 ~]$ npm login --registry=http://nexus_ip:prot/repository/npm-repository/
Username: admin    #用户
Password:    #密码
Email: (this IS public) admin@example.com    #邮箱
Logged in as admin on http://nexus_ip:prot/repository/npm-repository/ .

Jenkins 端配置

凭据里配置连接 Nexus 平台的账号密码:

nexus08
nexus09

Pipeline 按 DEPLOY 参数区分环境:dev 分支走检出、cnpm install、构建、npm publish 上传制品,再 scp 推到开发机;test 环境不构建,直接 ssh 调用节点上的下载脚本从 Nexus 拉对应版本解包。收尾 curl -I 做访问探活,成功失败都通过企业微信插件通知:

pipeline {
    agent  { 
        node { label 'master'} //指定使用的执行Job任务的节点
    }
    environment {
        dev_serverIP = "192.168.66.80"	// 开发环境节点ip
        test_serverIP = "192.168.66.81" // 测试环境节点ip
        CODE_DIR = "/data/web_client "  // 代码存储目录(各节点存储路径统一)
        server_user = "appadmin"	    // ssh登入用户(前提是已经实现免密)
        DEPLOY = "${DEPLOY}"		    // 指定部署环境
    }

    stages {
        stage('Checkout') {
        //只在开发环境进行代码检出
        when {
            environment name: 'DEPLOY',value: 'dev'
        }
        steps {
		        //job中调用REVISION实现在web界面选择不同分支进行构建
                checkout([$class: 'GitSCM', branches: [[name: '${REVISION}']], doGenerateSubmoduleConfigurations: false, extensions: [], submoduleCfg: [], userRemoteConfigs: [[credentialsId: 'bc392f71-0bd0-4011-aedc-a5345f8f6b2e', url: '项目gitlab存储路径']]])
            }
        }
        
        stage('代码构建') {
            //只有开发环境进行代码构建,其他环境直接下载成品即可
            when {
                environment name: 'DEPLOY',value: 'dev'
            }
            steps{
                // npm构建
                script {
                    sh '''
                        /usr/local/bin/cnpm install
                        /usr/local/bin/npm run build
                    '''
                }
            }
        }
        
        stage('上传制品') {
            when {
                environment name: 'DEPLOY',value: 'dev'
            }
            steps{
                script {
                    sh '''
                        cp package.json dist/
                        cd dist/
                        /usr/local/bin/npm publish --registry=http://nexus_ip:PORT/repository/npm-repository/
                    '''
                }
            }
        }

        stage('部署到开发环境') {
            when {
                environment name: 'DEPLOY',value: 'dev'
            }
 
            steps {
                script {
                    sh """
			            # 调用发布节点环境中的版本备份脚本
                        ssh ${server_user}@${dev_serverIP} "/script/web_client.sh"
                        ssh ${server_user}@${prod_serverIP} "/script/web_client.sh"
                        scp -r ./dist/* ${server_user}@${dev_serverIP}:${CODE_DIR}/package
                    """
                }
            }
        }
        stage('部署到测试环境') {
            when {
                environment name: 'DEPLOY',value: 'test'
            }
            steps {
                script {
                    sh """
                        ssh ${server_user}@${test_serverIP} "/script/web_client.sh"
			            # 调用下载制品脚本,并进行解压到目标目录下
                        ssh ${server_user}@${test_serverIP} "cd /opt/web_code && /script/wget_nexus ${Package} && tar -xf *.tgz -C ${CODE_DIR} && rm -f *.tgz"
                    """
                } 
            }
        }
        stage('进行访问测试') {         
            steps { 
                script {                    
                    sh 'curl -I ${HTTP_URL}'
                }
            }
        }
     }

     // 下面执行构建消息通知,需要安装企业微信插件
     post {
        success {
        script {
                if ("${DEPLOY}" == "uat" || "${DEPLOY}" == "prod") {
                        qyWechatNotification mentionedId: '', 
                        mentionedMobile: '',
                        webhookUrl: ''
                }
                else {
                    qyWechatNotification mentionedId: '', 
                        mentionedMobile: '', 
                        webhookUrl: ''
                }
            }
        }
        failure {
            script {
                if ("${DEPLOY}" == "uat" || "${DEPLOY}" == "prod"){
                    qyWechatNotification mentionedId: '', 
                    mentionedMobile: '', 
                    webhookUrl: ''
                }
                else {
                    qyWechatNotification mentionedId: '', 
                    mentionedMobile: '', 
                    webhookUrl: ''
                }
            }
        }
    }
}

各目标节点上放一个从 Nexus 下载制品的脚本,参数 $1 是包的下载地址:

#在各个目标节点服务器上编辑shell脚本,用来从nexus下载制品
[root@localhost ~]# cd /script/wget_nexus
#!/bin/bash
wget --user="nexus用户" --password="nexus密码" $1 &>/dev/null 

脚本里是明文的 Nexus 账号密码,不希望它出现在 Pipeline 日志或被看到的话,可以用 shc 把脚本编译加密成二进制再分发。

各节点建好制品临时目录和程序目录,属主给 ssh 登录用户:

[root@dev-server ~]# mkdir -p /opt/web_code
[root@dev-server ~]# chown -R appadmin. /opt/web_code
[root@dev-server ~]# mkdir -p /data/web_client/package
[root@dev-server ~]# chown -R appadmin. /data/web_client/package

JOB 与插件

装两个插件:Nexus Artifact Uploader(上传制品到制品库)和 Nexus Platform(把 Nexus Repository Manager / Nexus Lifecycle 集成进 Jenkins 作业)。JOB 配置分支参数和构建参数:

nexus10
nexus11
nexus12
nexus13

注意 REVISION(分支选择参数)只需要在开发环境的 JOB 里配置,测试、生产环境的 JOB 不需要这个参数:

nexus14
nexus15
nexus16
nexus17

执行验证

先跑开发环境:检出、构建、上传制品一条龙:

nexus18
nexus19
nexus20

再选 test 跑部署到测试环境,日志里能看到只做下载、解包,没有构建动作:

nexus21
nexus22

几点提醒

npm publish 的版本号必须递增,重复发同一版本 Nexus 会拒绝,package.json 建议纳入发布检查;免密 ssh 是这套 Pipeline 的前提;wget 下载加了 >/dev/null,节点脚本出错时记得先去掉静默看原因。

© 版权声明
THE END
喜欢就支持一下吧
点赞5 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容