docker-compose(Docker for mac)で実践的なnode.js開発環境を作る

# Docker

Docker のメリット、デメリットについては[この記事](http://qiita.com/minodisk/items/5ffd20588b995523756f)が詳しい。
個人的に大事かなと思うProsは以下のふたつ。

> 複数人で開発する際に、環境の差が生まれない。

バージョンに依存した開発をしてる場合などに、同一の環境である保証ができる。
「It works on my machine!!」とか言えなくなる。
> コンテナを捨てる・再生成するのが容易。

たとえば、`Node.js`のバージョンを変えたい場合、`Dockerfile`の`image`を書き換えるだけで出来る。
ただ`Docker`自体、職人技とかクセが多かったりもするので`Vagrant`でいいじゃんとなることもありますが。。。

## ここでやること
この記事では`Express4`で`node.js`のプロジェクトを作成して`Hello World`を表示する`node.js`コンテナ
ポート80番を`node.js`の3000番にポートフォワードする`nginx`コンテナ、
使わないかもですが、`node.js`コンテナから接続する`mysql`コンテナを作成して連携させます。

## 環境
最近`Docker for Mac`が出たので、ついにVirtualBoxが必要なくなりました :tada: 

- Macbook
- [Docker for Mac](https://docs.docker.com/docker-for-mac/)
- [Docker Compose](https://docs.docker.com/compose/install/)
- Node.js v6.9 ※
- Express 4
- MySQL 5.6

※ローカルにもnode.jsが必要です。
### express-generator で雛形作成

```bash
$ npm install -g express 
$ npm install -g express-generator
```

```bash
$ express hello-world                                                                                                                                                                                  

  warning: the default view engine will not be jade in future releases
  warning: use `--view=jade' or `--help' for additional options


   create : hello-world
   create : hello-world/package.json
   create : hello-world/app.js
   create : hello-world/public
   create : hello-world/routes
   create : hello-world/routes/index.js
   create : hello-world/routes/users.js
   create : hello-world/public/images
   create : hello-world/views
   create : hello-world/views/index.jade
   create : hello-world/views/layout.jade
   create : hello-world/views/error.jade
   create : hello-world/public/javascripts
   create : hello-world/public/stylesheets
   create : hello-world/public/stylesheets/style.css
   create : hello-world/bin
   create : hello-world/bin/www

   install dependencies:
     $ cd hello-world && npm install

   run the app:
     $ DEBUG=hello-world:* npm start
```

```bash
$ cd hello-world/
```

### docker-compose.ymlの作成
`node.js`のイメージは[公式リポジトリ](https://hub.docker.com/_/node/)の`6.9-alpine`を使います。
※ alpineは軽量化されたLinuxイメージです。例えば`vim`とかインストールされてません。
基本的に必要がなければ`alpine`で進めます。

**docker-compose.yml**

```
version: '2'
services:
  nginx:
    image: nginx:alpine
    container_name: nginx
    ports:
      - "80:80"
    volumes:
      - "./conf.d:/etc/nginx/conf.d"
    links:
      - node_express

  node_express:
    image: node:6.9-alpine
    container_name: node_express
    hostname: node_express
    volumes:
      - ".:/src"
    working_dir: /src
    command: [sh, -c, npm install && npm start]
    ports:
      - "3000:3000"
    links:
      - mysql

  mysql:
    image: mysql:5.6
    container_name: mysql56
    hostname: mysql
    command: mysqld --character-set-server=utf8 --collation-server=utf8_unicode_ci
    ports:
      - "3306:3306"
    environment:
      - "MYSQL_ROOT_PASSWORD=root"
      - "MYSQL_DATABASE=sample"
```

**/conf.d/nodejs.conf**
80番から3000番ポートフォワーディング

```
server {
    listen 80;
    server_name _;
    client_max_body_size 10M;
    location / {
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Host $http_host;
        proxy_set_header X-NginX-Proxy true;
        proxy_pass http://node_express:3000/;
    }
}
```

`proxy_pass http://node_express:3000/;`は`docker-compose.yml`の`hostname`を指定してます。

一旦これで動くと思うので試してみます。

```bash
$ docker-compose -p hello_project up -d --build
```

[http://localhost:3000](http://localhost:3000)か[http://localhost](http://localhost)にアクセスするとexpressの画面が表示されるはずです。

![スクリーンショット 2016-12-12 16.03.42.png](https://qiita-image-store.s3.amazonaws.com/0/87900/954502a9-3cfc-91f4-9933-4ea7e1be742f.png "スクリーンショット 2016-12-12 16.03.42.png")

`docker-compose`を止めます。

```bash
$ docker-compose -p hello_project kill
```

### Makefileの作成
`docker-compose`でよく使うコマンドは`Makefile`にまとめてしまいましょう。

**Makefile**

```basemake
PROJECT = hello_project

.PHONY: start
start: 
	docker-compose -p $(PROJECT) up -d --build
	
.PHONY: logs
logs:
	docker-compose -p $(PROJECT) logs
	
.PHONY: restart
restart:
	docker-compose -p $(PROJECT) kill && \
	docker-compose -p $(PROJECT) rm -f && \
	docker-compose -p $(PROJECT) up -d --build

.PHONY: kill
kill: 
	docker-compose -p $(PROJECT) kill

.PHONY: ps
ps: 
	docker-compose -p $(PROJECT) ps

```

`make start`,`make restart`,`make logs`,`make kill`,`make ps`で`docker-compose`を操作できるようになりました。

```bash
$ make start
docker-compose -p hello_project up -d --build
Creating mysql56
Creating node_express
Creating nginx
```

```bash
$ make ps
docker-compose -p hello_project ps
    Name                  Command               State              Ports
-----------------------------------------------------------------------------------
mysql56        docker-entrypoint.sh mysql ...   Up      0.0.0.0:3306->3306/tcp
nginx          nginx -g daemon off;             Up      443/tcp, 0.0.0.0:80->80/tcp
node_express   sh -c npm install && npm start   Up      0.0.0.0:3000->3000/tcp
```

HostからMySQLコンテナに接続してみる。

```bash
$ mysql -h 0.0.0.0 -uroot -proot
```

```bash
$ make kill
docker-compose -p hello_project kill
Killing nginx ... done
Killing node_express ... done
Killing mysql56 ... done
```

[ソース](https://github.com/ichiwa/docker-compose-express-hello)

Enjoy your docker life !!