【初心者向け】Dockerで手軽にNode.js開発環境構築 (2)

前回[【初心者向け】Dockerで手軽にNode.js開発環境構築 (1)](https://qiita.com/yuji001/items/f597f06cb5a05b3fe82e)

# Node.js

サーバーサイド Javascript
[参考]
[Node.js を5分で大雑把に理解する](https://qiita.com/hshimo/items/1ecb7ed1b567aacbe559)
[基礎から学ぶNode.js：第1回 Node.jsとは](http://gihyo.jp/dev/serial/01/nodejs/0001)

# Express.js

シンプルな Web アプリケーションフレームワーク
[Express - Node.js Web アプリケーション・フレームワーク](http://expressjs.com/ja/)

Version は 4.16.0 を使う
巷には Express 3 の情報が溢れているが（最近は4も増えてきた）
互換性がないので Express 3 系の記事は絶対鵜呑みにしてはいけない
結局上の公式リファレンスが最強だと思う

# 開発環境構築

普通に作ろうとすると
・Homebrew （Mac 用パッケージマネージャー）
・Nodebrew （Node.js のバージョン管理ツール）
・Node.js 本体

をインストールした後
npm （Node.js 用パッケージマネージャー）を用いて
Express などの必要なパッケージをインストール

みたいな手順を踏むため環境が汚れてしまう
そこで Docker の出番

## ディレクトリ作成

プロジェクト名はなんでもいい
以下のようなディレクトリ構成にする
ターミナルで移動しやすい場所（ホームディレクトリの近くとか？）だと少し楽

```
MyApp
├─ node
│   ├─ Dockerfile
│   └─ .dockerignore
└─ docker-compose.yml
```

## Dockerfile

公開されているイメージをそのまま使ってもいいが Dockerfile を作成してみる
Dockerfile とは Docker イメージの設計書のようなもの

```dockerfile:Dockerfile
# ベースイメージを指定
# 今回は LTS の 8.9.4 にする
# alpine は 軽量の linux OS
FROM node:8.9.4-alpine

# node.js の環境変数を定義する
# 本番環境では production
ENV NODE_ENV=development

# 雛形を生成するのに必要なパッケージのインストール
RUN npm install -g express-generator@4.16.0

# ディレクトリを移動する
WORKDIR /app

# ポート3000番を開放する
EXPOSE 3000
```

[参考]
[Dockerfile reference （公式）](https://docs.docker.com/engine/reference/builder/)
[Dockerfile リファレンス （日本語訳）](http://docs.docker.jp/engine/reference/builder.html) 
日本語訳は情報が古いので注意

## Compose file

```yaml:docker-compose.yml
version: '3'
services:
  webserver:
    build: node
    image: node-express-dev:1.0
    container_name: node
    tty: true
    volumes:
      - ./node/app:/app
    ports:
      - "8080:3000"
```

`services` 以下にコンテナの情報を記述していく

・`webserver`
Docker が構築する Network でのホスト名になる（任意の名前で良い） 
例えばこの場合、別のコンテナから node に繋げたいときは `http://webserver:3000` といった感じ

・`build`
Dockerfile があるディレクトリを指定する。省略した場合は local または Docker Hub からイメージを取得する

・`image`
イメージの名前を指定する
`build` の有無で意味が変わる

・`container_name`
コンテナ名

・`tty`
コンテナ内の標準出力とホストの出力を繋げるためのもの
docker run 時の `-t` オプションに対応
これがないとコンテナがすぐ終了してしまうため、基本的に `true`

・`volumes`
ボリュームには２種類あるので気をつけること
この場合はコンテナのディレクトリをホスト（Mac）のディレクトリにマウントするという意味

現時点でホストには `./node/app` というディレクトリは存在しないが
この状況で Compose を立ち上げると
ホストにディレクトリが生成され、コンテナ内のディレクトリとしてマウントされる

こうすることで VSCode などのエディタでホストのファイルを直接編集すれば
コンテナ内のファイルを編集したことになるので、開発がすごく楽になる

・`ports`
この場合はコンテナのポートとホストのポートを繋げる役割
例えば `http://localhost:８０８０` で node コンテナの 3000 番に繋がる

[参考]
[Compose file version 3 reference](https://docs.docker.com/compose/compose-file/)

## コンテナの起動

準備が整ったのでコンテナを立ち上げていく
`docker-compose.yml` が置いてあるディレクトリに移動する

```
cd MyApp
```

Dockerfile からイメージをビルド

```
$ docker-compose build
```

コンテナを生成し、今回はバックグラウンドで起動

```
$ docker-compose up -d
```

node ディレクトリの直下に app ディレクトリができているのが確認できる

```
MyApp
├─ node
│   ├─ app ←      
│   ├─ Dockerfile
│   └─ .dockerignore
└─ docker-compose.yml
```


ちなみに上2つのコマンドを Docker Compose を使わないでやると次のようになる

```
$ docker build ./node -t node-express-dev:1.0
$ docker run -itd —-name node -v ~/MyApp/node/app:/app -p 8080:3000 node-express-dev:1.0
```


## コンテナに接続

状態を確認

```
$ docker-compose ps
Name        Command       State           Ports         
--------------------------------------------------------
node    node              Up      0.0.0.0:8080->3000/tcp
```

`Command` が `node` になっているのはベースイメージ由来のコマンド
このプロセスに `attach` しても REPL（Read eval print loop：対話的実行環境）に接続するだけでサーバを起動できない
ここでは別プロセスを立ち上げて接続するための `docker exec` コマンドを利用する

```
$ docker exec -it node /bin/sh
```

express-generator で雛形を作成する

```
# express -f --view=pug /app
```

`-f` オプションをつけることで
既にディレクトリが存在していても強制的に作成できる

必要なパッケージのインストール

```
# npm install
```

サーバーを起動

```
# npm start
```

ブラウザで http://localhost:8080 にアクセス

Welcome to Express!

確認ができたら `Ctrl + C` で終了

コンテナを抜ける

```
$ exit
```

コンテナを止める

```
$ docker-compose stop
```

次回からは `start` コマンドでコンテナを起動できる（コンテナ自体を作り直す場合は `up` コマンド) 

```
$ docker-compose start
```

次は express のコード周りを見ていきます