Node.js Web アプリケーションを Docker 化する

この例の目的は、Node.js アプリケーションを Docker コンテナに取り込む方法を説明することです。 このガイドは開発を目的としており、 本番展開を目的としていません。 このガイドでは、正常に Docker がインストールされ、 Node.js アプリケーションがどのように構成されているかについての基本的な知識があることも前提としています。

このガイドの最初の部分では、Node.js で単純な Web アプリケーションを作成してから、 そのアプリケーション用の Docker イメージを作成し、 最後にそのイメージをコンテナとして実行します。

Docker を使用すると、ソフトウェア開発用に、コンテナと呼ばれる標準化された単位に すべての依存関係を持つアプリケーションをパッケージ化できます。 コンテナは、Linux オペレーティングシステムの基本バージョンを削除したものです。 イメージはコンテナにロードするソフトウェアです。

Node.js アプリケーションを作成する

まず、すべてのファイルを配置する新しいディレクトリを作成します。 このディレクトリにあなたのアプリケーションとその依存関係を記述する package.json ファイルを作成してください:

{
  "name": "docker_web_app",
  "version": "1.0.0",
  "description": "Node.js on Docker",
  "author": "First Last <first.last@example.com>",
  "main": "server.js",
  "scripts": {
    "start": "node server.js"
  },
  "dependencies": {
    "express": "^4.16.1"
  }
}

新しい package.json ファイルを使って、npm install を実行してください。 バージョン 5 以降の npm を使っているなら、 これは Docker イメージにコピーされる package-lock.json ファイルを生成します。

それから、Express.js フレームワークを使って Web アプリケーションを定義する server.js ファイルを作成します。

'use strict';

const express = require('express');

// Constants
const PORT = 8080;
const HOST = '0.0.0.0';

// App
const app = express();
app.get('/', (req, res) => {
  res.send('Hello World');
});

app.listen(PORT, HOST, () => {
  console.log(`Running on http://${HOST}:${PORT}`);
});

次のステップでは、公式の Docker イメージを使用して Docker コンテナ内でこのアプリケーションを実行する方法を見ていきます。 まず、アプリケーションの Docker イメージを作成する必要があります。

Dockerfile を作成する

Dockerfile という名前の空のファイルを作ります。

touch Dockerfile

お気に入りのテキストエディタで Dockerfile を開きます

最初にしなければならないことは、どのイメージから構築したいかを定義することです。 ここではDocker Hubから入手できる node の最新の LTS (long term support) バージョン 12 を使います。

FROM node:12

次に、イメージ内にアプリケーションコードを入れるディレクトリを作成します。 アプリケーションの作業ディレクトリになります。

# アプリケーションディレクトリを作成する
WORKDIR /usr/src/app

このイメージには Node.js と NPM が既にインストールされていますので、 次に必要な作業は npm バイナリを使ってアプリケーションの依存関係をインストールすることです。 npm バージョン 4 以前を使用している場合、 package-lock.json ファイルは生成されないことに注意してください。

# アプリケーションの依存関係をインストールする
# ワイルドカードを使用して、package.json と package-lock.json の両方が確実にコピーされるようにします。
# 可能であれば (npm@5+)
COPY package*.json ./

RUN npm install
# 本番用にコードを作成している場合
# RUN npm install --only=production

作業ディレクトリ全体をコピーするのではなく、 package.json ファイルだけをコピーしていることに注意してください。 これにより、キャッシュされた Docker レイヤーを利用することができます。 bitJudo はこのことについてよく説明しています。

アプリケーションのソースコードを Docker イメージ内にバンドルするには、COPY 命令を使います。

# アプリケーションのソースをバンドルする
COPY . .

アプリケーションは 8080 ポートにバインドされているので EXPOSE 命令を使って docker デーモンによってマッピングされるでしょう:

EXPOSE 8080

最後に重要なことを言い忘れましたが、ランタイムを定義する CMD を使ってアプリケーションを実行するためのコマンドを定義してください。 ここでサーバを起動するために node server.js を実行する 基本的な npm start を使います:

CMD [ "node", "server.js" ]

Dockerfile はこのようになっているはずです。

FROM node:12

# アプリケーションディレクトリを作成する
WORKDIR /usr/src/app

# アプリケーションの依存関係をインストールする
# ワイルドカードを使用して、package.json と package-lock.json の両方が確実にコピーされるようにします。
# 可能であれば (npm@5+)
COPY package*.json ./

RUN npm install
# 本番用にコードを作成している場合
# RUN npm install --only=production

# アプリケーションのソースをバンドルする
COPY . .

EXPOSE 8080
CMD [ "node", "server.js" ]

.dockerignore ファイル

以下の内容で Dockerfile と同じディレクトリに .dockerignore ファイルを 作成してください:

node_modules
npm-debug.log

これにより、ローカルモジュールとデバッグログが Docker イメージにコピーされたり、 イメージ内にインストールされているモジュールが上書きされたりするのを防ぐことができます。

自分のイメージを構築する

Dockerfile があるディレクトリに行き、次のコマンドを実行して Docker イメージを構築してください。 -t フラグを使うとイメージにタグを付けることができるので、 後で docker images コマンドを使って見つけやすくなります。

docker build . -t <your username>/node-web-app

あなたのイメージは Docker によって表示されます。

$ docker images

# 例
REPOSITORY                      TAG        ID              CREATED
node                            12         1934b0b038d1    5 days ago
<your username>/node-web-app    latest     d64d3505b0d2    1 minute ago

イメージの実行

イメージを -d で実行するとコンテナは分離モードで実行され、バックグラウンドで実行されたままになります。 -p フラグはパブリックポートをコンテナ内のプライベートポートにリダイレクトします。 以前に構築したイメージを実行します。

docker run -p 49160:8080 -d <your username>/node-web-app

アプリの出力をプリントします。

# コンテナ ID を取得する
$ docker ps

# アプリ出力をプリントする
$ docker logs <container id>

# 例
Running on http://localhost:8080

コンテナの中に入る必要があるなら、exec コマンドを使うことができます。

# コンテナに入る
$ docker exec -it <container id> /bin/bash

テスト

アプリケーションをテストするには、Docker がマッピングしたアプリケーションのポートを取得します。

$ docker ps

# 例
ID            IMAGE                                COMMAND    ...   PORTS
ecce33b30ebf  <your username>/node-web-app:latest  npm start  ...   49160->8080

上の例では、Docker はコンテナの内側の 8080 ポートをマシンの 49160 ポートに マッピングしました。

これで curl (必要ならばインストールしてください: sudo apt-get install curl) を使ってアプリを呼び出すことができます:

$ curl -i localhost:49160

HTTP/1.1 200 OK
X-Powered-By: Express
Content-Type: text/html; charset=utf-8
Content-Length: 12
ETag: W/"c-M6tWOb/Y57lesdjQuHeB1P/qTV0"
Date: Mon, 13 Nov 2017 20:53:59 GMT
Connection: keep-alive

Hello world

このチュートリアルが、Docker 上で簡単な Node.js アプリケーションを立ち上げて実行するのに 役立つことを願います。

Docker および Docker 上の Node.js に関する詳細は、 次の場所にあります。

上部へスクロールする