本次优化在未进行 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"
}
}
}
}
欢迎来到这里!
我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。
注册 关于