Node-REDのDockerコンテナをflowデータ付きでGKEにデプロイする

SensewayのLoRa無線モジュールを使って、室内環境センサーを作ってます。 CO２濃度と温度湿度気圧を記録しています。温室で使うのにちょうどいいと思います。もともとはオフィスで眠気に襲われることが多く、もしかしてCO2濃度高いんじゃないかと思ったのが作成のきっかけです。

下にあるのがセンサーユニット写真です。ArduinoにSenseway社のLoRaシールドを載せ、さらにその上にBME280温度湿度気圧センサーと、MH-Z19BのCO２センサーが載ってます。

![センサーユニットの写真](https://qiita-image-store.s3.amazonaws.com/0/96615/438c85d4-6cd8-aea8-710c-28405fd54f98.png)

※　CO2センサーは電気を食うので、乾電池駆動には少々無理がありました

開発自体は最近便利なツールが多いので、そんなに問題なかったのですが、個人でNode-REDを常時動かす環境に悩みました。所詮は３０分に一回のメッセージを拾うだけなので家にラズパイを置いてあげてもいいけど、家に置いておくとコンセント足りない問題が起きます。若い頃ならともかく、前職でサーバは都合7000台ほど、普通のエンジニアなら人生何回分かの面倒みたのでもう家にサーバを置くのは生理的に嫌なのです。というわけで、Herokuあたりに置いてやろうと思いました。

まてよ、開発はコンテナでやってるんだから、そのままコンテナデプロイできるKubernetesに置けばいいじゃないか、ということで、Google Cloud PlatformのGKE(Google Kuberenetes Engine)にデプロイすることにしました。北米ならf1-microの無料枠も使えます（現在、完全無料にする技は塞がれたようです）。どうせ外部公開ではないので、ロードバランサーも不要です。

しかし、これが案外手強いということを予想してませんでした。

# 事前知識

まずは、クイックスタートを一通り通しました。
https://cloud.google.com/kubernetes-engine/docs/quickstart?hl=ja


# 

今度は実際に使うクラスタの作成です。Node-REDは軽いので、f1-micro程度でも十分です。まえ、Apache NiFiを使ったことがあるのですが、あれはちょっとしたことに使うには重たすぎました。

```
PC% gcloud config set compute/zone us-central1-a
PC% gcloud config set project PROJECT-ID
PC% gcloud container clusters create --machine-type=f1-micro --num-nodes=3 my-cluster
PC% gcloud container clusters get-credentials my-cluster
```


# build and push

デプロイするDockerには、SensewayのLoRaサービスのmqttからデータを処理するため、senseway, kgpparser, kgpcomposerのモジュールを入れます。データはGoogle SpreadsheetにWebAPIで叩いて記録していくのですが、別途Amazon S3にも保存したいので、S3のモジュールも入れてあります。


```Dockerfile:Dockerfile(試行錯誤中)
 FROM nodered/node-red-docker
 RUN npm install node-red-contrib-senseway
 RUN npm install node-red-contrib-kgpparser
 RUN npm install node-red-contrib-kgpcomposer
 RUN npm install node-red-contrib-s3
```


```shell:デプロイ用スニペット
# ソースいじってると認証の時間切れするので、クレデンシャルの取得
% gcloud container clusters get-credentials my-cluster

# Dockerのビルドと、Dockerレポジトリへのプッシュ
PC%  gcloud builds submit --tag asia.gcr.io/$GCP_PROJECT/my-docker:<TAG> .
PC%  gcloud docker -- push asia.gcr.io/$GCP_PROJECT/my-docker

# このコマンドを入れると、イメージが切り替わってローリングデプロイされる
PC%  kubectl set image deployment mynodered mynodered=asia.gcr.io/$GCP_PROJECT/my-docker:<TAG>
```

## Node-REDのフロー設定がうまく反映されない

思ったより簡単にデプロイはできたのですが、まずプログラムにあたるflowがちゃんとセットされた状態でデプロイされません。これは、開発用Node-RED内Dockerにある/data/flows.jsonをレポジトリにコピーし、デプロイ用Dockerに配置してあげることで解決できます。ついでに、認証情報いりのflows_cred.jsonやsettings.jsも配置してあげましょう。

```
PC $ docker exec -it mynodered /bin/bash
docker% cd /data/
docker% ls
flows.json	 lib    flows_cred.json      node_modules  
settings.js      package.json  settings.js.new

# cat filenameして、レポジトリに内容をコピーしていく
```



```Dockerfile:Dockerfile(完成)
 FROM nodered/node-red-docker
 RUN npm install node-red-contrib-senseway
 RUN npm install node-red-contrib-kgpparser
 RUN npm install node-red-contrib-kgpcomposer
 RUN npm install node-red-contrib-s3

ADD ./data/flows.json /data/flows.json
ADD ./data/flows_cred.json /data/flows_cred.json
ADD ./data/settings.js /data/settings.js
```

## Sensewayの認証情報とS3のAPI Key/Secret Key情報がちゃんとロードできない

さて、これで動くはず、、、のはずが、Dockerのログを見ると、SensewayとS3の認証エラーがでています。「Error loading credentials: SyntaxError: Unexpected token」あたりです。

```
&gt; node-red-docker@1.0.0 start /usr/src/node-red
&gt; node $NODE_OPTIONS node_modules/node-red/red.js -v $FLOWS "--userDir" "/data"
 15 Sep 05:15:09 - [info] 
 Welcome to Node-RED
===================
 15 Sep 05:15:09 - [info] Node-RED version: v0.19.3
15 Sep 05:15:09 - [info] Node.js  version: v6.14.4
15 Sep 05:15:09 - [info] Linux 4.4.111+ x64 LE
15 Sep 05:15:10 - [info] Loading palette nodes
15 Sep 05:15:11 - [warn] rpi-gpio : Raspberry Pi specific node set inactive
15 Sep 05:15:11 - [warn] rpi-gpio : Cannot find Pi RPi.GPIO python library
15 Sep 05:15:13 - [info] Settings file  : /data/settings.js
15 Sep 05:15:13 - [info] Context store  : 'default' [module=memory]
15 Sep 05:15:13 - [info] User directory : /data
15 Sep 05:15:13 - [warn] Projects disabled : set editorTheme.projects.enabled=true to enable
15 Sep 05:15:13 - [info] Flows file     : /data/flows.json
15 Sep 05:15:13 - [info] Server now running at http://127.0.0.1:1880/
15 Sep 05:15:13 - [warn] Error loading credentials: SyntaxError: Unexpected token � in JSON at position 0
15 Sep 05:15:13 - [warn] Error loading flows: Error: Failed to decrypt credentials
15 Sep 05:15:13 - [info] Starting flows
15 Sep 05:15:13 - [warn] [amazon s3 put:putS3] Missing AWS credentials
15 Sep 05:15:13 - [info] Started flows
15 Sep 05:15:16 - [info] [mqtt-broker:SensewayMQTT] Connection failed to broker: mqtt://mqtt.senseway.net:1883
15 Sep 05:15:36 - [info] [mqtt-broker:SensewayMQTT] Connection failed to broker: 
```


どうやら、フローで書き込んだAPI Keyなどを保存したflows_cred.jsonの文字列を生成する際にデフォルトでcredentialSecretのseed値が動的に作られるので、デプロイ用には固定文字列にセットする必要があるそうです。settings.jsの設定を変えます。

そして落とし穴が。コンテナにviなんか入ってないのです。そしてsudoも使えない。しかたないのでsedで変換しました。


```
docker% cp settings.js settings.js.org
docker%% cat settings.js| sed -e 's/\/\/credentialSecret: "a-secret-key",/credentialSecret: "MyCredentialString",/' > settings.js.new

docker% diff settings.js.new settings.js.org
76c76
<     credentialSecret: "MyCredentialString",
---
>     //credentialSecret: "a-secret-key",


docker% cp settings.js.new settings.js
```

さて、情報によればこれでNode-REDを再起動しフローのデプロイしなおせば動くと書いてありましたが、動きませんでした。ファイルのタイムスタンプも変わってません。

正解は、flows_cred.jsonを削除してから、Docker再起動とフローの再デプロイでした。

```shell
docker% rm flows_cred.json

PC% docker stop mynodered
PC% docker start mynodered

PC $ docker exec -it mynodered /bin/bash
docker% cat /data/flows_cred.json

```

新しくできたflows_cred.jsonをレポジトリにセットし、Dockerの再ビルドとデプロイ。
さあどうだ、動いた！

```
&gt; node-red-docker@1.0.0 start /usr/src/node-red
&gt; node $NODE_OPTIONS node_modules/node-red/red.js -v $FLOWS "--userDir" "/data"
 15 Sep 05:36:25 - [info] 
 Welcome to Node-RED
===================
 15 Sep 05:36:25 - [info] Node-RED version: v0.19.3
15 Sep 05:36:25 - [info] Node.js  version: v6.14.4
15 Sep 05:36:25 - [info] Linux 4.4.111+ x64 LE
15 Sep 05:36:26 - [info] Loading palette nodes
15 Sep 05:36:27 - [warn] rpi-gpio : Raspberry Pi specific node set inactive
15 Sep 05:36:28 - [warn] rpi-gpio : Cannot find Pi RPi.GPIO python library
15 Sep 05:36:30 - [info] Settings file  : /data/settings.js
15 Sep 05:36:30 - [info] Context store  : 'default' [module=memory]
15 Sep 05:36:30 - [info] User directory : /data
15 Sep 05:36:30 - [warn] Projects disabled : set editorTheme.projects.enabled=true to enable
15 Sep 05:36:30 - [info] Flows file     : /data/flows.json
15 Sep 05:36:30 - [info] Starting flows
15 Sep 05:36:30 - [warn] [amazon s3 put:putS3] Missing AWS credentials
15 Sep 05:36:31 - [info] Started flows
15 Sep 05:36:31 - [info] Server now running at http://127.0.0.1:1880/
15 Sep 05:36:31 - [info] [mqtt-broker:SensewayMQTT] Connected to broker: mqtt://mqtt.senseway.net:1883
```

これで、無事にデータが取れるようになりました。S3がまだ動いてないけど、まあいいか。。。

<img width="877" alt="室内環境_-_Google_スプレッドシート.png" src="https://qiita-image-store.s3.amazonaws.com/0/96615/089d0a77-4d22-5305-a243-e19f62bd2fa0.png">