Posted at

Docker 内部で npm run すると EXDEV を返され通らなくなる問題の解決方法

More than 3 years have passed since last update.

https://github.com/npm/npm/issues/9863


問題

docker build の中で npm install すると、下記のようなエラーが出て ret val != 0 となりコケる。

npm ERR! EXDEV: cross-device link not permitted, rename '/usr/local/lib/node_modules/npm' -> '/usr/local/lib/node_modules/.npm.DELETE'

上記は npm の例ですが、各所で発生し、阿鼻叫喚になっていた。

冒頭の github issues の長さでお察し


解決方法

Dockerfile 内に下記を記載

RUN cd $(npm root -g)/npm \

&& npm install fs-extra \
&& sed -i -e s/graceful-fs/fs-extra/ -e s/fs\.rename/fs.move/ ./lib/utils/rename.js


原因

ここまでわかっている模様


  • (docker の)aufs に固有の問題

  • aufs では多くの子レイヤがあるため、ディレクトリの rename が難しい(すべての子レイヤから探しだして、変更しないといけない。 inode の rename も含む)。この操作はコスト高で、 aufs は実行することを(たまに)拒否して、 EXDEV を返す。

  • EXDEV での copy/unlink の実行は、まあ、なんとかなる。

  • fs.extra と fs-extra は EXDEV での copy にフォールバックする。このため、不幸にも上記に引っかかる。

  • copy/unlink にフォールバックする代わりに、 mkdir/rename を再帰的に実行することができる。この処理は atomic ではなくなってしまう。これで十分かな?奇妙な npm の競合状況に出くわしたことがないので確かではないですが・・・


おしまい

上記の通り、 atomic ではなくなってしまいますが、ほとんどのケースではうまくいくだろうとのことです。