npm安装在docker的jenkins管道中失败

时间:2017-03-12 02:56:23

标签: docker jenkins ember.js npm jenkins-pipeline

我正在关注Jenkins管道的教程,我可以得到一个" hello world"在节点6.10 docker container下工作。

但是,当我将一个默认的EmberJS应用程序(使用ember init)添加到repo并尝试在管道中构建它时,它在运行npm install时失败(因为目录访问问题)。 Jenkins文件可以在这里看到:https://github.com/CloudTrap/pipeline-tutorial/blob/fix-build/Jenkinsfile

构建打印的错误消息(在本地安装并在Macbook上使用java -jar jenkins.war运行,不相关但仅包括在内)是:

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.

注意:我希望以root / sudo运行npm install

更新:我已经取得了如下进展:

我找到了Jenkins用来使用日志中的容器构建的命令:

[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

因此,当docker镜像运行时,它的工作目录是/long-workspace-directory(它真的是一个神秘的jenkins工作空间路径),用户ID是501(组ID 20),用户没有姓名(这显然打破了与此问题无关的其他事项)。

  1. 更改了代理以使用Dockefile:

    agent {
      dockerfile {
        filename 'Dockerfile'
        args '-v /.cache/ -v /.bower/  -v /.config/configstore/'
      }
    }
    
  2. 指定args '-v ...'为npm install / bower需要的目录创建卷。

12 个答案:

答案 0 :(得分:19)

来自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
    }
}

答案 1 :(得分:14)

在这个问题上浪费了一整天,我发现只需在代理阶段将以下内容添加为环境变量,使用管道编辑器就可以解决问题。

'npm_config_cache=npm-cache'

答案 2 :(得分:14)

添加环境并将“主页”设置为“。”。解决此问题的方法如下。

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"
            }
        }
    }
}

答案 3 :(得分:4)

我添加了同样的问题。我使用root用户解决了它以运行Docker镜像:

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"
        }
    }
}

答案 4 :(得分:4)

Jenkins在Docker代理中运行阶段时,通常会设置HOME=/(图像WORKDIR值),但是Jenkins用户在此目录中没有写权限,这就是npm无法创建的原因其缓存目录~/.npm。要解决此问题,您需要覆盖HOME或NPM默认缓存目录:

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

答案 5 :(得分:2)

你可以覆盖Jenkins运行docker容器的用户,例如在这里我用root覆盖(userid:groupid是0:0):

ConsumerRecords

您可以在控制台输出中的private void invokeListener(final ConsumerRecords<K, V> records) { if (this.isBatchListener) { invokeBatchListener(records); } else { invokeRecordListener(records); } } 参数中找到当前用户。

答案 6 :(得分:1)

我们遇到了同样的问题,问题的核心是,Container中的用户和运行Jenkins节点的用户有不同的UID。 更改容器中用户的UID + GID后(并更改 用户主目录的所有权)以匹配 运行构建节点npm的用户将表现正常。

如果容器用户的主目录不可写,也可能发生这种情况。

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>

当工作区安装到容器中时,它已经属于 UID。通过Jenkinsfile运行容器时的UID和GID 容器用户自动设置以匹配buildnode。但主目录仍将拥有其原始所有者。

现在node_modules将被放置在当前目录中。

答案 7 :(得分:1)

在我的情况下,问题是在容器内部,我是用户jenkins而不是root。我通过在容器内设置whoami到达那里,并遇到了类似cannot determine user 111的错误(碰巧是詹金斯)。所以我做了以下事情:

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

答案 8 :(得分:1)

只想提供更多细节,简而言之,可以接受的答案有效,但我是Docker的新手,并希望得到更好的理解,并认为我会分享发现的内容。

因此对于我们的詹金斯设置,它通过

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

结果,此容器以用户uid=995 gid=315 groups=315的身份运行

由于我使用的图像(circleci / node:latest)没有该UID / GID的用户,因此该用户将没有“主”文件夹,并且仅对已安装的卷具有权限。

调用NPM命令时,它将尝试使用该用户的主目录(用于缓存),并且由于未在映像上创建该用户,因此主目录被设置为/(Linux的默认目录?)。因此,要获得NPM工作正常,我们简单地指向容器HOME环境变量通过詹金斯文件的用户到当前文件夹

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

因此,用户可以在.npm中创建所需的/folder/forProject/.npm文件夹

希望这对某人有帮助,如果您发现我错了,请告诉我:D

答案 9 :(得分:1)

我使用 maven 来构建项目,它确实运行了负责调用 npm install 的 frontend-maven-plugin 所以 npm install 因错误而中断: 路径 /.npm npm 错误!代码 EACCES npm 错误!错误号 -13 npm 错误!系统调用 mkdir

我改成 npm install --cache /tmp/empty-cache

它奏效了

答案 10 :(得分:0)

您可以在构建之前动态安装nvm,在NVM_DIR的本地目录中,而不将其设置为全局依赖:

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

新的位置是:

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

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

答案 11 :(得分:0)

此配置对我有用。

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'
            }
        }
    }
}