PrivateなNodeをConcourseとCFを利用して無停止で追加する

この記事は[Node-RED Advent Calendar 2016](http://qiita.com/advent-calendar/2016/nodered)の20日目になります

前日は[tseigo](http://qiita.com/tseigo)さんの[node-red-contrib-usbhid がRaspberryPiでうまく入らないときの対処法](http://qiita.com/tseigo/items/c671e283aad4fb2acf0e)でした

## TL; DR

[これ](https://github.com/idahobean/sample-node)と[これ](https://github.com/idahobean/node-red-deploy-config)と各種ツールを利用して無停止でNodeをdeployするはなし

## Motivation

PrivateなNodeを追加する際、Node-REDに極力ダウンタイムを発生させずに追加したい
さらに言うとNodeとNode-REDの管理を分けることによってより柔軟なNode管理を行いたい
もっと言うとAdvent Calendar駆動で色々お勉強しておきたい

## Node-REDにNodeを追加する為にはどうしたらよいのか

[公式](https://nodered.org/docs/getting-started/adding-nodes)より、以下3通りの方法で追加が可能

1.Node-RED画面上からエディタを利用する
2.npmからインストール & Node-REDインスタンスを再起動
3.`nodes`ディレクトリ下にファイルを配置する

上述した理由(Node/Node-REDの管理を分ける、無停止追加)より
2.npmからインストール & Node-REDインスタンスを再起動
に各種ツールを組み合わせて実現することとした

## 前提環境

```text:hardware
MacBook(Early 2015)
```

```text:version
Node-RED:  0.15.2
Concourse: 2.5.0
PCF-dev:   0.21.0
sinopia:   0.13.0
```

```text:network
Node-RED:  PCF-dev上にdeploy(node-red.local.pcfdev.io)
Concourse: local上にdocker-compose up
PCF-dev:   vagrant上のVM(192.168.11.XXX)
sinopia:   vagrant上のVM(192.168.33.XXX)上のDocker(port:4873)
```

## 1.環境構築
### 1.1.PCF-dev(CloudFoundry)を起動する

以下を読むとだいたいできる

* [公式チュートリアル(Workstation)](https://pivotal.io/jp/platform/pcf-tutorials/getting-started-with-pivotal-cloud-foundry-dev/introduction)
* [PCF DevでローカルCloud Foundry環境を作る(v.0.16+)](https://blog.ik.am/entries/387)

### 1.2.Concourseを起動する

以下を読むとだいたいできる

* [公式ドキュメント(Docker Compose版)](http://concourse.ci/docker-repository.html)
* [Binary版で構築するとハマったりする](http://qiita.com/idahobean/items/1c80310112cfb46d6357)

オススメはBOSH/BOSH-lite上の構築らしい、確かに管理は楽そう(TODO)

### 1.3.Private Node Registry(sinopia)を起動する

[docker-sinopia](https://github.com/kfatehi/docker-sinopia)や[dockerでsinopiaを試したメモ](http://qiita.com/ooooooo_q/items/f35dac9abb8af88c9360)を読んで起動する

```bash
docker run --name sinopia -d -p 4873:4873 keyvanfatehi/sinopia:latest
```

注)sinopia自身は更新が停止しているっぽい
npmへのアクセスをnpmコマンドでproxyしてくれるやつであれば何でも良い

## 2.Nodeの作成と登録
### 2.1.Nodeを作成する

公式の[Creating Nodes](https://nodered.org/docs/creating-nodes/)を読みながら[サンプル](https://github.com/idahobean/sample-node)を作成する
今回はNodeの追加までを確認したかったので表示のみの簡素なNodeを作成した

```html:sampleNode.html
<script type="text/javascript">
	RED.nodes.registerType("Sample Node", {
		category: "private",
		color: "#FFFFFF",
		defaults: {
			name: { value: "aaa", required: true },
			value: { value: "bbb", required: false },
		},
		inputs: 1,
		outputs: 1,
		icon: "",
		label: function() {
			return this.name || "SampleNode"
		}
	});
</script>

<script type="text/x-red" data-template-name="sampleNode">
	<div class="form-row">
		<label for="node-input-name"><i class="icon-tag"></i> Name</label>
		<input type="text" id="node-input-name" placeholder="Name">
	</div>
	<div class="form-row">
		<label for="node-input-value"><i class="icon-tag"></i> Value</label>
		<input type="text" id="node-input-value" placeholder="Value">
	</div>
</script>

<script type="text/x-red" data-help-name="sampleNode">
	<p>A node that is only examine between private repository and Node-RED instance</p>
</script>
```

### 2.2.作成したRegistryへNodeをPublishする

npmの接続先を作成したPrivate Registryへ切り替える

```bash
npm set registry http://192.168.33.10:4873
```

publish用ユーザを作成する

```bash
npm adduser
```

作成したNode directory上でpublish!

```bash
npm publish
```

Nodeが追加された

![スクリーンショット 2016-12-18 11.52.05.png](https://qiita-image-store.s3.amazonaws.com/0/24177/bd4d70a3-98cf-6728-936c-20f6c03520f7.png "スクリーンショット 2016-12-18 11.52.05.png")

## 3.Private Node管理用ファイルの作成
### 3.1.Private Node追加用のファイルを作成する

Node-REDへPrivate Nodeを追加する際に必要なファイルは以下

* `package.json` ... [Node-RED](https://github.com/node-red/node-red/blob/master/package.json)のものを利用する
* `.npmrc` ... [npmの接続先をprivateへ切り替える為に必要](https://docs.npmjs.com/files/npmrc)

それぞれ以下のように編集/追加する

```json:package.json(抜粋)
{
    "name"         : "node-red",
    "version"      : "0.15.2",
...
    "dependencies": {
        "basic-auth": "1.0.4",
...
        "node-red-node-rbe":"0.1.*",
        "sample-node": "0.0.1"    ## 追加するNode
    },
...
}
```

```bash:.npmrc
registry=http://192.168.33.10:4873/
```

### 3.2.CloudFoundryへのdeploy用manifest.ymlを作成する

詳しくは[ここ](https://docs.cloudfoundry.org/devguide/deploy-apps/manifest.html)
今回は必要最小限の記載とした

```yaml:manifest.yml
---
applications:
- name: node-red
  memory: 128M
  disk_quota: 128M
```

### 3.3.Concourse用のpipelineやtaskを作成する

Concourse自身の説明については以下を参照
* [公式ドキュメント](http://concourse.ci/introduction.html)
* [ConcourseCI overview](http://www.slideshare.net/gwennetourneau/concourseci-overview)
* [はじめてのConcourse CI](https://blog.ik.am/entries/380)

今回NodeとNode-REDの管理を分離する為、以下のようなpipelineとした

```
[Node-REDのrelease code(from github)]
     |
     | <-(overwrite)- [3.1, 3.2のgithub repo]
     |
     ∨
[CloudFoundry] ## ここでnpm installされる
```

上記より、(Nodeがpublish済みであれば)上書き元のpackage.jsonを修正するだけで必要な構成のNode-REDインスタンスが用意できるようになる

今回はNode-REDの記事なのでConcourse用の[pipeline.yml](https://github.com/idahobean/node-red-deploy-config/blob/master/pipeline.yml)や[task.yml](https://github.com/idahobean/node-red-deploy-config/blob/master/integrate.yml), [script](https://github.com/idahobean/node-red-deploy-config/blob/master/scripts/ci)の説明は割愛する

## 4.動かしてみる

Githubに[configリポジトリ](https://github.com/idahobean/node-red-deploy-config)を作成する
login, pipelineの登録, pipelineのunpauseを実行

```bash:bash(pipeline.ymlのディレクトリ上で)
fly -t cci login
fly -t cci sp -p node-red-deploy -c pipeline.yml
fly -t cci up -p node-red-deploy
```

こんな感じのpipelineが登録される

![スクリーンショット 2016-12-18 16.11.10.png](https://qiita-image-store.s3.amazonaws.com/0/24177/80aaf46c-c61f-afae-5734-f60487414d0a.png "スクリーンショット 2016-12-18 16.11.10.png")

cloudfoundryへのdeploy時に作成したPrivate Nodeがinstallされていることが確認できる

![スクリーンショット 2016-12-18 16.14.09.png](https://qiita-image-store.s3.amazonaws.com/0/24177/a68150c2-5f82-6c90-8a8d-1a5eba5950d0.png "スクリーンショット 2016-12-18 16.14.09.png")

deployされたNode-REDインスタンスに作成したPrivate Nodeが追加されている事が確認できた

![スクリーンショット 2016-12-18 1.36.35.png](https://qiita-image-store.s3.amazonaws.com/0/24177/bcb78d90-e34c-74f4-303d-eba228a016b7.png "スクリーンショット 2016-12-18 1.36.35.png")

## 無停止は?

今回途中で説明を省略したが、Concourseが用意しているCloudFoundryへのdeploy用resourceは[autopilot](https://github.com/contraband/autopilot)プラグインが組み込まれている
その為、以下のようにpipelineを定義すれば、同名のappについては自動的にrenameやroute設定(無停止による切り替え)が実施される

```yaml:pipeline.yml(抜粋)
  - put: pcf-dev
    params:
      manifest: integrate-output/manifest.yml
      path: integrate-output
      current_app_name: node-red  ## 差し替えたいapp
```

## まとめ

Node-REDへPrivateなNodeを追加するときの実現方法について色々考えて実装/設定してみました
実運用下に持ち込む場合はまた別な部分(GitHub的な部分とか管理者の定義とか)が必要そうです

今回、CloudFoundryとしてPCF-devを用いてdeployを実施しましたが、[Cloud Foundry Certified Provider](https://www.cloudfoundry.org/use/cloud-foundry-certified/)であればどれも同様の定義でデプロイ可能です(たぶん)

動かなかったよ!という方がいらっしゃいましたらコメント/twitterまでご連絡下さい。