可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
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).
Changed agent to use a Dockefile:
agent {
dockerfile {
filename 'Dockerfile'
args '-v /.cache/ -v /.bower/ -v /.config/configstore/'
}
}
Specify args '-v ...'
for creating volumes for the directories npm install / bower needs.
回答1:
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
}
}
回答2:
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'
回答3:
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"
}
}
}
}
回答4:
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"
}
}
}
回答5:
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.
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.
This might also happen if the Home-Directory of the container-user is not writeable.
Code in the 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. When running the container through the Jenkinsfile the UID and GID of
the container user are set automatically to match the buildnode. But the home directory will still have its original owner.
Now the node_modules will be placed in the current directory.
回答6:
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.
回答7:
In my case the problem was that inside the container I was user jenkins instead of root. I got there by setting whoami
inside the container and got error like cannot determine user 111
(which happens to be jenkins). So I did the following:
stage('Run build') {
webappImage.inside("-u root") {
sh "yarn run build"
}
}
回答8:
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.
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
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.
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?). 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
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
Hopefully this is helpful to someone and if you see something that i got wrong please let me know :D
回答9:
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