Npm установка завершается неудачей в проекте jenkins в докере

Я следую учебному пособию о конвейере Jenkins, и я могу получить "привет мир", работающий в док-контейнере узла 6.10.

Но когда я добавил в репозиторий приложение EmberJS по умолчанию (с помощью ember init) и попытался создать его в конвейере, оно перестало работать при запуске npm install (из-за проблем с доступом к каталогу). Файл Jenkins можно увидеть здесь: https://github.com/CloudTrap/pipeline-tutorial/blob/fix-build/Jenkinsfile

Сообщение об ошибке, напечатанное сборкой, (которое устанавливается локально и запускается с помощью java -jar jenkins.war на Macbook, не имеет значения, но включено на всякий случай):

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.

Примечание: я бы не хотел запускать npm install от имени пользователя root/sudo.

ОБНОВЛЕНИЕ: я был в состоянии сделать некоторый прогресс следующим образом:

Я нашел команду, которую Дженкинс использует для построения с использованием контейнера из журналов:

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

Таким образом, когда запускается образ докера, его рабочий каталог представляет собой каталог /long-workspace-directory (это действительно загадочно выглядящий путь рабочей области jenkins), а идентификатор пользователя - 501 (идентификатор группы 20) и т.д. У пользователя нет имени (что явно нарушает другие вещи, не связанные с этим вопросом).

  1. Изменен агент для использования Dockefile:

    agent {
      dockerfile {
        filename 'Dockerfile'
        args '-v /.cache/ -v /.bower/  -v /.config/configstore/'
      }
    }
    
  2. Укажите args '-v...' для создания томов для каталогов, необходимых для npm install/bower.

Ответ 1

из 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
    }
}

Ответ 2

Впустую целый день по этой проблеме, я просто добавил следующее как переменную среды на этапе агента, используя Редактор конвейера, устранил проблему.

'npm_config_cache=npm-cache'

Ответ 3

Добавление окружения и установка Home в '.' решает это, как показано ниже.

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

Ответ 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"
        }
    }
}

Ответ 5

Вы можете переопределить пользователя, с которым Jenkins запускает контейнер докера, например, здесь я переопределяю с помощью корня (userid: groupid равен 0: 0):

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

Вы можете определить текущего пользователя в параметрах docker run в выводе консоли.

Ответ 6

У нас была та же проблема, основной проблемой для нас было то, что пользователь в контейнере и пользователь, работающий с Jenkins node, имели разные UID. После изменения UID + GID пользователя в контейнере (и изменения владение домашним каталогом пользователей), чтобы соответствовать пользователь, выполняющий build node npm, будет вести себя нормально.

Это также может произойти, если Home-Directory контейнера-пользователя не может быть записана.

Код в файле Docker:

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 пользователь контейнера автоматически устанавливается в соответствии со строковым блоком. Но домашний каталог будет по-прежнему иметь своего первоначального владельца.

Теперь node_modules будет помещен в текущий каталог.

Ответ 7

В моем случае проблема заключалась в том, что внутри контейнера я был пользователем jenkins вместо root. Я получил это, установив whoami внутри контейнера, и получил ошибку, как будто cannot determine user 111 (который, как оказалось, является jenkins). Итак, я сделал следующее:

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

Ответ 8

Хотел просто предоставить немного больше деталей, короче говоря, принятый ответ работает, но я новичок в 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 работать правильно, мы просто указываем переменную окружения HOME для пользователя на текущую папку через файл Jenkins.

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

Таким образом, давая пользователю возможность создать необходимую .npm папку в /folder/forProject/.npm

Надеюсь, это кому-нибудь пригодится, и если вы видите что-то, что я ошибся, пожалуйста, дайте мне знать: D

Ответ 9

Вы можете установить 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

Ответ 10

эта конфигурация работает для меня.

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