Bluemix DevOps で Angular をデプロイする

# 概要
Bluemix DevOps (Open Toolchains) の Delivery PipelineでAngular 2 (TypeScript)をビルドして稼働させるには、次のようにしてビルドするとよい。

## Delivery Pipelineの編集
1. Delivery Pipeline の Buildタスクを編集する。デフォルトでは、BUILDフェーズのBuildタスクである。
2. **ビルダー・タイプ** を、デフォルトの「シンプル」から「npm」に変更する
3. **シェル・コマンドのビルド** に次のスクリプトを仕込む

```
#!/bin/bash
export NVM_DIR=/home/pipeline/nvm
export NODE_VERSION=6.10.3
export NVM_VERSION=0.33.2

npm config delete prefix \
  && curl https://raw.githubusercontent.com/creationix/nvm/v${NVM_VERSION}/install.sh | sh \
  && . $NVM_DIR/nvm.sh \
  && nvm install $NODE_VERSION \
  && nvm alias default $NODE_VERSION \
  && nvm use default \
  && node -v \
  && npm -v
npm install -g @angular/cli

npm install
ng build -prod --aot
rm -rf node_modules/
```
4.ビルドタスクを保存してパイプラインを流すと、Angularソースがビルドされ、成果物の中に `dist/` フォルダが作成される。

## 処理の機序
Delivery Pipelineは、github等のgitレポジトリからコードをcloneしてコンテナ内にもってきます。
デフォルトで構成されている「シンプル」ビルドタスクは、cloneしてもってきたコードを再度まとめて保存し後続フェーズのタスクへ渡すのですが、それでは後続フェーズでは直接 `cf push` されるため、`ng build`でJavaScriptコードを生成させる機会はありません。そのため「シンプル」以外の何らかのビルドタスクにて`ng build`を行う必要があります。

コンテナの`/opt/IBM`には各種ビルドツール、ランタイム類が仕込んであります。

```
drwxr-xr-x 21 root     root  4096 Jun 22 22:42 .
drwxr-xr-x  3 root     root  4096 Jun 22 20:41 ..
lrwxrwxrwx  1 root     root    25 Jun 22 22:38 ant -> /opt/IBM/apache-ant-1.9.2
lrwxrwxrwx  1 root     root    26 Jun 22 22:38 ant.java8 -> /opt/IBM/apache-ant-1.10.1
drwxr-xr-x  6 root     root  4096 Feb  2 19:00 apache-ant-1.10.1
drwxr-xr-x  6 root     root  4096 Jul  8  2013 apache-ant-1.9.2
drwxr-xr-x  6 pipeline  1000 4096 May  2  2014 apache-maven-3.2.1
drwxr-xr-x  3 root     root  4096 Jun 22 20:56 cf
lrwxrwxrwx  1 root     root    20 Jun 22 22:38 gradle -> /opt/IBM/gradle-1.12
drwxr-xr-x  6 root     root  4096 Apr 29  2014 gradle-1.12
lrwxrwxrwx  1 root     root    19 Jun 22 22:38 gradle2 -> /opt/IBM/gradle-2.9
drwxr-xr-x  6 root     root  4096 Nov 17  2015 gradle-2.9
drwxr-xr-x 10 root     root  4096 Mar 13  2015 ibm-java-x86_64-71
drwxr-xr-x 10 root     root  4096 May 18 14:11 ibm-java-x86_64-80
lrwxrwxrwx  1 root     root    14 Jun 22 22:38 java -> /opt/IBM/java7
lrwxrwxrwx  1 root     root    27 Jun 22 22:38 java7 -> /opt/IBM/ibm-java-x86_64-71
lrwxrwxrwx  1 root     root    27 Jun 22 22:38 java8 -> /opt/IBM/ibm-java-x86_64-80
lrwxrwxrwx  1 root     root    27 Jun 22 22:38 maven -> /opt/IBM/apache-maven-3.2.1
lrwxrwxrwx  1 root     root    32 Jun 22 22:38 node -> /opt/IBM/node-v0.10.40-linux-x64
lrwxrwxrwx  1 root     root    32 Jun 22 22:38 node-v0.10 -> /opt/IBM/node-v0.10.40-linux-x64
drwxr-xr-x  7      495   371 4096 Aug 14  2015 node-v0.10.40-linux-x64
lrwxrwxrwx  1 root     root    32 Jun 22 22:38 node-v0.10.48 -> /opt/IBM/node-v0.10.48-linux-x64
drwxr-xr-x  7    50371 50009 4096 Oct 19  2016 node-v0.10.48-linux-x64
lrwxrwxrwx  1 root     root    31 Jun 22 22:38 node-v0.12 -> /opt/IBM/node-v0.12.7-linux-x64
lrwxrwxrwx  1 root     root    32 Jun 22 22:38 node-v0.12.17 -> /opt/IBM/node-v0.12.17-linux-x64
drwxr-xr-x  7    50371 50009 4096 Oct 19  2016 node-v0.12.17-linux-x64
drwxr-xr-x  7      495   371 4096 Aug 14  2015 node-v0.12.7-linux-x64
lrwxrwxrwx  1 root     root    30 Jun 22 22:38 node-v4.2 -> /opt/IBM/node-v4.2.2-linux-x64
drwxr-xr-x  7      495   371 4096 Nov 11  2015 node-v4.2.2-linux-x64
lrwxrwxrwx  1 root     root    30 Jun 22 22:38 node-v4.4.5 -> /opt/IBM/node-v4.4.5-linux-x64
drwxr-xr-x  7    50371 50009 4096 May 26  2016 node-v4.4.5-linux-x64
lrwxrwxrwx  1 root     root    30 Jun 22 22:38 node-v4.6.0 -> /opt/IBM/node-v4.6.0-linux-x64
drwxr-xr-x  7    50371 50009 4096 Sep 28  2016 node-v4.6.0-linux-x64
lrwxrwxrwx  1 root     root    30 Jun 22 22:38 node-v6.2.2 -> /opt/IBM/node-v6.2.2-linux-x64
drwxr-xr-x  7    50371 50009 4096 Jun 20  2016 node-v6.2.2-linux-x64
lrwxrwxrwx  1 root     root    30 Jun 22 22:38 node-v6.7.0 -> /opt/IBM/node-v6.7.0-linux-x64
drwxr-xr-x  7    50371 50009 4096 Sep 28  2016 node-v6.7.0-linux-x64
drwxr-xr-x  4 root     root  4096 Jun 22 22:27 pipeline
drwxr-xr-x  3 root     root  4096 Jun 22 22:38 RTC-SCM-Tools
```
「npm」ビルドタスクを選ぶことで、上記のツール群を使ったシェルスクリプトを実行できますので、この環境で`ng build`を動かすことになります。

ただ、@angular/cli は、Node V6.9以上を要求しますが、上記の2017-06時点での `ls -al /opt/IBM` の出力を見てわかるように、Node環境は要求を満たせません。（V6.7までしか無い)
そのため、@angular/cliをグローバルインストールする以前に、一旦 `NVM` にて最新のNodeを導入します。

`/opt/IBM` に　Ver. 6.9以上のNode.jsがインストールされていれば、そのNVMの部分はスクリプトに含める必要はなく、直接 `npm install -g @angular/cli` を実行すればOKです。

# 実施手順（詳細） 2017-06現在

**前提** 
開発環境に：
* Node.js **Ver 6.9以降** が導入されていること
* git ツールが導入されていること
* `npm install -g @angular/cli` で、Angular-CLIがグローバル導入されていること
* Cloud Foundry CLI (`cf` コマンド) が導入されていること

あと、有効なBluemixのアカウントを登録済みであること。

**やりたいこと**
Gitレポジトリ (GitHub または Git repositry on Bluemix) 上に Angular-CLI で生成されたプロジェクト・ファイルを置く。（ただしビルドはしていない）
開発環境から `git push origin master` で更新されると、自動的にビルドされ、稼働サーバー `(http|https)://somewhere.mybluemix.net/` に反映される。

## 開発環境ローカルにて初期プロジェクト・コードを作成する

* Angular-CLI でひな形コードを生成
`~` でも `~/dev` でもいいですが、親フォルダにて `ng new PROJECT_NAME` コマンドを実行する。プロジェクト名を `ang2` とした場合

```
ng new ang2
```

* 正常なコードが出来たことを確認するには, `ng serve` にてローカルで実行する。

```
cd ang2/
ng serve
```
http://localhost:4200/ で初期コードが稼働します。

## Bluemix で DevOpsデリバリー・パイプラインを構成する

### 新規ツールチェーンの作成 

* http://bluemix.net でBluemixにログインするとダッシュボードが表示されるので、左上のメニューボタンから「サービス - DevOps」を選択する。(なお、事前に地域として米国南部を選択しておく。)
* 「始めに」ボタンを押すと「ツールチェーンの作成」画面になります。好きなツールチェーンのテンプレートを選べばいいのだが、初めて使う場合には Simple Cloud Foundry ツールチェーン (v1 か v2) を選ぶのが無難。
    > ちなみにv1（と表記は無い方）がGitHubを使う。v2（と表記がある方）が GitLab on Bluemixを使う。

* ツールチェーンの設定画面になるので、「ツールチェーン名」にアプリケーションの名前を入れる。（まだ、**作成**ボタンは押さない)
* ツールチェーン名を入れるボックスの下に「ツール統合」セクションがある。*Git Repos* を選んだ状態では、下に作成するGitレポジトリーの設定を行う項目がある。**リポジトリー・タイプ** で **新規作成** を選択する。 
* **作成** ボタンを押す。

### デリバリー・パイプラインの構成
デリバリー・パイプラインが、Gitレポジトリー上のコードをクローンし、ビルドし、CloudFoundryにプッシュして稼働させる一連の作業を自動で行う。これをカスタマイズし、Typescriptをコンパイルし、ビルドするように変更する。

* ツールチェーンの概要画面のパイプラインボタンを押すと、パイプライン画面になる。
BUILDステージの枠とDEPLOYステージの枠の二つが表示されている。
* BUILDステージ枠の右上隅に歯車アイコンがあるので、これを押して **ステージの構成** を選択する。
* ステージ構成画面で「ジョブ」が表示されており、ビルトインの「Build」ジョブ構成画面になっている。
* ビルド構成の **ビルダー・タイプ** を **npm** にする。
* 現れた **シェル・コマンドのビルド** フィールドにて、下記コードをペースト。

```
#!/bin/bash
export NVM_DIR=/home/pipeline/nvm
export NODE_VERSION=6.10.3
export NVM_VERSION=0.33.2

npm config delete prefix \
  && curl https://raw.githubusercontent.com/creationix/nvm/v${NVM_VERSION}/install.sh | sh \
  && . $NVM_DIR/nvm.sh \
  && nvm install $NODE_VERSION \
  && nvm alias default $NODE_VERSION \
  && nvm use default \
  && node -v \
  && npm -v
npm install -g @angular/cli

npm install
ng build -prod --aot
rm -rf node_modules/
```
* **保存** ボタンを押す。

### Git Repositry on Bluemix を選んだ場合: Git接続

2017/06現在ssh接続しか出来ないので、ssh公開鍵を登録しておくこと。
* ツールチェーンの概要画面の Git ボタンをおすと、GitLabのプロジェクト初期画面に入る。右上のアカウントアイコンから Settings に入り、上部メニューのSSH Keysで公開鍵登録画面になる。

プロジェクトのSSH接続文字列: `git@git.ng.bluemix.net:somebody/something.git` を控えておくことも重要。

### ローカルのプロジェクト・フォルダをGitレポジトリーにpush
下記のコマンドをプロジェクト・フォルダの中で実行する。

```
git remote add origin git@github.com:somebody/something.git
git add --all
git commit -m 'initial commit'
git push -u origin master
```
Gitレポジトリーにプッシュされるのでパイプラインが起動し、ひな形コードがCloudFoundryにプッシュされ、サーバーランタイムが作成される。
Bluemix画面の左上メニューボタンで アプリ - ダッシュボード を選択しダッシュボードを開くと、Cloud Foundry アプリのリストに新しい名前・経路のランタイムが出来ている。だが、サーバーランタイムとしは **未実行** になってしまっており、「経路」のリンクから画面表示させてもAngularの初期コード画面は表示されない。
なぜなら、フロントエンドのJavaScriptコードは、ビルドにより生成されたものの、それを提供するためのhttpデーモンが稼働していないから。
なので、初期コードに Node.js Expressのサーバーコードを組み合わせてやり、サーバーランタイムとして正常に稼働できるようにする。

## サーバーサイド・コードの組み込み

### サーバーサイドのひな形コードをダウンロード
ひな形コード: https://github.com/open-toolchain/node-hello-world
 のうち、次の２つのファイルをダウンロードし、ローカルのプロジェクト・フォルダに配置する。

* manifest.yml
* app.js

配置先は、ローカルのプロジェクト・フォルダの直下。すなわち、package.jsonやREADME.mdと同じ階層。

### サーバーサイドのひな形コードをカスタマイズする。
プロジェクト・フォルダにある、サーバーサイドコードを編集する。

* `manifest.yml` のカスタマイズ
	`manifest.yml` は、CloudFoundryでランタイム・インスタンスを作成する際に参照される設定ファイル。ゆえに、ここでは、サーバー・ランタイムをどのような設定で動かすかを記述する。
	カスタマイズ推奨フィールド:
		- applications → name: Bluemixでのランタイム名
		- applications → memory: Bluemixでのメモリ量設定 (初期コードなら64Mで十分)
	追加推奨フィールド:
		- applications → host: Webアクセスする際のホスト名
		- applications → domain: Webアクセスする際のドメイン名 (mybluemix.net)

* `app.js` のカスタマイズ
	`app.js` は、node.jsにてhttpサーバーを立て稼働させるソースコード。Angularプロジェクトをビルドした成果物をstaticとして見せたいので、ここでは、どのフォルダがstaticフォルダか指定する。
	- 下記の行 (19行目)
	
	```
	app.use(express.static(__dirname + '/public'));
	```
	を
	
	```
	app.use(express.static(__dirname + '/dist'));
	```
	に変更する。

* `package.json` のカスタマイズ
	`package.json` は、npmがnode.jsパッケージをビルドする際に参照される設定ファイル。ゆえに、ここでは、node.jsをどのような設定で動かすかを記述する。
	
	- package.json を開く前に、dependencies への `express`, `cfenv` の追加
	下記コマンドを実行する。
	
	```
	npm install express cfenv --save
	```
	
	- scripts → start の変更
	`package.json` (ll. 5-7) の sciprts.start を変更。
	
	```
	"scripts": {
		...
		"start": "node app.js",
		...
	}
	```
	- engines → node の追加
	`package.json` (l. 50) に engines.node を追加。
	
	```
	"engines": {
		"node": "6.10.x"
	}
	```

### gitレポジトリへ再push
下記のコマンドをプロジェクト・フォルダの中で実行する。

```
git add --all
git commit -m 'added server-side code'
git push origin master
```
pushすると、デリバリー・パイプラインが自動で実行される（自動でビルドとプッシュ）
しばらく待ち、アプリのダッシュボードで該当するランタイムを見ると稼働中になっており、経路欄に表示されるリンクで画面を表示させると、Angualrのひな形コード画面が表示される。