【3-3.5】NginxとNode.jsでDockerfileの書き方が違うのはなぜ?
NginxとNode.jsでDockerfileの書き方が違うのはなぜ?
はじめに
前回の記事では、静的なHTMLを配信するNginxイメージと、Node.jsアプリケーションのイメージを作成しました。 その際、2つのDockerfileの書き方が大きく異なっていることに気づいたかと思います。
- Nginx: ベースイメージにCOPY命令でHTMLファイルを配置するだけと非常にシンプル
-
Node.js: WORKDIRの設定や
npm installの実行など、複数のステップが必要
この違いはどこから来るのでしょうか?
本記事ではその根本的な理由である、プログラムの実行方式の違いに焦点を当てて解説します。この点を理解することで、様々なアプリケーションをDocker化する際のDockerfile設計が、より深く理解できるようになります。
結論:なぜDockerfileの書き方が違うのか
結論から言うと、その違いはOS (Operating System) がそのプログラムを直接実行できるか否かに起因します。
- Nginx: コンパイルされたアプリケーションであり、OSが直接実行できる
- Node.js アプリ (app.js): スクリプトであり、OSが直接実行できない。そのため、通訳役の実行環境 (Node.js) が必要になる
以下で、それぞれを詳しく見ていきましょう。
1. Nginx:OSが直接実行できる「コンパイル済みアプリケーション」
Nginxは、C言語のようなコンパイラ言語で開発されています。
コンパイラ言語のプログラムは、開発の最終段階でコンパイルという処理が行われます。これは、人間が書いたソースコードを、コンピュータのCPUが直接理解できる機械語(マシンコード) に一括で翻訳する作業です。
この翻訳済みのファイル(Windowsなら .exe ファイルのようなもの)は、OSにとって非常に扱いやすいものです。OSは、このファイルを実行するだけで、WebサーバーとしてのNginxを起動できます。
これをDockerfileに当てはめてみましょう
FROM nginx:alpineで指定したイメージには、このコンパイル済みのNginx本体がすでに入っています。
そのため、私たちがDockerfileで行うべき作業は非常にシンプルです。
- 完成品のNginxプログラムが参照するディレクトリ(
/usr/share/nginx/html)を調べる - そこに、表示させたいコンテンツ(
index.html)をCOPY命令で配置する
私たちは、すでに完成しているアプリケーションに対して、設定やコンテンツを追加しているだけなのです。
2. Node.js:実行環境が必要な「スクリプト」
一方、私たちが書いたapp.jsはJavaScriptという言語で書かれています。JavaScriptはインタプリタ言語(またはスクリプト言語) に分類されます。
こちらのプログラムは、事前に機械語へ翻訳されません。app.jsは、あくまで人間が読めるテキストファイルのままです。当然、OSはこのテキストファイルの中身を直接解釈して実行することはできません。
そこで必要になるのが、実行環境(Runtime Environment) です。
実行環境は、スクリプトのコードを1行ずつ読み込み、それをその場で解釈しながら、OSが理解できる命令へと変換してくれる通訳プログラムの役割を果たします。サーバーサイドJavaScriptにおける、その実行環境がNode.jsです。
これをDockerfileに当てはめると、各命令の意味が明確になります
FROM node:18-alpine は、完成したWebサーバーを呼び出しているのではありません。これは、JavaScriptの通訳プログラムである「Node.js」そのものをインストールしているのです。
この「Node.js」という土台の上に、私たちのアプリケーションを構築していく必要があります。
-
WORKDIR /app: アプリケーションを構築する作業場所を準備します -
COPY package.json . / RUN npm install: アプリ(app.js)が必要とする追加部品(expressライブラリ)を、Node.jsに付属するnpmというツールでインストールさせます -
COPY . .: メインの設計図であるapp.jsを配置します -
CMD ["npm", "start"]: 最後に、「Node.jsよ、このapp.jsを通訳・実行して、Webサーバーを起動しなさい」と命令しています
このように、Node.jsのDockerfileは、アプリケーションを動かすための環境を構築し、その上でスクリプトを実行するというプロセスを定義しているのです。
まとめ:両者の違いが一目でわかる比較表
| 項目 | Nginxの例 | Node.jsの例 |
|---|---|---|
| プログラムの種類 | コンパイル済みアプリケーション | スクリプト + 実行環境 |
| OSによる実行 | 直接実行できる | Node.jsを介して間接的に実行 |
| イメージの核となるもの | Nginxという完成品プログラム | Node.jsという実行環境 |
| Dockerfileの役割 | 完成品にコンテンツを配置・設定する | 実行環境を整え、アプリを構築・実行する |
この根本的な違いを理解することで、「なぜこのRUN命令が必要なのか」「なぜCOPYを2回に分けるのか」といったDockerfileのベストプラクティスに対する理解も、一層深まるはずです。
Dockerの強力な点は、こうした実行方式が全く異なるアプリケーションでも、それぞれの「実行環境」ごとコンテナにパッケージ化することで、どんな環境でも同じように動かせる点にあります。
Discussion