nodeにgulpやらbabelやらonsen-uiやら大量にインポートしたサーバーアプリケーション。
いままでVagrantで動いていたこの環境を、Dockerコンテナ化するタスクを受けました。
加えてマルチOS(Windows, Mac, Linux)で動作する必要があります。
現状
- ルートディレクトリに package.json は残っていました。
- /node_modules はありませんでした。
(そもそも、違う環境の /node_modules は(環境依存モジュールが有る可能性があるので)流用する気はないですけれども)
package.json をたよりに npm install を実行してみた
- Mac ... 動いた。
- Linux ... 動いた。
- Windows ... 全然動かない。
npm ERR! code ENOENT
npm ERR! syscall open
npm ERR! path /xxxxxxxxxxx/xxxxxxxxxxx/xxxxxxxxxxx
npm ERR! errno -2
npm ERR! enoent ENOENT: no such file or directory, open '/xxxxxxxxxxx/xxxxxxxxxxx/xxxxxxxxxxx'
...
npm ERR! Maximum call stack size exceeded
"Failed to load external module @babel/register"
これらのエラーが途中で無秩序に発生します。
上記3種のエラーが出て止まればまだマシな方で、最悪、Docker Desktopがハングアップします。
なおコマンドインターフェース上のプログレス表示の傾向としては、
- 最初は快速にnpm installが進行していきますが、
- だんだん遅くなり、
- やがてハングアップします。
現象の傾向から、メモリリークを大リファクタリングした昔の仕事をなんとなく思い出しました。
トライアンドエラー
ネット上には一見似たような事例が散見されるのですが、
- npm install --no-bin-links
- rm -f package-lock.json
- docker desktopの性能設定を上げる
- npm cache clean --force
- .npmignore を作る
- npm rebuild
- npm config set registry http://registry.npmjs.org/
- package.jsonをすべて手書きのnpm installにする
これらを全部やってみましたが、ダメでした。
結果的対処方法
割と泥臭い対応で対応しました。
- docker-nodeコンテナのワークディレクトリをdocker-compose.ymlなどでvolumeマウントしておく。
- コンテナの中のシェルにログオンする。
- /node_modules は絶対削除せずに、何度も
npm install
する。(コンテナの外から直接docker-compose exec
でnpm install
を実行しない) - インストール済のモジュールは飛ばされるので、徐々に/node_modulesの中身が充足していきます。
- 完成した /node_modules を(volumeマウント経由でdockerコンテナから確保し、)/windows_node_modules などとして確保しておく。
- ビルドスクリプトを修正し、次回からは npm install を実行させるのではなく、/windows_node_modules を
mv windows_node_modules node_modules
で済ませるようにする。