简体   繁体   English

npm install 在 docker 的 jenkins 管道中失败

[英]npm install fails in jenkins pipeline in docker

I'm following a tutorial about Jenkins pipeline and I can get a "hello world" working under at node 6.10 docker container.我正在关注关于 Jenkins 管道的教程,我可以在节点 6.10 docker 容器下获得一个“hello world”。

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).但是,当我将默认的 EmberJS 应用程序(使用ember init )添加到存储库并尝试在管道中构建它时,运行 npm install 时它会失败(因为目录访问问题)。 The Jenkinsfile can be seen here: https://github.com/CloudTrap/pipeline-tutorial/blob/fix-build/Jenkinsfile Jenkinsfile 可以在这里看到: 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:构建打印的错误消息是(在本地安装并在 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.

Note: I would like to not run npm install as root / sudo.注意:我不想以 root / sudo 身份运行npm install

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:我从日志中找到了 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

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).因此,当 docker 映像运行时,它的工作目录是/long-workspace-directory (它实际上是一个看起来很神秘的 jenkins 工作区路径),用户 id 是 501(组 id 20)等。用户没有名字(这显然破坏了与这个问题无关的其他事情)。

  1. Changed agent to use a Dockefile:更改代理以使用 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.指定args '-v ...'为 npm install / bower 需要的目录创建卷。

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

from https://github.com/jenkins-infra/jenkins.io/blob/master/Jenkinsfile来自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
    }
}

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

'npm_config_cache=npm-cache'

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 .当 Jenkins 在 Docker 代理中运行阶段时,它通常设置HOME=/ (图像WORKDIR值),但是 Jenkins 用户在该目录中没有写入权限,这就是npm无法创建其缓存目录~/.npm的原因。 To solve this you need either to override HOME or NPM default cache directory:要解决这个问题,您需要覆盖HOME或 NPM 默认缓存目录:

pipeline {
    agent {
        docker {
            reuseNode true
            image 'node:16.15'
        }
    }

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

    stages {
        stage('Build') {
            steps {
                sh 'npm install'
                sh 'npm run build'
            }
        }
    }
}

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

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结果,该容器以用户身份运行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.由于我使用的映像 (circleci/node:latest) 没有具有此 UID/GID 的用户,因此该用户将没有“主”文件夹,并且仅对已安装的卷具有权限。

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?).当调用 NPM 命令时,它将尝试使用该用户的主目录(用于缓存),并且由于该用户不是在映像上创建的,因此主目录设置为/ (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因此,为了让 NPM 正常工作,我们只需通过 Jenkins 文件将用户的容器 HOME 环境变量指向当前文件夹

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从而使用户能够在/folder/forProject/.npm中创建所需的.npm文件夹

Hopefully this is helpful to someone and if you see something that i got wrong please let me know :D希望这对某人有帮助,如果您发现我做错了什么,请告诉我:D

I add the same issue.我添加了同样的问题。 I solved it using the root user to run the Docker image:我使用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"
        }
    }
}

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):您可以覆盖 Jenkins 运行 docker 容器的用户,例如这里我用 root 覆盖(userid:groupid 为 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.您可以在控制台输出的docker run参数中发现当前用户。

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.我们有同样的问题,对我们来说问题的核心是,容器中的用户和运行 Jenkins 节点的用户有不同的 UID。 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.在更改容器中用户的 UID+GID(并更改用户主目录的所有权)以匹配运行构建节点的用户之后,npm 将表现正常。

This might also happen if the Home-Directory of the container-user is not writeable.如果容器用户的主目录不可写,也可能发生这种情况。

Code in the Dockerfile: 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.由于 Workspace 已安装到容器中,因此它已经属于 UID。 When running the container through the Jenkinsfile the UID and GID of the container user are set automatically to match the buildnode.当通过 Jenkinsfile 运行容器时,容器用户的 UID 和 GID 会自动设置为与 buildnode 匹配。 But the home directory will still have its original owner.但主目录仍将拥有其原始所有者。

Now the node_modules will be placed in the current directory.现在 node_modules 将被放置在当前目录中。

In my case the problem was that inside the container I was user jenkins instead of root.就我而言,问题是在容器内我是用户 jenkins 而不是 root。 I got there by setting whoami inside the container and got error like cannot determine user 111 (which happens to be jenkins).我通过在容器内设置whoami到达那里并得到了cannot determine user 111 (恰好是詹金斯)之类的错误。 So I did the following:所以我做了以下事情:

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

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

In my case this solved the problem就我而言,这解决了问题

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

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!我正在使用 maven 构建项目,它确实正在运行负责调用 npm install 的前端 maven-plugin 所以 npm install 因错误而中断:path /.npm npm ERR! code EACCES npm ERR!代码 EACCES npm 错误! errno -13 npm ERR! errno -13 npm 错误! syscall mkdir系统调用 mkdir

I changed it to npm install --cache /tmp/empty-cache我将其更改为npm install --cache /tmp/empty-cache

and it worked它奏效了

You can install nvm on the fly before building, in a local directory with NVM_DIR without setting it as global dependency :您可以在构建之前即时安装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

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM