优化jenkins构建vue项目时间

2020-09-25

1599814231932.jpg

本次优化在未进行 webpack 配置修改的前提下,可以减少 40+ 秒,据前端反馈 webpack 优化后还可以再减少 40+ 秒

我这里使用了单独的 jenkins slave 用来专门处理编译耗时的 job,工作目录/data/jenkins/

使用 tmpfs,进行内存换时间

mount -t tmpfs -o size=1G,nr_inodes=10k,mode=0700 tmpfs /data/jenkins

如果 inode 设置过小很容易占满,df -i 可以查看到 100%,根据实际使用情况调整

mount -o remount,size=2G,nr_inodes=100k /data/jenkins

设置开机挂载,编辑/etc/fstab

tmpfs /data/jenkins tmpfs defaults,size=2G,nr_inodes=100k,mode=0700 0 0

使用 yarn 进行依赖管理

之前有看到使用 npm ci 的方式,不过 npm v5 暂时不支持,安装 yarn

npm install -g yarn

配置 yarn 的缓存路径和全局安装路径

yarn config set cache-folder /data/jenkins/yarn-cache

yarn config  set global-folder "/data/jenkins/yarn-global"

配置淘宝源,也可以换成私库

yarn config set registry https://registry.npm.taobao.org

避免报错:The engine "node" is incompatible with this module

yarn config set ignore-engines true

使用 --prefer-offline 模式。

  • 如果设置为--prefer-offline 则优先使用缓存数据,如果没有匹配的缓存数据,则从远程仓库下载。
  • 如果设置为--prefer-online 则优先使用网络数据,忽略缓存数据,这种模式可以及时获取最新的模块。
yarn --prefer-offline

禁用 progress

当设置 progress为 true 时, 时将会显示进度条,把它设置为 false 可小幅提高 的速度。

// npm set progress=false && npm run build:${ENV}
yarn run build:${ENV} --no-progress

附:清理缓存

//npm cache clean --force
yarn cache clean

复用 node_modules

jenkins 构建时不清理 workspace,复用 node_modules,这里我使用 mount --bind 的方式把/data/jenkins/node_modules 挂载到 $WORKSPACE/node_modules,job 完成后 umount

最终 jenkins pipeline

pipeline {

    // agent any

    agent {

        label 'tmpfs-slave'

    }

    options {

        ansiColor('xterm')

        buildDiscarder(logRotator(daysToKeepStr: '1', numToKeepStr: '5'))

    }

    tools {

        Git 'git_2.19.1'

    }

    environment {

        Git = 'http://172.19.76.222/adminfe/adminfe-admin-fe.git'

        IMAGE_GROUP = "adminfe" //对应 harbor 镜像分组

        K8S_NAMESPACE = "${ENV}-${IMAGE_GROUP}"

        REPLICAS = 1

        TEMPLATE="deployment-frontend.yml"

        PROJECT = sh(script: "echo ${GIT} | awk -F '/' '{print \$NF}' | awk -F '.' '{print \$1}'", returnStdout: true).trim()

        ENV = sh(script: "echo ${JOB_BASE_NAME} | awk -F '-' '{print \$1}'", returnStdout: true).trim()

        HARBOR_HOST = 'test-devops-harbor.demo.com'

        ZIP = "target"

        PATH = "/data/node-v8.11.1/bin:$PATH"

        DOCKER_IMAGE = "${IMAGE_GROUP}/${JOB_BASE_NAME}:${VERSION_VALUE}"

        MAIL_TO = "admin@demo.com"

        CHECK_TAG = sh(script: "echo ${BRANCH_OR_TAG} | awk -F '/' '{if (\$3) print \$3; else print \$1}'", returnStdout: true).trim()  // 分支或 tag

        VERSION_VALUE = "${CHECK_TAG}-${TIME}" // 分支或 tag

        TIME = sh(script: "date '+%Y%m%d%H%M%S'", returnStdout: true).trim()

    }

    stages {

        stage ('代码获取') {

            steps {

              echo "\033[46;30m************************************************ 拉取代码开始 ************************************************\033[0m"

            //   deleteDir() // 清理工作目录

              Git credentialsId: 'gitlab_username_password_credential', url: "${GIT}"

              sh '[ -n "${CHECK_TAG}" ] &&  Git checkout ${CHECK_TAG} ||  { echo -e "切换至指定的 tag 的版本,tag:${CHECK_TAG} 不存在或为空,请检查输入的 tag!" && exit 111; }'

              echo "\033[46;30m************************************************ 拉取代码结束 ************************************************\033[0m"

            }

        }



        stage ('代码编译') {

            steps {

              echo "\033[46;30m************************************************ 编译打包开始 ************************************************\033[0m"

              sh "git pull || true"
              sh "[ -d 'node_modules' ] && echo 'Directory Exists' || mkdir node_modules && mount --bind /data/jenkins/node_modules node_modules"
              sh "yarn config set ignore-engines true && yarn config set registry https://registry.npm.taobao.org && yarn --prefer-offline && yarn run build:${ENV} --no-progress"

              echo "\033[46;30m************************************************ 编译打包结束 ************************************************\033[0m"

            }

        }



        stage('镜像构建') {

            steps {

              echo "\033[46;30m************************************************ 镜像构建开始 ************************************************\033[0m"

              script {

                  sh "/usr/bin/cp -f /data/template/docker/Dockerfile-frontend Dockerfile"

                  sh "docker build --build-arg PROJECT=${PROJECT} -t ${HARBOR_HOST}/${DOCKER_IMAGE} ."

                  sh "docker push ${HARBOR_HOST}/${DOCKER_IMAGE}"

                  sh "docker rmi ${HARBOR_HOST}/${DOCKER_IMAGE}"

              }

              echo "\033[46;30m************************************************ 镜像构建结束 ************************************************\033[0m"

            }

        }



        stage('发布服务至 kubernetes 集群') {

            steps {

                script {

                echo "\033[46;30m************************************************ 发布服务至 kubernetes 集群开始 ************************************************\033[0m"

                    sh "cp /data/template/k8s/${TEMPLATE} ${TEMPLATE}"

                    sh "sed -i -e 's#{IMAGE_URL}#${HARBOR_HOST}/${DOCKER_IMAGE}#g;s#{PROJECT}#${PROJECT}#g;s#{IMAGE_GROUP}#${IMAGE_GROUP}#g;s#{K8S_NAMESPACE}#${K8S_NAMESPACE}#g;s#{REPLICAS}#${REPLICAS}#g;' ${TEMPLATE}"

                    sh "kubectl --kubeconfig /data/kubecfg/test-cluster cluster-info && kubectl --kubeconfig /data/kubecfg/test-cluster get nodes"

                    sh "kubectl --kubeconfig /data/kubecfg/test-cluster apply -f ${TEMPLATE} --namespace=${K8S_NAMESPACE}"

                echo "\033[46;30m************************************************ 发布服务至 kubernetes 集群结束 ************************************************\033[0m"

                }

            }

        }

    }



    post {

      always {

                script{

                    sh "umount node_modules" // 解除目录挂载

                    echo "\033[46;30m************************************************ 邮件通知开始 ************************************************\033[0m"

                    def jobUserId, jobUserName

                    wrap([$class: 'BuildUser']) {

                        jobUserId = "${BUILD_USER_ID}"

                        jobUserName = "${BUILD_USER}"

                        jobUserEmail = "${BUILD_USER_EMAIL}"

                    }

                    if (currentBuild.currentResult == "ABORTED" || currentBuild.currentResult == "FAILURE" || currentBuild.currentResult == "UNSTABLE" ){

                        mail to: "devops@demo.com,'${jobUserEmail}",

                        subject: "PineLine '${JOB_NAME}' (${BUILD_NUMBER})构建失败",

                        body: "操作人: ${jobUserName}\n 操作事项: 执行执行 PineLine '${JOB_NAME}' (${BUILD_NUMBER})\n 于 ${TIME} 构建 job 失败\n 项目 url 为 ${BUILD_URL}console",

                        charset:"UTF-8"

                    } else {

                        mail to: "devops@demo.com",

                        subject: "PineLine '${JOB_NAME}' (${BUILD_NUMBER})构建成功",

                        body: "操作人: ${jobUserName}\n 操作事项: 执行执行 PineLine '${JOB_NAME}' (${BUILD_NUMBER})\n 于 ${TIME} 进入 kubernetes 集群发布状态\n 请前往 rancher 查看发布详情",

                        charset:"UTF-8"

                    }

                    echo "\033[46;30m************************************************ 邮件通知结束 ************************************************\033[0m"

                }

        }

    }

}

标题:优化jenkins构建vue项目时间
作者:fish2018
地址:http://www.devopser.org/articles/2020/09/11/1599814292016.html