codekitchen / dinghy

faster, friendlier Docker on OS X. Deprecated.
MIT License
2.12k stars 109 forks source link

npm throws Operation not permitted #17

Closed haggen closed 9 years ago

haggen commented 9 years ago

Using dinghy, when I try to npm install something, it complains:

npm ERR! Error: EPERM, chown '/shared/node_modules/gulp/package.json'
npm ERR!  { [Error: EPERM, chown '/shared/node_modules/gulp/package.json']
npm ERR!   errno: 50,
npm ERR!   code: 'EPERM',
npm ERR!   path: '/shared/node_modules/gulp/package.json',
npm ERR!   fstream_finish_call: 'chown',
npm ERR!   fstream_type: 'File',
npm ERR!   fstream_path: '/shared/node_modules/gulp/package.json',
npm ERR!   fstream_class: 'FileWriter',
npm ERR!   fstream_stack: 
npm ERR!    [ '/usr/lib/nodejs/fstream/lib/writer.js:305:19',
npm ERR!      '/usr/lib/nodejs/graceful-fs/polyfills.js:143:7',
npm ERR!      'Object.oncomplete (evalmachine.<anonymous>:107:15)' ] }
npm ERR! 
npm ERR! Please try running this command again as root/Administrator.

npm ERR! System Linux 3.18.11-tinycore64
npm ERR! command "/usr/bin/nodejs" "/usr/bin/npm" "install" "gulp"
npm ERR! cwd /shared
npm ERR! node -v v0.10.29
npm ERR! npm -v 1.4.21
npm ERR! path /shared/node_modules/gulp/package.json
npm ERR! fstream_path /shared/node_modules/gulp/package.json
npm ERR! fstream_type File
npm ERR! fstream_class FileWriter
npm ERR! fstream_finish_call chown
npm ERR! code EPERM
npm ERR! errno 50
npm ERR! stack Error: EPERM, chown '/shared/node_modules/gulp/package.json'
npm ERR! fstream_stack /usr/lib/nodejs/fstream/lib/writer.js:305:19
npm ERR! fstream_stack /usr/lib/nodejs/graceful-fs/polyfills.js:143:7
npm ERR! fstream_stack Object.oncomplete (evalmachine.<anonymous>:107:15)
npm ERR! 
npm ERR! Additional logging details can be found in:
npm ERR!     /shared/npm-debug.log
npm ERR! not ok code 0

It used to work well on boot2docker, even when using nfs.

codekitchen commented 9 years ago

hm I don't know why npm install would be trying to chown this file, but I can give you some background on why it's failing: dinghy configures the NFS volume to "squash" all files to be owned by your user on the host OSX machine. It didn't originally, it ran NFS operations as root on the host machine, this change was discussed in https://github.com/codekitchen/dinghy/issues/15

The consequence of this is that you aren't writing to the NFS share as root, and you typically won't have permission to chown files. Ideally, I'd love to be able to configure the NFS share to just ignore chown commands, like virtualbox built-in file shares do, but that isn't possible without modifications to the NFS server code.

As far as your specific problem, is the npm install running as root? If so, modifying your container to run as a non-root user would potentially fix the issue.

I wouldn't be totally opposed to a configuration setting to let you choose whether dinghy enables root squashing or not, since both have their advantages.

haggen commented 9 years ago

Hey @codekitchen thanks a lot for the heads up! I'm going to try changing the container user later and report back to you.

0ff commented 9 years ago

Had the exact same problem running wercker, as I don't know how to configure it to not run as root inside the box, I have added a new step right before npm install is run, that would solve my problem (effectively running npm installas my host's user):

    # NOTE: you might want to adjust the uid and gid values for your user
    - script:
        name: downgrade to mac user
        code: |
          useradd -u 501 -g 20 wercker
          mkdir /home/wercker
          /usr/bin/sudo -u wercker -s
          export HOME=/home/wercker
codekitchen commented 9 years ago

@haggen I'm going to close this, let me know of you're still hitting issues.

MrMMorris commented 9 years ago

@haggen I actually just hit a similar issue and wanted to share my solution.

I have a nodejs app. I run it in a nginx container as it is just static site code built with nodjs. Because of this, developers can't just attach to the container and run npm because it's not actually installed. What happens when you need to update a module?

Well, I run a separate container that is the official node image. I mount my local git repo into it and then I can run npm command inside the container. Great! but then I run into your issue:

Error: EPERM, chown '/app/node_modules/watchify/package.json'

I don't want to have to mess around with starting a container, mounting the repo, adding users/changing permissions, I want it automated! So this is what I came up with:

docker run --rm -u $UID -it -w /app -v $PWD /client/container/npm:/.npm -v $PWD:/app node:0.10-slim npm install watchify@3.3.1 --save

-u sets the uid of the user running the container to my local uid which means that I don't run into Error: EPERM, chown

the first -v is specific to my case because npm wants to create a /.npm folder. You may not need it depending on if you keep a .npm folder in your repo, but if you do, just have a empty npm directory in your local repo that you can mount to /.npm (-v can't mount dotfiles as it doesn't have permission to view them)

the second -v mounts everything in my local repo to /app so that my changes show up in my local repo even after the container is gone

-w just sets the WORKDIR

This essentially is a containerized way of running commands so you don't need to install something like nodejs and npm on your local. You could take it one step further and use the docker run command as an alias or make task.

Hope this can help someone

markshust commented 9 years ago

This still does appear to be an issue. I worked around it by doing something like the following:

  echo "Installing node modules..."
  cp /src/package.json /root/
  cd /root && npm install -q
  echo "Node modules installed. Syncing back to /src/node_modules..."
  rsync -rlzuIO --ignore-errors /root/node_modules/ /src/node_modules > /dev/null 2>&1
  rm -rf /root/node_modules /root/package.json
ryanmt commented 8 years ago

Switching user in the Dockerfile to a non-root user fixed it for me.

kilpatty commented 8 years ago

@ryanmt How were you able to switch the user to a non-root user in the Dockerfile?

MrMMorris commented 8 years ago

@Skilgarriff https://docs.docker.com/engine/reference/builder/#user?

kilpatty commented 8 years ago

@MrMMorriss I attempted that, but I'm now getting an even uglier exit than before. Still getting 'chown permission denied, Please try running as root' on npm install

ryanmt commented 8 years ago

@Skilgarriff USER is the command. I've often seen prerequisite useradd steps, and it might be necessary to run a chown before the npm install.

kilpatty commented 8 years ago

@ryanmt Turns out it was an issue with maproot. Dinghy does not map the root to 0 which causes some issues when trying to run any privileged command when trying to use that command on Volumes mounted with NFS.

wchrisjohnson commented 8 years ago

More background on this issue: https://github.com/docker/machine/issues/1817 I'm specifically hitting this issue ATM with npm and it's looking like I'm going to have to use virtual box ... ;-(

trakos commented 8 years ago

There's a comment here: https://github.com/npm/npm/issues/3565#issuecomment-202473011 showing a nice way to overcome that - you can make chmod do nothing by using LD_PRELOAD.

You can do it for the entire container in Dockerfile. First make sure you've gcc installed, and then add:

RUN echo "int chown() { return 0; }" > preload.c && gcc -shared -o /libpreload.so preload.c && rm preload.c
ENV LD_PRELOAD=/libpreload.so

This simply makes chmod think it actually did something and succeed, so npm is all happy and confident it did a good job.

You can also do it just for one command - just call npm install this way (again, you need gcc):

echo "int chown() { return 0; }" > preload.c && gcc -shared -o preload.so preload.c && LD_PRELOAD=$PWD/preload.so npm install && rm preload.c preload.so
TomFrost commented 8 years ago

This is driving me nuts. In our dev environments, my team mounts their home folder to /root due to needing access to the NPM login token, AWS credentials, shared NPM cache, etc stored there. This worked well with docker implementations where root took ownership of new files (we've used dlite with success in the past, but lack of maintenance is making that one tough to use now). Under dinghy's model of setting root to use the executing user/group's access levels, I get this every time I NPM install, even if I delete ~/.npm first:

npm ERR! Error: EPERM: operation not permitted, chown '/root/.npm/_locks'
npm ERR!     at Error (native)
npm ERR!  { Error: EPERM: operation not permitted, chown '/root/.npm/_locks'
npm ERR!     at Error (native)
npm ERR!   errno: -1,
npm ERR!   code: 'EPERM',
npm ERR!   syscall: 'chown',
npm ERR!   path: '/root/.npm/_locks' }
npm ERR!
npm ERR! Please try running this command again as root/Administrator.
npm ERR! Linux 4.4.17-boot2docker
npm ERR! argv "/usr/bin/node" "/usr/bin/npm" "install" "-g" "node-gyp"
npm ERR! node v6.3.1
npm ERR! npm  v3.10.5
npm ERR! path npm-debug.log.737059936
npm ERR! code EACCES
npm ERR! errno -13
npm ERR! syscall open

So I did a code-dive and discovered the :custom_nfs_export_options preference. "Eureka!" I thought. So I popped open my system's /etc/exports and grabbed this line that dlite injected: /Users -network 192.168.64.0 -mask 255.255.255.0 -alldirs -maproot=root:wheel and converted that to what it looked like dinghy's bundled NFS needed. I ended up with these prefs:

---
:preferences:
  :proxy_disabled: false
  :fsevents_disabled: false
  :create:
    provider: xhyve
  :custom_nfs_export_options: rw,alldirs,maproot=root:wheel

After a dinghy restart, I confirmed that my machine-nfs-exports-dinghy file had the appropriate settings. Hurrah!

...but my in-container npm install still failed. I got the same error as before, and this one:

npm ERR! Error: EACCES: permission denied, open 'npm-debug.log.737059936'
npm ERR!     at Error (native)
npm ERR!  { Error: EACCES: permission denied, open 'npm-debug.log.737059936'
npm ERR!     at Error (native)
npm ERR!   errno: -13,
npm ERR!   code: 'EACCES',
npm ERR!   syscall: 'open',
npm ERR!   path: 'npm-debug.log.737059936' }
npm ERR!
npm ERR! Please try running this command again as root/Administrator.

I really, really do not want to do the chown hack mentioned above if there's an nfs configuration that can restore the old functionality. Any idea why my solution didn't take care of this?

EDIT: Neeeevermind. Rather than maproot=root:wheel, I did anonuid=0,anongid=0. Worked like a charm. I don't get the dinghy fanciness of keeping everything under my local user's ownership, but at least my native npm modules build now.

luctus commented 7 years ago

I'm using the passenger-ruby22 base image and I had this line in my Dockerfile:

RUN bower install --allow-root --config.interactive=false --verbose --force

which was giving me that error. I fixed it setting the user to someone different than root, as follows:

RUN setuser app bower install --allow-root --config.interactive=false --verbose --force

(The app user is the user that comes with my base image)

Carl-Meyer commented 5 years ago

This is driving me nuts. In our dev environments, my team mounts their home folder to /root due to needing access to the NPM login token, AWS credentials, shared NPM cache, etc stored there. This worked well with docker implementations where root took ownership of new files (we've used dlite with success in the past, but lack of maintenance is making that one tough to use now). Under dinghy's model of setting root to use the executing user/group's access levels, I get this every time I NPM install, even if I delete ~/.npm first:

npm ERR! Error: EPERM: operation not permitted, chown '/root/.npm/_locks'
npm ERR!     at Error (native)
npm ERR!  { Error: EPERM: operation not permitted, chown '/root/.npm/_locks'
npm ERR!     at Error (native)
npm ERR!   errno: -1,
npm ERR!   code: 'EPERM',
npm ERR!   syscall: 'chown',
npm ERR!   path: '/root/.npm/_locks' }
npm ERR!
npm ERR! Please try running this command again as root/Administrator.
npm ERR! Linux 4.4.17-boot2docker
npm ERR! argv "/usr/bin/node" "/usr/bin/npm" "install" "-g" "node-gyp"
npm ERR! node v6.3.1
npm ERR! npm  v3.10.5
npm ERR! path npm-debug.log.737059936
npm ERR! code EACCES
npm ERR! errno -13
npm ERR! syscall open

So I did a code-dive and discovered the :custom_nfs_export_options preference. "Eureka!" I thought. So I popped open my system's /etc/exports and grabbed this line that dlite injected: /Users -network 192.168.64.0 -mask 255.255.255.0 -alldirs -maproot=root:wheel and converted that to what it looked like dinghy's bundled NFS needed. I ended up with these prefs:

---
:preferences:
  :proxy_disabled: false
  :fsevents_disabled: false
  :create:
    provider: xhyve
  :custom_nfs_export_options: rw,alldirs,maproot=root:wheel

After a dinghy restart, I confirmed that my machine-nfs-exports-dinghy file had the appropriate settings. Hurrah!

...but my in-container npm install still failed. I got the same error as before, and this one:

npm ERR! Error: EACCES: permission denied, open 'npm-debug.log.737059936'
npm ERR!     at Error (native)
npm ERR!  { Error: EACCES: permission denied, open 'npm-debug.log.737059936'
npm ERR!     at Error (native)
npm ERR!   errno: -13,
npm ERR!   code: 'EACCES',
npm ERR!   syscall: 'open',
npm ERR!   path: 'npm-debug.log.737059936' }
npm ERR!
npm ERR! Please try running this command again as root/Administrator.

I really, really do not want to do the chown hack mentioned above if there's an nfs configuration that can restore the old functionality. Any idea why my solution didn't take care of this?

EDIT: Neeeevermind. Rather than maproot=root:wheel, I did anonuid=0,anongid=0. Worked like a charm. I don't get the dinghy fanciness of keeping everything under my local user's ownership, but at least my native npm modules build now.

Thank you so much! This helped me solve this problem as well!