[FIXED] Jenkins: "sh npm i …" not working in docker agent

Issue

Intention

I am trying to build a very simple declarative Jenkinsfile that is based on the latest node docker image. I want to install the dependencies for the Node.js app by calling sh 'npm install ...' in the Jenkinsfile. Installing with npm from the Docker container without Jenkins works like a charm, but not when using Jenkins Pipeline.

Jenkinsfile

pipeline {
   agent { 
       docker {
           image 'node:latest'
       }
   }
   stages {
      stage('Install Dependencies') {
         steps {
            sh 'npm -v' // sanity check
            sh 'ls -lart' // debugging filesystem
            sh 'npm i axios' // this leads to the error
         }
      }
   }
}

Console Log in Jenkins

+ npm install axios
npm ERR! code EACCES
npm ERR! syscall mkdir
npm ERR! path /.npm
npm ERR! errno -13
npm ERR! 
npm ERR! Your cache folder contains root-owned files, due to a bug in
npm ERR! previous versions of npm which has since been addressed.
npm ERR! 
npm ERR! To permanently fix this problem, please run:
npm ERR!   sudo chown -R 1962192188:58041779 "/.npm"

I assume it has to do something with the privileges in the mounted volume from Jenkins and/or the user with which the Docker container ist started from:

What I tried

  1. args '-u root' in the Docker code block in the Jenkinsfile. This works but I doubt this is how this should be solved.

    docker {
        image 'node:latest'
        args '-u root'
    }
    
  2. sudo chown -R 1962192188:58041779 "/.npm" as proposed in the error message. But this leads to:

    + sudo chown -R 1962192188:58041779 /.npm
    /Users/<user>/.jenkins/workspace/pipe@tmp/durable-664f481d/script.sh: 1: 
    /Users/<user>/.jenkins/workspace/pipe@tmp/durable-664f481d/script.sh: sudo: not found
    
  3. Define a layer RUN npm install axios in the Dockerfile. This works, but out of curiosity I want to know why I cannot invoke this directly in Jenkinsfile instead.

    FROM node:latest
    
    RUN npm i axios
    

Solution

The best way to solve this issue is by using one of the following methods (inspired by npm install fails in jenkins pipeline in docker). All three will end up changing the default directory of .npm (i.e., npm’s cache) to the current working directory (which is the Jenkins Job’s workspace mapped to the Docker container).

set ENV variable HOME to current working directory

Declarative Pipeline

pipeline {
    agent { docker { image 'node:latest'' } }
    environment {
        HOME = '.'
    }
    ...

Scripted Pipeline

docker.image('node:latest').inside {
    withEnv([
        'HOME=.',
    ])
    ...

use the additional argument --cache to change the location of the .npm folder when calling npm install

npm install --cache npm_cache <optional:packagename>

set the environment variable npm_config_cache used by npm before calling npm install

Declarative Pipeline

pipeline {
    agent { docker { image 'node:latest'' } }
    environment {
        npm_config_cache = 'npm-cache'
    }
    ...

Scripted Pipeline

docker.image('node:latest').inside {
    withEnv([
        'npm_config_cache=npm-cache',
    ])
    ...

Answered By – Chris Graf

Answer Checked By – Candace Johnson (Easybugfix Volunteer)

Leave a Reply

(*) Required, Your email will not be published