Node.js を動かす Dockerfile のサンプル

## 概要

- Node.js アプリケーションのシンプルなサンプルを作成する
- Node.js を動かす Dockerfile を作成する
- Dockerfile から Docker イメージを作成する
- Docker イメージから Docker コンテナを作成する
- Docker コンテナを起動する

## 今回の環境

- macOS Catalina
- Docker Desktop Community 2.3.0.3
- Node.js v14.4.0

docker コマンドは Docker Desktop に付属のものを使う。

```
$ docker --version
Docker version 19.03.8, build afacb8b

$ which docker
/usr/local/bin/docker

$ ls -l /usr/local/bin/docker 
lrwxr-xr-x  1 root  admin  54  5 24 23:06 /usr/local/bin/docker -> /Applications/Docker.app/Contents/Resources/bin/docker
```

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

[Node\.js Web アプリケーションを Docker 化する \| Node\.js](https://nodejs.org/ja/docs/guides/nodejs-docker-webapp/) を参考にシンプルなサンプルプログラムを作成する。

### ファイル一覧

- package.json: プログラムの諸情報と今回使うライブラリ情報を記述したファイル
- server.js: 今回のメインプログラム

### package.json

外部ライブラリを使うサンプルとして Express.js を導入する。

```package.json
{
  "name": "hello",
  "version": "1.0.0",
  "description": "Node.js on Docker",
  "main": "server.js",
  "scripts": {
    "start": "node server.js"
  },
  "dependencies": {
    "express": "4.17.1"
  }
}
```

### server.js

```server.js
'use strict';

const express = require('express');

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

const PORT = 8080;
const HOST = '0.0.0.0';
app.listen(PORT, HOST);

console.log(`Running on http://${HOST}:${PORT}`);
```

### npm install コマンドで package-lock.json を作る

```
$ npm install
```

```
$ ls -1
Dockerfile
node_modules
package-lock.json
package.json
server.js
```

## Dockerfile を作成

Dockerfile は Docker イメージの素になるテキストファイル。
ベースとなる OS の情報や Docker イメージに含めたいファイルについて記述する。
イメージを作るために Dockerfile に記述するコマンド (FROM とか COPY とか) は [Dockerfile リファレンス — Docker\-docs\-ja ドキュメント](http://docs.docker.jp/engine/reference/builder.html) に載っている。

ベースとなる Docker イメージとして Node.js を使用可能な Docker イメージを [node \- Docker Hub](https://hub.docker.com/_/node) から探して記述する。今回は Debian Buster + Node.js 14.4.0 を選択する。

```Dockerfile
# OS: Debian Buster
# Node.js: 14.4.0
FROM node:14.4.0-buster

# Create app directory
WORKDIR /usr/src/app

# Install app dependencies (package.json and package-lock.json)
COPY package*.json ./
RUN npm install

# Bundle app source (server.js)
COPY . .

# Listen port
EXPOSE 8080

# Run Node.js
CMD [ "node", "server.js" ]
```

## Docker イメージとコンテナの操作

Docker のコマンドは [Docker コマンド — Docker\-docs\-ja ドキュメント](http://docs.docker.jp/engine/reference/commandline/) に載っている。

### Dockerfile から Docker イメージを作成

docker build コマンドで Docker イメージを作成する。

```
$ docker build -t foobar/hello:1.0 .
Sending build context to Docker daemon  19.97kB
Step 1/7 : FROM node:14.4.0-buster
 ---> 467c817255bf
Step 2/7 : WORKDIR /usr/src/app
 ---> Running in 94a1975e6c96
Removing intermediate container 94a1975e6c96
 ---> db5d6b07a9e9
Step 3/7 : COPY package*.json ./
 ---> c9a8a6523573
Step 4/7 : RUN npm install
 ---> Running in 90f9fb92056b
npm WARN hello@1.0.0 No repository field.
npm WARN hello@1.0.0 No license field.

added 50 packages from 37 contributors and audited 50 packages in 2.61s
found 0 vulnerabilities

Removing intermediate container 90f9fb92056b
 ---> 540f2f19d410
Step 5/7 : COPY . .
 ---> 53e4a6ad59d6
Step 6/7 : EXPOSE 8080
 ---> Running in 4741417b8721
Removing intermediate container 4741417b8721
 ---> 24a7d4294ed5
Step 7/7 : CMD [ "node", "server.js" ]
 ---> Running in c5deb899fc5f
Removing intermediate container c5deb899fc5f
 ---> 78e3f12c948c
Successfully built 78e3f12c948c
Successfully tagged foobar/hello:1.0
```

IMAGE ID 78e3f12c948c で Docker イメージが作成された。
docker images コマンドで確認できる。

```
$ docker images
REPOSITORY     TAG             IMAGE ID       CREATED              SIZE
foobar/hello   1.0             78e3f12c948c   About a minute ago   913MB
node           14.4.0-buster   467c817255bf   8 days ago           910MB
```

### Docker イメージから Docker コンテナを作成

docker create コマンドで Docker コンテナを作成する。

```
$ docker create --name mycontainer --publish=3000:8080 78e3f12c948c
2638645fa32e6c02d97fe443415877ac27054feb8a253f4270a8e81b73817fe7
```

CONTAINER ID 2638645fa32e で Docker コンテナが作成された。
docker ps コマンドで確認できる。

```
$ docker ps -all
CONTAINER ID   IMAGE          COMMAND                  CREATED         STATUS    PORTS   NAMES
2638645fa32e   78e3f12c948c   "docker-entrypoint.s…"   5 seconds ago   Created           mycontainer
```

### Docker コンテナを起動

docker start コマンドで Docker コンテナを起動する。

```
$ docker start 2638645fa32e
2638645fa32e
```

curl コマンドで HTTP アクセスしてレスポンスが返ってくるか確認する。

```
$ curl --include http://localhost:3000/
HTTP/1.1 200 OK
X-Powered-By: Express
Content-Type: text/html; charset=utf-8
Content-Length: 11
ETag: W/"b-Ck1VqNd45QIvq3AZd8XYQLvEhtA"
Date: Thu, 18 Jun 2020 11:51:24 GMT
Connection: keep-alive

Hello World
```

### あとしまつ

Docker コンテナを停止。

```
$ docker stop 2638645fa32e
2638645fa32e
```

Docker コンテナを削除。

```
$ docker rm 2638645fa32e
2638645fa32e
```

削除されたのを確認。

```
$ docker ps --all
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
```

Docker イメージを削除。

```
$ docker rmi 78e3f12c948c
```

削除されたのを確認。

```
$ docker images
REPOSITORY                           TAG                                              IMAGE ID            CREATED             SIZE
node                                 14.4.0-buster                                    467c817255bf        8 days ago          910MB
```

## 参考資料

- [Node\.js Web アプリケーションを Docker 化する \| Node\.js](https://nodejs.org/ja/docs/guides/nodejs-docker-webapp/)
- [Docker コマンド — Docker\-docs\-ja ドキュメント](http://docs.docker.jp/engine/reference/commandline/)
- [Dockerfile リファレンス — Docker\-docs\-ja ドキュメント](http://docs.docker.jp/engine/reference/builder.html)
- [node \- Docker Hub](https://hub.docker.com/_/node)