SensewayのLoRa無線モジュールを使って、室内環境センサーを作ってます。 CO2濃度と温度湿度気圧を記録しています。温室で使うのにちょうどいいと思います。もともとはオフィスで眠気に襲われることが多く、もしかしてCO2濃度高いんじゃないかと思ったのが作成のきっかけです。
下にあるのがセンサーユニット写真です。ArduinoにSenseway社のLoRaシールドを載せ、さらにその上にBME280温度湿度気圧センサーと、MH-Z19BのCO2センサーが載ってます。
※ CO2センサーは電気を食うので、乾電池駆動には少々無理がありました
開発自体は最近便利なツールが多いので、そんなに問題なかったのですが、個人でNode-REDを常時動かす環境に悩みました。所詮は30分に一回のメッセージを拾うだけなので家にラズパイを置いてあげてもいいけど、家に置いておくとコンセント足りない問題が起きます。若い頃ならともかく、前職でサーバは都合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のモジュールも入れてあります。
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
# ソースいじってると認証の時間切れするので、クレデンシャルの取得
% 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して、レポジトリに内容をコピーしていく
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」あたりです。
> node-red-docker@1.0.0 start /usr/src/node-red
> 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再起動とフローの再デプロイでした。
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の再ビルドとデプロイ。
さあどうだ、動いた!
> node-red-docker@1.0.0 start /usr/src/node-red
> 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がまだ動いてないけど、まあいいか。。。