Node.js の Docker イメージには node:20、node:20-slim、node:20-alpine といったバリエーションが存在する。 これらの違いに関する説明として最も適切なものはどれか。
解説
正解は「alpine は Alpine Linux + musl libc ベース、slim は Debian ベースから不要パッケージを削ったもの」です。タグ無し(node:20)は Debian ベースのフルイメージで、ビルドツールやデバッグユーティリティが一通り揃っています。slim は同じ Debian をベースにしつつ、man ページや開発ツールなど多くのパッケージを削ぎ落とした軽量版です。一方 alpine は Alpine Linux という別ディストリビューションをベースにしており、C 標準ライブラリも一般的な glibc ではなく musl libc を採用しています。選択肢Aは「両方とも Debian ベース」としていますが alpine は別ディストリビューションなので誤り。選択肢CのCPUアーキテクチャ説、選択肢Dの用途固定説もどちらも事実ではありません。イメージサイズの実際の違い各イメージのおおよそのサイズ感は以下の通りです(Node.js 20 系の場合):node:20 — 約 1GB 前後。ビルド環境がそのまま使えるnode:20-slim — 約 200MB 前後。Debian の使い勝手はそのままにスリム化node:20-alpine — 約 150MB 前後。最も軽量イメージが小さいほど pull が速く、レジストリのストレージ消費も減り、コンテナ起動も早くなります。ただし「小さければ正義」ではなく、後述する罠があります。alpine で踏みやすい musl libc の罠Node.js のパッケージには内部で C/C++ で書かれたネイティブモジュール(bcrypt、sharp、node-canvas など)を使うものがあります。これらは glibc 向けにビルドされたバイナリが prebuilt として配布されることが多く、musl libc の Alpine 上では動かずソースからのコンパイルが走ったり、最悪まったく動かないことがあります。「Alpine に変えたら CI が落ちた」「sharp が読み込めない」といったトラブルの多くはこれが原因です。実務でどう選ぶかプロダクションではマルチステージビルドと組み合わせるのが定石です。ビルドステージにはフル機能の node:20 を使ってネイティブモジュールをコンパイルし、最終ステージに node:20-slim や node:20-alpine を使って成果物だけコピーします:FROM node:20 AS builder WORKDIR /app COPY package*.json ./ RUN npm ci COPY . . RUN npm run build FROM node:20-slim WORKDIR /app COPY --from=builder /app/dist ./dist COPY --from=builder /app/node_modules ./node_modules CMD ['node', 'dist/index.js']迷ったらまず slim から始めるのが無難です。Debian ベースなのでネイティブモジュールの互換性問題が起きにくく、十分に軽量だからです。極限までサイズを削りたい、かつ依存ライブラリが musl で動作確認できている場合に alpine を選びます。