npm install 在 docker 的 jenkins 管道中失败

Posted

技术标签:

【中文标题】npm install 在 docker 的 jenkins 管道中失败【英文标题】:npm install fails in jenkins pipeline in docker 【发布时间】:2017-08-02 06:18:53 【问题描述】:

我正在学习有关 Jenkins 管道的教程,我可以在节点 6.10 docker 容器下获得一个“hello world”。

但是,当我将默认的 EmberJS 应用程序(使用 ember init)添加到存储库并尝试在管道中构建它时,运行 npm install 时它会失败(因为目录访问问题)。 Jenkinsfile 可以在这里看到: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)等等。用户没有名字(这显然破坏了与这个问题无关的其他事情)。

    将代理更改为使用 Dockefile:

    agent 
      dockerfile 
        filename 'Dockerfile'
        args '-v /.cache/ -v /.bower/  -v /.config/configstore/'
      
    
    

    指定 args '-v ...' 为 npm install / bower 需要的目录创建卷。

【问题讨论】:

npm ERR! Please try running this command again as root/Administrator. 试试这个提示。 通常情况下,您不会以 root 身份运行 npm install;它被认为是非常糟糕的形式;我想避免这种情况。 请看nvm 我没有安装任何全局依赖项。我在工作中和我们现有的 ci 设置中广泛使用 nvm。 我认为我使用的图像不正确。节点映像用于运行节点服务器应用程序,而不是运行一系列构建命令。 【参考方案1】:

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

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

成功了

【讨论】:

【参考方案2】:

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

【讨论】:

NPM_CONFIG_CACHE 传递给 docker 镜像终于解决了,这是一个令人抓狂的问题。谢谢【参考方案3】:

就我而言,这解决了问题

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

【讨论】:

【参考方案4】:

这个配置对我有用。

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'
            
        
    

【讨论】:

【参考方案5】:

只想提供更多细节,简而言之,接受的答案有效,但我是 Docker 新手,想要更好地理解并想分享我发现的东西。

所以对于我们的 jenkins 设置,它通过

启动容器
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 正常工作,我们只需通过 Jenkins 文件将用户的容器 HOME 环境变量指向当前文件夹

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

从而使用户能够在/folder/forProject/.npm 中创建所需的.npm 文件夹

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

【讨论】:

【参考方案6】:

在我的情况下,问题是在容器内我是用户 jenkins 而不是 root。我通过在容器内设置whoami 到达那里,并得到像cannot determine user 111 这样的错误(恰好是詹金斯)。所以我做了以下事情:

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

【讨论】:

【参考方案7】:

添加环境并将主页设置为“。”解决这个问题如下。

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"
            
        
    

【讨论】:

哇,好神奇!这也为我解决了,谢谢。我想 npm 取决于 Jenkins 未设置的 HOME 变量。 环境也可以单阶段设置。谢谢!【参考方案8】:

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

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

您可以在控制台输出的docker run 参数中发现当前用户。

【讨论】:

【参考方案9】:

我们有同样的问题,对我们来说问题的核心是,容器中的用户和运行 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>

当工作空间被挂载到容器中时,它已经属于 用户标识符。通过 Jenkinsfile 运行容器时的 UID 和 GID 容器用户被自动设置为匹配构建节点。但主目录仍将拥有其原始所有者。

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

【讨论】:

【参考方案10】:

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

'npm_config_cache=npm-cache'

【讨论】:

我正在使用纱线并且有同样的问题。你知道纱线怎么解决吗? 如何使用这个配置?【参考方案11】:

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

【讨论】:

你只需要设置HOME=.,因为npm_config_cache$HOME/.npm,所以在这种情况下它将是./.npm而不是/.npm 我可以确认只是设置 'HOME=.'够了 为了完整性environment HOME="." 修复了 Jenkins 声明性语法的问题。 我可以确认设置 'npm_config_cache=npm-cache' 也足够了【参考方案12】:

我添加了同样的问题。我使用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"
        
    

【讨论】:

在此之后,您必须删除在 root 用户下创建的所有文件,否则 jenkins 将由于工作空间目录内的权限冲突而导致下一个作业失败。 加上在容器中使用 root 是一种不好的安全做法【参考方案13】:

您可以在构建之前即时安装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

【讨论】:

以上是关于npm install 在 docker 的 jenkins 管道中失败的主要内容,如果未能解决你的问题,请参考以下文章

在 Docker 中运行时,`npm install` 导致`cb() never called!`

Docker 容器的最大调用堆栈大小超过了 npm install

npm install git+ssh 在 docker (node16) 中失败

docker image 上的 npm global install 没有访问权限错误

为啥在 `npm install` 时`package-lock.json` 会导致 docker 容器构建失败?

npm install 后 Gitlab Shared Runner docker build