npm install fails in jenkins pipeline in docker

DockerJenkinsember.jsNpmJenkins Pipeline

Docker Problem Overview


I'm following a tutorial about Jenkins pipeline and I can get a "hello world" working under at node 6.10 docker container.

But, when I added a default EmberJS app (using ember init) to the repo and attempt to build that in the pipeline, it fails when running npm install (because of directory access issues). The Jenkinsfile can be seen here: https://github.com/CloudTrap/pipeline-tutorial/blob/fix-build/Jenkinsfile

The error message printed by the build is (which is installed locally and run using java -jar jenkins.war on a Macbook, not relevant but included just in case) is:

npm ERR! Linux 4.9.12-moby
npm ERR! argv "/usr/local/bin/node" "/usr/local/bin/npm" "install"
npm ERR! node v6.10.0
npm ERR! npm  v3.10.10
npm ERR! path /.npm
npm ERR! code EACCES
npm ERR! errno -13
npm ERR! syscall mkdir

npm ERR! Error: EACCES: permission denied, mkdir '/.npm'
npm ERR!     at Error (native)
npm ERR!  { Error: EACCES: permission denied, mkdir '/.npm'
npm ERR!     at Error (native)
npm ERR!   errno: -13,
npm ERR!   code: 'EACCES',
npm ERR!   syscall: 'mkdir',
npm ERR!   path: '/.npm',
npm ERR!   parent: 'pipeline-tutorial' }
npm ERR! 
npm ERR! Please try running this command again as root/Administrator.

Note: I would like to not run npm install as root / sudo.

UPDATE: I have been able to make some progress as follows:

I found the command that Jenkins uses to build using the container from the logs:

[Pipeline] withDockerContainer
$ docker run -t -d -u 501:20 -w /long-workspace-directory -v /long-workspace-directory:/long-workspace-directory:rw -v /long-workspace-directory@tmp:/long-workspace-directory@tmp:rw -e

So when the docker image runs, it's work directory is a /long-workspace-directory (it's really a cryptic looking jenkins workspace path) and the user id is 501 (group id 20), etc. The user doesn't have a name (which is apparently breaking other things not related to this question).

  1. Changed agent to use a Dockefile:

     agent {
       dockerfile {
         filename 'Dockerfile'
         args '-v /.cache/ -v /.bower/  -v /.config/configstore/'
       }
     }
    
  2. Specify args '-v ...' for creating volumes for the directories npm install / bower needs.

Docker Solutions


Solution 1 - Docker

Adding the environments and setting the Home to '.' solves this as below.

pipeline {
	agent { docker { image 'node:8.12.0' } }
	environment {
		HOME = '.'
	}
	stages {
		stage('Clone') {
			steps {
				git branch: 'master',
					credentialsId: '121231k3jkj2kjkjk',
					url: 'https://myserver.com/my-repo.git'
			}
		}
		stage('Build') {
			steps {
				sh "npm install"
			}
		}
	}
}

Solution 2 - Docker

from https://github.com/jenkins-infra/jenkins.io/blob/master/Jenkinsfile

docker.image('openjdk:8').inside {
	/* One Weird Trick(tm) to allow git(1) to clone inside of a
	* container
	*/
	withEnv([
		/* Override the npm cache directory to avoid: EACCES: permission denied, mkdir '/.npm' */
		'npm_config_cache=npm-cache',
		/* set home to our current directory because other bower
		* nonsense breaks with HOME=/, e.g.:
		* EACCES: permission denied, mkdir '/.config'
		*/
		'HOME=.',
	]) {
			// your code
	}
}

Solution 3 - Docker

Having wasted a whole day on this issue, I found simply adding the following as an environment variable at the agent stage using the Pipeline Editor removed the problem.

'npm_config_cache=npm-cache'

Solution 4 - Docker

When Jenkins runs the stage in Docker agent it usually sets HOME=/ (image WORKDIR value), but Jenkins user does not have write permissions in this directory, that's why npm cannot create its cache directory ~/.npm. To solve this you need either to override HOME or NPM default cache directory:

environment {
    // Override HOME to WORKSPACE
    HOME = "${WORKSPACE}"
    // or override default cache directory (~/.npm)
    NPM_CONFIG_CACHE = "${WORKSPACE}/.npm"
}

Solution 5 - Docker

Wanted to just provide a bit more detail, in short the accepted answer works but that I'm new to Docker and wanted to get a better understanding and figured i'd share what i found.

So for our jenkins setup, it starts containers via

docker run -t -d -u 995:315 -w /folder/forProject -v /folder/forProject:/folder/forProject:rw,z ...

As a result this container is running as user uid=995 gid=315 groups=315

Since the image I was using (circleci/node:latest) doesn’t have a user with this UID/GID, the user will not have a “home” folder and will only have permission on the mounted volume.

When NPM commands are called it will try using that users home directory (for cache) and since that user wasn’t created on the image, the home directory gets set to / (default for linux?). So to get NPM to work correctly we simply point the containers HOME environment variable for the user to the current folder via the Jenkins file

pipeline {
  agent none
  stages {
    stage('NPM Installs') {
      agent {
        docker {
            image 'circleci/node:latest'
        }
      }
      environment { HOME="." }
      ...
    }
  }
}

Thus giving the user the ability to create the required .npm folder in /folder/forProject/.npm

Hopefully this is helpful to someone and if you see something that i got wrong please let me know :D

Solution 6 - Docker

I add the same issue. I solved it using the root user to run the Docker image:

node {
    stage("Prepare environment") {
        checkout scm
        // Build the Docker image from the Dockerfile located at the root of the project
        docker.build("${JOB_NAME}")
    }

    stage("Install dependencies") {
        // Run the container as `root` user
        // Note: you can run any official Docker image here
        withDockerContainer(args: "-u root", image: "${JOB_NAME}") {
            sh "npm install"
        }
    }
}

Solution 7 - Docker

You can override the user that Jenkins runs the docker container with, for example here I override with the root (userid:groupid is 0:0):

docker { 
    image 'node:8'
    args '-u 0:0'
}

You can spot the current user in the docker run parameters in the console output.

Solution 8 - Docker

We had the same issue, the core of the problem for us was, that the user in the Container and the User running the Jenkins node had different UIDs. After changing the UID+GID of the user in the container (and changing ownership of the users home-directory) to match the user running the build node npm would behave normal.

This might also happen if the Home-Directory of the container-user is not writeable.

Code in the Dockerfile:

RUN usermod -u <uid of buildnode> <container user> && \
    groupmod -g <gid of buildnode> <container user group> && \
    chown -R <container user>:<container user group> /home/<container user>

As the Workspace is mounted into the container it will already belong to the UID. When running the container through the Jenkinsfile the UID and GID of the container user are set automatically to match the buildnode. But the home directory will still have its original owner.

Now the node_modules will be placed in the current directory.

Solution 9 - Docker

In my case the problem was that inside the container I was user jenkins instead of root. I got there by setting whoami inside the container and got error like cannot determine user 111 (which happens to be jenkins). So I did the following:

stage('Run build') {
    	webappImage.inside("-u root") {
    		sh "yarn run build"
    	}
    }

Solution 10 - Docker

this configuration work for me.

pipeline {
    agent {
        docker {
            image 'node:6-alpine'
            args '-p 3000:3000 -p 5000:5000'
            args '-u 0:0'

        }
    }
    environment {
        CI = 'true'
    }
    stages {
        stage('Build') {
            steps {
                sh 'npm install --unsafe-perm'
            }
        }
        stage('Test') {
            steps {
                sh './jenkins/scripts/test.sh'
            }
        }
        stage('Deliver for development') {
            when {
                branch 'development' 
            }
            steps {
                sh './jenkins/scripts/deliver-for-development.sh'
                input message: 'Finished using the web site? (Click "Proceed" to continue)'
                sh './jenkins/scripts/kill.sh'
            }
        }
        stage('Deploy for production') {
            when {
                branch 'production'  
            }
            steps {
                sh './jenkins/scripts/deploy-for-production.sh'
                input message: 'Finished using the web site? (Click "Proceed" to continue)'
                sh './jenkins/scripts/kill.sh'
            }
        }
    }
}

Solution 11 - Docker

In my case this solved the problem

            agent {
                docker {
                    image 'node:10-stretch'
                    args '-v /home/jenkins/.ssh:/home/jenkins/.ssh:ro -u 0'
                }
            }

Solution 12 - Docker

I was using maven to build the project and which indeed was running the frontend-maven-plugin which is responsible for calling the npm install So npm install was breaking with error: path /.npm npm ERR! code EACCES npm ERR! errno -13 npm ERR! syscall mkdir

I changed it to npm install --cache /tmp/empty-cache

and it worked

Solution 13 - Docker

You can install nvm on the fly before building, in a local directory with NVM_DIR without setting it as global dependency :

mkdir -p node_dir
export NVM_DIR=$(pwd)/node_dir
curl https://raw.githubusercontent.com/creationix/nvm/v0.33.1/install.sh | bash
source $(pwd)/node_dir/nvm.sh
nvm install 7
nvm use 7

The new locations are :

$ which node
~/someDir/node_dir/versions/node/v7.7.2/bin/node

$ which npm
~/someDir/node_dir/versions/node/v7.7.2/bin/npm

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
Questionles2View Question on Stackoverflow
Solution 1 - DockerDinuka De SilvaView Answer on Stackoverflow
Solution 2 - DockerarturhView Answer on Stackoverflow
Solution 3 - DockerSwagridView Answer on Stackoverflow
Solution 4 - DockerOleksandr ShmyrkoView Answer on Stackoverflow
Solution 5 - DockerJeffBeltranView Answer on Stackoverflow
Solution 6 - DockerPierreView Answer on Stackoverflow
Solution 7 - DockerIevgen GoichukView Answer on Stackoverflow
Solution 8 - Dockeruser2859193View Answer on Stackoverflow
Solution 9 - DockerRemigiuszView Answer on Stackoverflow
Solution 10 - Dockeryasin lachiniView Answer on Stackoverflow
Solution 11 - DockerAntoxaView Answer on Stackoverflow
Solution 12 - DockerRajkiranView Answer on Stackoverflow
Solution 13 - DockerBertrand MartelView Answer on Stackoverflow