Dockerでangular2のquickstartを試してみた

# 概要
Angular2の[5 Min Quickstart ][link1]をDockerを使って試す。

(2016/7/13)　必要な手順を行わず強引に行っていた部分を修正

環境は以下の通り
 
 - OS:Windows10
 - VirtualBox: 5.0.22
 - Vagrant: 1.8.4

# フォルダ構成

```Windows上のテスト用ディレクトリ以下.
- Vagrantfile
- share
　- angular2
　  - index.html
　  - styles.css 
    - app
      - app.component.ts
      - main.ts
```

(2016/7/13)       ~~- lib.es6.d.ts~~

```
  - gulp
    - tasks
      - task.js
  - Docker
    - angular2
      - Dockerfile
      - package.json
      - systemjs.config.js
      - tsconfig.json
      - typings.json
    - shell
      - angular.sh
      - env.conf
```

# 各ファイルの設定

以下のファイルは[Angular2　5 Min Quickstart ][link1]の通り

```
- share
　- angular2
　  - index.html
　  - styles.css 
    - app
      - app.component.ts
      - main.ts
  - Docker
    - angular2
      - package.json
      - systemjs.config.js
      - tsconfig.json
      - typings.json
```

(2016/7/3)~~[typescript/lib/lib.es6.d.ts][link2]からlib.es6.d.tsダウンロードして、
share/angular2/app/フォルダにいれる。~~

```
- share
　- angular2
    - app
      - lib.es6.d.ts
```

(2013/07/16)~~これがないと、 ``` Error TS2304: Cannot find name```のエラーが発生する。~~
(2013/07/16)打消し部分は`typings install `を行っていなかったのが原因のエラー。


仮想環境のプロビジョニングでDockerをインストールする。

```shell:Vagrantfile
# ==> Dockerインストールshell.ここから
$docker_install = <<SHELL
　　 # aptが使用中でupdateが成功しないことがあるため殺してからupdate。
    sudo killall -KILL apt.systemd.daily

　　#　以下、Dockerの公式インストール手順
    sudo apt-get update
    sudo apt-get install apt-transport-https ca-certificates

    sudo apt-key adv --keyserver hkp://p80.pool.sks-keyservers.net:80 --recv-keys 58118E89F3A912897C070ADBF76221572C52609D

    echo 127.0.1.1 $(hostname) >> /etc/hosts

    echo "deb https://apt.dockerproject.org/repo ubuntu-xenial main" > /etc/apt/sources.list.d/docker.list

    sudo apt-get update
    sudo apt-get purge lxc-docker
    apt-cache policy docker-engine

    sudo apt-get update
    sudo apt-get install -y linux-image-extra-$(uname -r)

    sudo apt-get update
    sudo apt-get -y install docker-engine

　　#　Dockerをsudoなしに実行できるようvagrantユーザをdockerグループに追加
    sudo gpasswd -a vagrant docker
SHELL
# <== Dockerインストールshell.ここまで

#　仮想環境設定
Vagrant.configure(2) do |config|
  config.vm.box = "bento/ubuntu-16.04"
  
  # ネットワーク設定。
  config.vm.network "private_network", ip: "192.168.50.12"
  
  # 使用するメモリ容量を変更。
  # デフォルトだと512で少ないためdockerのbuildが失敗しやすい
  config.vm.provider "virtualbox" do |vm|
    # メモリを1024MBに設定
    vm.memory = 1024
    # Vagrant1.8から利用出来るLinked Cloneをオンにする。
    vm.linked_clone = true
  end

  # dockerをインストール
  config.vm.provision "shell", inline: $docker_install

end

```

Dockerファイル設定。
angular2のインストールと、ファイル共有のためのgulpをインストール。

(2016/7/13)typings installをするための ` RUN npm run postinstall `を追記。

```bash:Docker/angular2/Dockerfile
FROM node:4.4.7

# Add our user and group first to make sure their IDs get assigned consistently
RUN groupadd -r vagrant && useradd -r -g vagrant vagrant 

ENV DOCKER_FILE_DIR=/vagrant/Docker/angular2
ENV WORK_DIR=/home/vagrant/angular2-quickstart

# ======================================================================
#タスクランナーインストール
ENV GULP_DIR=/home/vagrant/gulp
RUN mkdir -p ${GULP_DIR}
WORKDIR ${GULP_DIR}

# package.jsonを書き出し
# nameをgulpにするとエラーとなる
RUN echo '{ "name": "my_gulp",  "scripts": { "gulp":"gulp" }}' > package.json

# install
RUN npm install -g gulp 
RUN npm install --save-dev gulp 
RUN npm install --save-dev require-dir 
RUN npm install --save-dev gulp-if 

#gulpfileを書き出し
RUN echo "var requireDir = require('require-dir'); requireDir('/home/vagrant/share/gulp/tasks/', { recurse: true }); " > gulpfile.js 

# ======================================================================

RUN mkdir -p ${WORK_DIR}
WORKDIR ${WORK_DIR}

# COPY命令では../のように親ディレクトリは指定できない。
# 構築時にコンテクストのディレクトリ以下をDockerデーモンに送るため
COPY package.json $WORK_DIR/package.json
RUN npm install

# 各種設定ファイル用意
COPY tsconfig.json ${WORK_DIR}/tsconfig.json
COPY typings.json ${WORK_DIR}/typings.json
COPY systemjs.config.js ${WORK_DIR}/systemjs.config.js

# typings install
RUN npm run postinstall

RUN mkdir app

# ======================================================================
ENV SHARE_DIR=/home/vagrant/share
RUN mkdir -p ${SHARE_DIR}
# ======================================================================

WORKDIR ${GULP_DIR}
CMD ["npm", "run", "gulp" ]
```

```json:package.json
{
  "name": "angular2-quickstart",
  "version": "1.0.0",
  "scripts": {
    "start": "tsc && concurrently \"npm run tsc:w\" \"npm run lite\" ",
    "lite": "lite-server",
    "postinstall": "typings install",
    "tsc": "tsc",
    "tsc:w": "tsc -w",
    "typings": "typings"
  },
  "license": "ISC",
  "dependencies": {
    "@angular/common": "2.0.0-rc.4",
    "@angular/compiler": "2.0.0-rc.4",
    "@angular/core": "2.0.0-rc.4",
    "@angular/forms": "0.2.0",
    "@angular/http": "2.0.0-rc.4",
    "@angular/platform-browser": "2.0.0-rc.4",
    "@angular/platform-browser-dynamic": "2.0.0-rc.4",
    "@angular/router": "3.0.0-beta.1",
    "@angular/router-deprecated": "2.0.0-rc.2",
    "@angular/upgrade": "2.0.0-rc.4",
    "systemjs": "0.19.27",
    "core-js": "^2.4.0",
    "reflect-metadata": "^0.1.3",
    "rxjs": "5.0.0-beta.6",
    "zone.js": "^0.6.12",
    "angular2-in-memory-web-api": "0.0.14",
    "bootstrap": "^3.3.6"
  },
  "devDependencies": {
    "concurrently": "^2.0.0",
    "lite-server": "^2.2.0",
    "typescript": "^1.8.10",
    "typings":"^1.0.4"
  }
}
```

gulp用の設定ファイルを記述.
共有フォルダのangular2を監視してファイルをコピーする。
また、angular2を起動する。

```js:share/gulp/taks.js
var gulp = require('/home/vagrant/gulp/node_modules/gulp');
var spawn = require('child_process').spawn;

var angular2_dir = "/home/vagrant/angular2-quickstart";

gulp.task('default', ['copy', 'watch', 'angular2']);

gulp.task('copy',function(){
    var base_dir = "/home/vagrant/share/angular2",
        dist_dir = angular2_dir;
    return gulp.src(
        [ base_dir + '/*', base_dir + '/app/*' ],
        { "base": base_dir }
    )
    .pipe( gulp.dest( dist_dir ) );
});

gulp.task('angular2', function(){
  spawn('npm',['start'], {cwd:angular2_dir,
    stdio: ['pipe', process.stdout, process.stderr]});
});

gulp.task('watch',['copy'],function(){
  gulp.watch(['/home/vagrant/share/angular2/**'], ['copy']);
});

```

docker起動用のシェルを記述

```bash:Docker/shell/env.conf
#!/bin/bash

# docker用ディレクトリ
path_Dockerfile_dir="/vagrant/Docker"


#共通関数

# dockerファイルからビルド
build(){
  local dir=$1
  local imageName=$2

  # 移動してビルド
  cd $dir && docker build -t $imageName .
}

# 前回のコンテナをチェック。残っていれば削除
checkBeforeContainer(){
  local containerName=$1

  # 前回のコンテナが残っているかチェック。
  docker ps -a | grep $containerName >/dev/null 2>&1

  # コンテナが残っている場合は削除。
  if [ $? -eq 0 ]; then
    docker rm -f $containerName
  fi
}

# 引数が指定されていない時はrunを行う
default(){
  if [ $1 -eq 0 ] ; then
    run
    exit
  fi
}

# 指定されたオプションで処理を切り替える。
main(){
  local opt=$1
  local buildDir=$2
  local imageName=$3
  local containerName=$4

  case ${opt} in
    b)
      build ${buildDir} ${imageName}
      ;;
    r)
      run
      ;;
    d)
      run_d
      ;;
    i)
      run_d
      docker exec -it ${containerName} /bin/bash
      ;;
    \?)
      exit 1
      ;;
  esac
}
```

```bash:Docker/shell/angular.sh
#!/bin/bash 

source "/vagrant/Docker/shell/env.conf"

imageName="hibo/angular2"
containerName="angular2"
host_src_dir="/vagrant/share"
container_src_dir="/home/vagrant/share"
docker_dir="${path_Dockerfile_dir}/angular2"

# -t: docker側の標準出力をホストの標準出力につなげる。
# -i: ホスト側のキーボードで打った文字をコンテナに送る
# -p:ポートフォワディング ホスト側：コンテナ側
# -e:環境変数
# -u:user
# -v: ディレクトリ共有
# -w: ワークディレクトリ
run(){
  docker run --name $containerName --rm -it \
             -p 80:3000 \
             -m "300M" --memory-swap "512M" \
             -e "NODE_ENV=production" \
             -v $host_src_dir:$container_src_dir \
             $imageName 
}

run_d(){
  docker run --name $containerName -d -i \
             -p 80:3000 \
             -m "300M" --memory-swap "512M" \
             -e "NODE_ENV=production" \
             -v $host_src_dir:$container_src_dir \
             $imageName 
}

checkBeforeContainer $containerName
default $#

while getopts brdi opt
do
  main ${opt} $docker_dir $imageName $containerName
done

```

ファイルをすべて準備できたら、

```
vagrant up
vagrant ssh-config --host angular >> ~/.ssh/config
ssh angular
```

ssh接続できたら、仮想環境で以下を実行。

```
/vagrant/Docker/shell/angular.sh -b
/vagrant/Docker/shell/angular.sh
```

Dockerが立ち上がったら、ブラウザで192.168.50.12にアクセスすると
angular2のquickstartの画面が見えるはず。

#参考資料
[5 Min Quickstart ][link1]
[lib.es6.d.ts][link2]
[stack over flow][link3]

[link1]:https://angular.io/docs/ts/latest/quickstart.html

[link2]:https://github.com/Microsoft/TypeScript/blob/master/lib/lib.es6.d.ts
[link3]:http://stackoverflow.com/questions/33332394/angular-2-typescript-cant-find-names