Dockerfileのnpm installエラー原因と解決策|ビルド・権限問題

Node.jsやReact、Next.js、TypeScriptなどのWebアプリケーションをDocker化する際、docker build(または docker compose build)の途中で RUN npm install や RUN npm ci のステップが赤字のエラーで止まってしまい、イメージのビルドが完了しないトラブルは開発現場で非常に多く発生します。

ローカルのPC(WindowsやMac)では問題なく npm install が通るにもかかわらず、Dockerfile 内でだけ失敗する理由は、「軽量なAlpineイメージにC++ビルドツールが入っていない」「ホスト側の node_modules がコンテナに混入している」「コンテナ内のユーザー権限(root と node)が衝突している」といったコンテナ環境特有の違いにあります。

この記事では、Dockerfile における npm install / npm ci エラーをエラーコード別に整理し、原因の特定から修正済みの実践的な Dockerfile テンプレートまでをわかりやすく解説します。

この記事で行うこと

  1. Dockerfile の npm install / npm ci で発生する主要エラーコードと解決策を早見表で確認する
  2. node:alpine イメージで頻発する node-gyp ビルドエラー(python3 / make / g++ 不足)の解決手順を解説する
  3. ホスト側の node_modules 混入によるバイナリ不整合エラーと .dockerignore の必須設定を解説する
  4. 依存関係の競合エラー(ERESOLVE)や npm ci 失敗時の対処法を説明する
  5. 権限エラー(EACCES: permission denied)を防ぐ WORKDIR と --chown・USER node の正しい書き方を解説する
  6. ネットワークタイムアウト(ETIMEDOUT / EAI_AGAIN)対策とBuildKitキャッシュマウントによる高速化手順を紹介する

前提条件・対象読者

項目内容
対象環境Docker Engine / Docker Compose v2 / WSL Containers(Windows 11・WSL2・macOS・Linux共通)
対象ベースイメージnode:20-alpine, node:22-alpine, node:22-bookworm-slim 等
最終確認日2026年10月19日
対象読者docker build 実行時に RUN npm install または RUN npm ci でエラーが出て困っている方

なお、Dockerfile の基本的な書き方や各命令(FROM、RUN、COPY、CMD)の基礎から復習したい方は、以下の入門ガイドもあわせて参考にしてください。

1. Dockerfileの npm install 失敗原因と解決策早見表

まずは、ビルドログに出力されている npm error(または npm ERR!)のコードから、該当する原因と解決策を一覧表で確認しましょう。

エラーコード・主なログ表示主な原因即効解決策
gyp ERR! find Python / not found: makenode:alpine 等の軽量イメージにネイティブアドオンのビルド用ツール(python3, make, g++)が入っていないRUN apk add --no-cache python3 make g++ を追加するか、node:slim ベースに変更する
invalid ELF header / Exec format errorWindowsやMacのホスト側にある node_modules がそのまま COPY . . でLinuxコンテナ内にコピーされ上書きされている.dockerignore ファイルを作成し、node_modules を除外リストに記載する
npm error code ERESOLVE (unable to resolve dependency tree)パッケージ間のPeer Dependencies(要求バージョン)が競合しており、npm v7以降の厳格チェックで停止している依存バージョンを揃えるか、RUN npm ci --legacy-peer-deps を指定する
npm ci can only install packages when your package.json and package-lock.json are in syncホスト側で package.json だけを編集し、package-lock.json が更新されていない(またはコピーし忘れている)ホスト側で一度 npm install を実行して package-lock.json を更新し、COPY package*.json ./ で両方コピーする
npm error code EACCES (permission denied, mkdir ...)USER node に切り替えた後、root 所有のディレクトリ(/app 等)に書き込もうとしている、またはグローバルインストール時の権限不足WORKDIR の所有権を chown -R node:node で変更し、COPY --chown=node:node を使用する
npm error code ETIMEDOUT / EAI_AGAINDockerコンテナ内のDNS名前解決エラー、またはレジストリ通信のタイムアウトDockerのDNS設定確認、および npm config set fetch-retries 5 やBuildKitキャッシュマウントを導入する

2. Alpineイメージ(node:alpine)で node-gyp ビルドエラーが出る場合の対処法

イメージサイズを小さくするために FROM node:22-alpine などのAlpine Linuxベースを選択した際、最も頻繁に遭遇するのが以下のような node-gyp 関連のビルドエラーです。

npm error gyp ERR! find Python
npm error gyp ERR! find Python Python is not set from command line or npm configuration
npm error gyp ERR! stack Error: Could not find any Python installation to use

または、以下のように make や g++ が見つからないというエラーが出ることもあります。

npm error gyp ERR! build error
npm error gyp ERR! stack Error: not found: make

原因:ネイティブモジュール(C/C++)のコンパイル環境がない

bcrypt、sqlite3、canvas、sharp(一部環境)、node-sass などのパッケージは、インストール時に環境に合わせてC/C++のソースコードをコンパイルする仕組み(node-gyp)を持っています。しかし、超軽量な alpine イメージには最初からは python3 や make、g++ といったコンパイラ群が含まれていないため、ビルドが失敗します。

解決策1:apk add でビルドツールを導入する

RUN npm install(または RUN npm ci)を実行する前の行に、Alpineのパッケージマネージャーである apk を使って python3、make、g++ をインストールする命令を追加します。

❌ 間違い例(ビルドツールがなく失敗する Dockerfile):

FROM node:22-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
CMD ["npm", "start"]

⭕ 正しい手順(ビルドツールを導入して成功させる Dockerfile):

FROM node:22-alpine
WORKDIR /app

# node-gyp のネイティブビルドに必要なパッケージをインストール
RUN apk add --no-cache python3 make g++

COPY package*.json ./
RUN npm ci
COPY . .
CMD ["npm", "start"]

解決策2:Debianベースの slim イメージ(node:22-bookworm-slim)へ切り替える

Alpine Linuxは標準Cライブラリとして glibc ではなく musl libc を採用しているため、パッケージによっては事前ビルド済みバイナリ(Prebuilt binary)が提供されておらず、毎回時間のかかるソースコンパイルが走ってしまいます。

もしビルド時間の短縮や高い互換性を優先する場合は、ベースイメージを node:22-bookworm-slim(Debianの軽量版)に変更するだけで、事前ビルド済みバイナリがそのままダウンロードされ、python3 等を入れなくてもエラーなく高速に通過するケースが多くあります。

FROM node:22-bookworm-slim
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
CMD ["npm", "start"]

3. ホスト側の node_modules 混入によるエラーと .dockerignore の必須設定

Dockerfile の中で先に RUN npm ci が成功しているように見えるのに、その後のビルド処理(npm run build)やコンテナ起動時に invalid ELF header や Exec format error、Cannot find module といった不可解なエラーが出ることがあります。

原因:COPY . . でホストPCの node_modules を上書きコピーしている

Dockerfile で以下の順番に命令を書いている場合を見てみましょう。

COPY package*.json ./
RUN npm ci
COPY . .

このとき、プロジェクトフォルダに .dockerignore ファイルが存在しないと、3行目の COPY . . を実行した瞬間に、ホストPC(WindowsやMac)で作られた node_modules フォルダがコンテナ内に丸ごとコピーされ、せっかく2行目の RUN npm ci で作ったLinux用の node_modules を上書きして破壊してしまいます。

解決策:.dockerignore を作成して node_modules を除外する

Dockerfile と同じ階層(ビルドコンテキストのルート)に .dockerignore という名前のファイルを作成し、以下の内容を記述します。

node_modules
npm-debug.log*
.git
.gitignore
.env
.env.*
dist
build
.next

これによって、ホスト側の node_modules がDockerデーモンへ転送されなくなり、OS間のバイナリ不整合エラーが完全に解消されるだけでなく、docker build の開始速度も大幅に向上します。

4. 依存関係の競合エラー(ERESOLVE)と package-lock.json 不整合の対処法

ケース1:ERESOLVE unable to resolve dependency tree が出る場合

Reactのバージョンアップ直後や、古いUIライブラリを併用しているプロジェクトでは、以下のような依存関係ツリー解決エラーが出ることがあります。

npm error code ERESOLVE
npm error ERESOLVE unable to resolve dependency tree
npm error Found: react@19.0.0
npm error Could not resolve dependency:
npm error peer react@"^18.0.0" from some-ui-library@2.1.0

ローカル環境では以前に --legacy-peer-deps を付けてインストールしていたり、古いバージョンの npm を使っていたりすると、コンテナ内の新しい npm で厳格に弾かれます。

根本的にはパッケージのバージョンを揃えるか package.json の overrides フィールドで解決するのが理想ですが、ビルドを通す必要がある場合は Dockerfile 側のコマンドに --legacy-peer-deps を明示します。

RUN npm ci --legacy-peer-deps

ケース2:npm ci で package.json と package-lock.json の不一致エラーが出る場合

Dockerビルドでは、再現性を担保するために npm install ではなく npm ci を使うのがベストプラクティスですが、以下のエラーで止まることがあります。

npm error `npm ci` can only install packages when your package.json and package-lock.json or npm-shrinkwrap.json are in sync.

このエラーが出た場合は、以下の2点を確認してください。

  1. Dockerfile 内で COPY package.json ./ とだけ書いており、package-lock.json をコピーし忘れていないか確認し、必ず COPY package*.json ./ と記述する。
  2. ホスト側で手動で package.json のバージョンを書き換えたままになっている場合は、ホスト側のターミナルで一度 npm install を実行して package-lock.json を最新状態に更新してから、再度 docker build を実行する。

5. 権限エラー(EACCES: permission denied)が出る原因と正しい権限設定

セキュリティ強化のためにコンテナ内の実行ユーザーをデフォルトの root から一般ユーザーである node(UID 1000)に切り替えた際、npm install やキャッシュ作成時に以下の権限エラーが発生することがあります。

npm error code EACCES
npm error syscall mkdir
npm error path /app/node_modules
npm error errno -13
npm error Error: EACCES: permission denied, mkdir '/app/node_modules'

原因:WORKDIR が root 所有のままになっている

Dockerfile の WORKDIR /app 命令で新しくディレクトリが自動作成された場合、そのディレクトリの所有者は root になります。その状態で USER node に切り替えて COPY や RUN npm ci を実行すると、node ユーザーには /app への書き込み権限がないため EACCES エラーとなります。

解決策:ディレクトリ所有権の付与と COPY –chown=node:node を使う

❌ 間違い例(/app が root 所有のまま USER node になり失敗する例):

FROM node:22-bookworm-slim
WORKDIR /app
USER node
COPY package*.json ./
RUN npm ci

⭕ 正しい手順(chown と --chown=node:node を組み合わせた安全な設定):

FROM node:22-bookworm-slim

# 作業ディレクトリを作成し、所有者を node ユーザーに変更する
WORKDIR /app
RUN chown -R node:node /app

# ここで一般ユーザー node に切り替える
USER node

# ファイルコピー時も所有者を node:node に指定する
COPY --chown=node:node package*.json ./
RUN npm ci

COPY --chown=node:node . .
CMD ["node", "index.js"]

なお、pm2 や typescript、nestjs/cli などを npm install -g でグローバルインストールする必要がある場合は、USER node に切り替える前(root 権限の段階)に実行しておくことで権限エラーを回避できます。

6. ネットワークエラー(ETIMEDOUT / EAI_AGAIN)とキャッシュ高速化

社内ネットワークやWSL2上のDockerで、パッケージ数が数百個あるプロジェクトをビルドすると、npm error network や ETIMEDOUT、EAI_AGAIN で途中失敗することがあります。

解決策:リトライ設定の追加とBuildKitキャッシュマウントの活用

Docker BuildKitのキャッシュマウント機能(--mount=type=cache)と、通信リトライ設定を組み合わせることで、一時的なネットワーク瞬断に強くなり、2回目以降のビルド速度も劇的に高速化します。

# syntax=docker/dockerfile:1
FROM node:22-bookworm-slim
WORKDIR /app

COPY package*.json ./

# BuildKitのキャッシュマウントを活用し、通信タイムアウト対策のパラメータを付与
RUN --mount=type=cache,target=/root/.npm \
    npm config set fetch-retries 5 && \
    npm config set fetch-retry-mintimeout 20000 && \
    npm config set fetch-retry-maxtimeout 120000 && \
    npm ci

※もし EAI_AGAIN(DNSの名前解決失敗)が毎回即座に発生する場合は、npm ではなくDocker自体のDNS設定(/etc/resolv.conf)が原因です。その場合の解決手順は 【解決】Docker apt-get「Temporary failure resolving」の原因と対処法 で詳しく解説しています。

7. まとめ:エラーを防ぐ実践 Dockerfile テンプレート

最後に、ここまで解説した「ネイティブビルド対応」「キャッシュ効率化」「非root権限での安全な実行」をすべて満たした、実務でそのまま使えるマルチステージビルドの Dockerfile テンプレートを紹介します。

# syntax=docker/dockerfile:1

# --- ステージ1:依存関係のインストールとビルド ---
FROM node:22-bookworm-slim AS builder
WORKDIR /app

# ネイティブアドオン(node-gyp)が必要な場合のみ以下のコメントアウトを解除
# RUN apt-get update && apt-get install -y --no-install-recommends python3 make g++ && rm -rf /var/lib/apt/lists/*

COPY package*.json ./
RUN --mount=type=cache,target=/root/.npm \
    npm ci

COPY . .
RUN npm run build

# --- ステージ2:本番実行用の軽量イメージ ---
FROM node:22-bookworm-slim AS runner
WORKDIR /app
ENV NODE_ENV=production

# ディレクトリの所有権を node ユーザーに設定
RUN chown -R node:node /app
USER node

COPY --chown=node:node package*.json ./
RUN --mount=type=cache,target=/home/node/.npm,uid=1000,gid=1000 \
    npm ci --omit=dev

# ビルド成果物のみをステージ1からコピー
COPY --from=builder --chown=node:node /app/dist ./dist

EXPOSE 3000
CMD ["node", "dist/index.js"]

Dockerfile での npm install エラーは、まず「.dockerignore に node_modules が入っているか」「package-lock.json が同期されているか」「Alpineイメージでビルドツールが不足していないか」の3点をチェックするだけで9割以上が解決します。ぜひお手元のプロジェクトと見比べてみてください。

次に読むおすすめ記事

DockerおよびWSL2を使ったWindows開発環境の全体構築や、Docker Compose v2の実践コマンド集は以下の記事で詳しくまとめています。

参考情報