Jenkins管道上的缓存NPM依赖项

rm5edbpk  于 2022-11-21  发布在  Jenkins
关注(0)|答案(6)|浏览(487)

我们都知道用npm下载依赖项可能非常耗时,特别是当我们被限制在旧的npm版本时。
对我来说,作为一个开发人员,这不是什么大问题,因为我在本地开发机器上只需要做几次,所有的工作都在我的项目文件夹中的node_modules缓存中进行。但是现在我想把这个应用程序带到CI环境中,和Jenkins一起。
我意识到用npm下载依赖项花费了大量的时间。这是一个问题,因为:

  1. npm下载项目文件夹中的依赖项,而不是全局文件夹(如Maven的/home/user/.m2
    1.我必须在每次运行中清理Jenkins工作区文件夹,以避免git checkout 时出现问题。
    我需要一个非常好的解决方案来缓存Jenkins slaves上的npm依赖项,但到目前为止我只能想到:
    1.从Jenkins工作区中删除了node_modules文件夹以外的所有内容。我不喜欢这样做,因为如果我一直为我的项目创建分支,我可能会消耗大量的硬盘。每个分支都会创建一个工作区。
    1.在每个npm安装后执行类似cp ./node_modules /home/npm_cache的操作,然后在代码 checkout 后执行cp /home/npm_cache ./node_modules
    我觉得这些解决方案很糟糕,一定有更好的方法来做到这一点。
webghufk

webghufk1#

NPM 具有 存储 在 ~/.npm 中 的 全局 缓存

2ul0zpep

2ul0zpep2#

我在Jenkins管道中为3个不同的项目所做的是使用tar而不是cp,然后使用npm install而不是npm ci,对于每个项目:

  1. cd添加到项目中
  2. npm i
  3. tar cvfz ${HOME}/your_project_node_modules.tar.gz node_modules
    然后在管道中:
dir(your_project){
  sh "tar xf ${HOME}/your_project_node_modules.tar.gz"
  sh "npm i"
}

当然,它的缺点是,随着时间依赖关系的变化,安装将需要更长的时间,但我已设法减少我的磁盘空间使用的映像约0.5GB和tar是快得多,然后cpcp约30秒,tar约5秒)
总安装时间去在我的情况下,从大约3分钟到几秒钟。

mdfafbf1

mdfafbf13#

我在Jenkins中创建了这样的脚本来检查package.json的md5sum:

stage('NPM Build') {
  steps {
    sh '''
    node -v && npm -v
    '''
    // rm -rf node_modules
    sh '''
    CACHE_FOLDER=${HOME}/.cache/md5
    echo "EXECUTOR_NUMBER: ${EXECUTOR_NUMBER}"
    MD5_FILE_NAME=package-json_${EXECUTOR_NUMBER}.md5sum

    [ -d ${CACHE_FOLDER} ] || mkdir -p ${CACHE_FOLDER}
    ls ${CACHE_FOLDER}

    if [ -f ${CACHE_FOLDER}/${MD5_FILE_NAME} ];then
      cp ${CACHE_FOLDER}/${MD5_FILE_NAME} ${MD5_FILE_NAME}
      md5sum package.json
      cat ${MD5_FILE_NAME}
      md5sum -c ${MD5_FILE_NAME} || npm ci
    else
      echo "No md5sum backup"
      npm ci
    fi

    echo "create new md5sum backup"
    md5sum package.json
    md5sum package.json > ${MD5_FILE_NAME}
    cp ${MD5_FILE_NAME} ${CACHE_FOLDER}
    '''
    sh '''
    npm run ngcc
    '''
    sh '''
    npm run build
    '''
  }
}
v1uwarro

v1uwarro4#

我已经选择在一个新的docker容器中运行每个构建,但是依赖缓存仍然可以完成。

  • 每个项目都有一个npm包的缓存,这些包被压缩到一个包含node_modules文件夹的文件中。这些zip文件都存储在主机(运行构建的节点)内的/home/.cache/node_modules文件夹中。因此,当启动docker容器时,它必须有一个bind mount,如
docker { 
    image dockerImage
    args "... -v \"/home/.cache/node_modules:/home/.cache/node_modules\""
}
  • 我正在使用一个共享库与一个自定义步骤进行构建,它的实现或多或少是这样的:
sh """#!/bin/bash -xe
    function getNodeModulesListHash {
        npm ls 2> /dev/null | md5sum | cut -d ' ' -f 1
    }
    
    frontendProjectHashZip="\$(echo "${project}" | md5sum | cut -d ' '  -f 1).tar"
    [[ -f "/home/.cache/node_modules/\$frontendProjectHashZip" ]] && tar -xf "/home/.cache/node_modules/\$frontendProjectHashZip"

    hashBeforeInstall="\$(getNodeModulesListHash)"
    npm install
    hashAfterInstall="\$(getNodeModulesListHash)"

    if [[ \$hashBeforeInstall != \$hashAfterInstall ]]
    then 
        tar -cf \$frontendProjectHashZip node_modules
        rm -f "/home/.cache/node_modules/\$frontendProjectHashZip"
        mv \$frontendProjectHashZip "/home/.cache/node_modules/\$frontendProjectHashZip"
    fi
"""

getNodeModulesListHash用于获取当前已安装包的哈希值。该哈希值在npm install之前和之后计算,因此如果它们的值相同,则我不需要使用node_modules重新创建zip文件,但可以保留最初提取的zip文件。其余部分非常简单,逻辑与其他用户的建议非常相似。

9jyewag0

9jyewag05#

你可以只使用pnpm.io,这将使你的构建速度大大加快(也是在本地)。
[或]
Jenkinsfile的这些部分将执行以下操作:
在分支master和developer上,始终执行全新的npm安装。
在所有其他分支上,package.json将被md5哈希,并且在npm安装后,node_modules文件夹将被放置在定义的缓存文件夹中,如下所示:<CACHE_DIRECTORY>/<MD5_SUM_PACKAGE_JSON>/node_modules .
下一个构建可以重用node_modules,而不必再次下载所有node_modules。

parameters {
    booleanParam(name: "CACHED_NODE_MODULES",
            description: "Should node_modules be taken from cache?",
            defaultValue: !'master'.equals(env.BRANCH_NAME) && !'develop'.equals(env.BRANCH_NAME))
}

...

stage('Build') {
   steps {
      cacheOrRestoreNodeModules()
      echo "Performing npm build..."
      sh 'npm install'

   }
}

...

def cacheOrRestoreNodeModules() {
    if (params.CACHED_NODE_MODULES) {
        sh '''
        MD5_SUM_PACKAGE_JSON=($(md5sum package.json))
        CACHE_FOLDER=/home/jenkins/.cache/npm/${MD5_SUM_PACKAGE_JSON}
        
        # check if folder exists and copy node_modules to current directory
        if [ -d ${CACHE_FOLDER} ]; then
          cp -r ${CACHE_FOLDER}/node_modules .
        fi
        
        npm install --no-audit
        
        # if folder does not exists, create it and cache node_modules folder
        if ! [ -d ${CACHE_FOLDER} ]; then
          mkdir -p ${CACHE_FOLDER}
          cp -r node_modules ${CACHE_FOLDER}/node_modules
        fi
        '''
    }
}
gopyfrb3

gopyfrb36#

我不太了解node.js,不知道如何在那端处理这个问题。但在Linux机器上处理这个问题的一个简单方法是,在你从git checkout 后,直接将该高速缓存目录符号链接到一个外部位置。每台代理机器都将维护自己的缓存,但你可能不得不这样做,而不管解决方案是什么。
我假设您已经研究了nodeJS插件,它不能做您想要的。

相关问题