缓存Jenkins管道上的NPM依赖项

时间:2017-10-22 02:46:48

标签: node.js caching jenkins dependencies

我们都知道用npm下载依赖项可能非常耗时,特别是当我们仅限于旧的npm版本时。

对我来说,作为一名开发人员,这不是什么大问题,因为我必须在我的本地开发机器上执行此操作,并且所有内容都与我项目文件夹中的node_modules缓存有关。但是现在我想把这个应用程序带到Jenns的CI环境中。

我意识到用npm下载依赖项花了很多时间。这是一个问题,因为:

  1. npm下载项目文件夹中的依赖项,而不是Maven的/home/user/.m2

  2. 等全局文件夹
  3. 我必须在每次运行时清理Jenkins工作区文件夹,以避免git checkout出现问题。

  4. 我想要一个非常优雅的解决方案来缓存我的Jenkins奴隶上的npm依赖项,但到目前为止我只能想到:

    1. 从Jenkins工作区中删除除node_modules文件夹之外的所有文件夹。我不喜欢这个,因为如果我继续为我的项目创建分支,我可能会消耗大量的硬盘。每个分支都创建一个工作区。

    2. 在每次安装npm后执行cp ./node_modules /home/npm_cache之类的操作,然后在代码结帐后执行cp /home/npm_cache ./node_modules

    3. 我觉得这些解决方案很糟糕。必须有更好的方法来做到这一点。

6 个答案:

答案 0 :(得分:0)

我不会'知道node.js足以知道如何处理这一方面。但是可以在Linux机器上处理的一个简单方法就是在从git签出后立即将缓存目录符号链接到外部位置。每个代理机器都将维护自己的缓存,但无论解决方案如何,您都可能必须这样做。

我假设你已经调查过nodeJS插件,它无法做你想做的事情。

答案 1 :(得分:0)

NPM在~/.npm

中存储了全局缓存

答案 2 :(得分:0)

我在Jenkins管道中针对3个不同项目所做的工作是,对于每个项目,分别使用*(*(matrix + i) + j) matrix[i][j] 而不是tar,然后使用cp而不是npm install

  1. npm ci到您的项目
  2. cd
  3. npm i

然后在管道中:

tar cvfz ${HOME}/your_project_node_modules.tar.gz node_modules

当然,它的缺点是随着时间的变化,安装时间会更长,但是我设法将映像中的磁盘空间使用量减少了约0.5GB,dir(your_project){ sh "tar xf ${HOME}/your_project_node_modules.tar.gz" sh "npm i" } 比{ {1}}(tar〜30秒,cp〜5秒)

在我看来,总安装时间从大约3分钟缩短到几秒钟。

答案 3 :(得分:0)

我创建了这样的脚本来检查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
    '''
  }
}

答案 4 :(得分:0)

Jenkinsfile 的那些部分将执行以下操作:

在 Branch master 和 develop 上,总是执行全新的 npm install。

在所有其他分支上,package.json 将被 md5 散列,并且在 npm install 之后 node_modules 文件夹将放置在定义的缓存文件夹中,例如: //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
    '''
}

}

答案 5 :(得分:0)

我选择在新的 docker 容器中运行每个构建,但仍然可以完成依赖项缓存。这就是我所做的:

  • 每个项目都有一个 npm 包缓存,这些包被压缩到一个包含 node_modules 文件夹的文件中。这些 zip 都存储在主机(运行构建的节点)内的 /home/.cache/node_modules 文件夹中。所以,当启动 docker 容器时,它必须有一个像
  • 这样的绑定挂载
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 文件,但我可以保留我最初提取的那个。其余部分非常简单,逻辑与其他用户提出的非常相似。

相关问题