Open1

Docker の Node バージョンと、local の Nodeバージョンを合わせる必要はあるかどうか📝

まさぴょん🐱まさぴょん🐱

Docker の Node バージョンと、local の Nodeバージョンを合わせる必要はあるかどうか📝

結論から言うと 「絶対に同じにしなければ動かないわけではないが、node_modules をホストとコンテナで共有する場合は“ほぼ同じ(少なくともメジャーバージョンは一致)にしておくほうが安全” です。理由と対処方針を整理します。


1. 何が起こるか

ケース 影響 詳細
純粋な JS パッケージのみ
(ネイティブアドオンなし)
多少のバージョン差なら動くことが多い Node の ABI を使わないため。ただし package-lock.json の生成物が変わるので lock ファイルの差分が頻発する。
バイナリ/ネイティブアドオンを含むパッケージあり
(node-gyp, bcrypt, sharp など)
ほぼ確実に壊れる ホスト側でビルドされたネイティブコードは「Node の ABI version × OS × CPU」で固有。Docker(Linux) と macOS/Windows で食い違う or Node のメジャーが違うと読み込めない。
npm scripts で Node API を呼ぶ
(例: node --watch, ESM loader)
動作差・エラーの可能性 17→18 で --watch が入り、20 で ESM Loader 周りが変わる…など CLI オプション差異による失敗が起きる。

2. ベストプラクティス

  1. node_modules は基本的にコンテナ内で完結させる

    • 共有したいのはソースコードだけにし、node_modulespackage-lock.json の書き込み先は volume にマッピングしない。

    • 例:

      volumes:
        - ./:/app      # ソースだけ
        - /app/node_modules  # node_modules は匿名ボリューム(ホストに出さない)
      
  2. Node のバージョンを 1 か所で定義して合わせる

    • Dockerfile.nvmrc / .node-version を同じ値に。
    • チーム開発なら engines.nodepackage.json に書き、"engine-strict": true(npm)や volta を使うと揃えやすい。
  3. どうしても共有したい場合の最低条件

    • OS が同じ(例: WSL2 で Linux⇔Linux)
    • Node のメジャーバージョンが一致(ABI 互換を保てる)
    • それでもネイティブアドオンがあると壊れるので、npm rebuildnpm ci をコンテナ側で一度は実行する。

3. よくある運用フロー

# 1) ホストでソースを編集
# 2) コンテナへアタッチまたは docker compose exec
npm ci        # コンテナ内で依存をインストール
npm run dev   # コンテナ内で開発サーバー起動

こうしておけばコンテナが Node の実行環境を完全に担うため、ホストの Node は「エディタ補完や軽いスクリプト用」と割り切れます。


4. まとめ

  • lock ファイルのノイズを減らし、ネイティブアドオン事故を防ぐには「node_modules を共有しない」+「Node バージョンを揃える」 が鉄板。
  • もし共有するなら メジャーバージョン一致は必須、さらにコンテナ内で必ず npm rebuild して ABI を合わせる。