npm install fails in jenkins pipeline in docker

2019-03-08 11:22发布

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.

9条回答
兄弟一词,经得起流年.
2楼-- · 2019-03-08 11:27

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
查看更多
成全新的幸福
3楼-- · 2019-03-08 11:29

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'
查看更多
Viruses.
4楼-- · 2019-03-08 11:31

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
    }
}
查看更多
冷血范
5楼-- · 2019-03-08 11:33

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"
            }
        }
    }
}
查看更多
再贱就再见
6楼-- · 2019-03-08 11:36

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"
        }
    }
}
查看更多
疯言疯语
7楼-- · 2019-03-08 11:36

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.

查看更多
登录 后发表回答