IBM Cloud 上の Node-RED 環境における Storage API によるデータの永続化

前から気になっていて、ちょこちょこ調べていた件が理解できたので、メモまとめておきます。

# IBM Cloud 上の Node-RED 環境とデータの永続化

[IBM Cloud](https://ibm.biz/BdzB7B) のカタログに Node-RED Starter ってあって、数分で手軽に、無料の Node-RED 環境が構築できて重宝している訳なのですが、
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/193519/53a76ba3-e7c7-845b-1f2e-318a12750173.png)
前からこの環境がどういった仕組みで動いているのか、ちょっと謎に思っていました。特にデータの永続化の観点から。

通常のローカル環境で動作している Node-RED だと、普通に設定ファイルを用いて、いろいろな情報を管理しています。しかし Cloud 環境の Cloud Foundry などの環境では、ファイルに保存したデータの永続性は保証されません。何かしらの永続化の仕組みが必要になってきます。

# Storage API によるデータの保持

鍵となる機能は Node-RED における [Storage API](https://nodered.jp/docs/api/storage/) サービスです。「Node-REDランタイムがどこにデータを格納するか設定するため」のAPIで、まさに Node-RED を Cloud 環境などに適用させるために用意された機能に思われます。

# IBM Cloud における実装

IBM Cloud における Node-RED Starter 用のコードですが、探したところ [node-red-app](https://github.com/IBM/node-red-app) が参考になりそうです。

最初から追ってみましょう。まず Node-RED アプリの起動ですが、[package.json](https://github.com/IBM/node-red-app/blob/master/package.json#L22) にパラメーターの指定があります。

```json:package.json
"scripts": {
  "start": "node --max-old-space-size=160 index.js --settings ./bluemix-settings.js -v"
},
```
[index.js](https://github.com/IBM/node-red-app/blob/master/index.js) と [bluemix-settings.js](https://github.com/IBM/node-red-app/blob/master/bluemix-settings.js) が主要なファイルであることがわかります。

これらファイルから Storage API に関する記述を探してみると、[bluemix-settings.js の後半](https://github.com/IBM/node-red-app/blob/master/bluemix-settings.js#L104) に以下のコードが見つかります。

```js:bluemix-settings.js
    }
    util.log("Using Cloudant service: "+settings.cloudantService.name+" db:"+settings.cloudantService.db+" prefix:"+settings.cloudantService.prefix);
    settings.storageModule = require("./cloudantStorage");
}

```

ようやく見えてきました。ここで storageModule に指定されている [cloudantStorage.js](https://github.com/IBM/node-red-app/blob/master/cloudantStorage.js) が、IBM Cloud 上でデータの永続性を提供するためのコード、Storage API の実装部分です。

例えばガイドにある [getFlows()](https://github.com/IBM/node-red-app/blob/master/cloudantStorage.js#L143) 関数は以下のように NoSQL DB をアクセスするよう記述されています。

```js:cloudantStorage.js
getFlows: function () {
    var key = appname + "/" + "flow";
    return when.promise(function (resolve, reject) {
        flowDb.get(key, function (err, doc) {
            if (err) {
                if (err.statusCode != 404) {
                    reject(err.toString());
                } else {
                    resolve([]);
                }
            } else {
                currentFlowRev = doc._rev;
                resolve(doc.flow);
            }
        });
    });
},
```

ガイドにあるように、元の [runtime/lib/storage/localfilesystem](https://github.com/node-red/node-red/blob/master/packages/node_modules/%40node-red/runtime/lib/storage/localfilesystem/index.js) と比べると、実装の差がより理解できそうです。

# DB のほうから確認してみる

さてこれで全体が見えた気がしますが、確認のため、IBM Cloud 上にある Cloudant DB の設定を見ておきましょう。これは Node-RED Starter アプリ作成の際に自動的に生成されたものです。

Cloudant DB の管理コンソールを起動すると、`nodered` という DB が作成されており、その中に4つの文書が存在することがわかります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/193519/3cb41d1a-ab1a-0294-5d6c-410267338888.png)
この中の例えば ID に /flow と名のついた文書を開いてみると、いま作成しているフローの情報が格納されているのが、確認できます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/193519/6fc8c16d-36d9-a68f-a6d8-1856751fba3b.png)

うん、実行環境に作成されるファイルではなくて、この NoSQL (Cloudant) DB でデータの永続化が実現されているのは間違いなさそうですね。

# というわけで

今回は Node-RED における、Storage API を用いた、NoSQL DBへのデータ保存(永続化)の例を確認しました。

例えばローカルな Node-RED 環境で動作する TJBot などでも、Storage API を用いた Cloud 上でのデータ永続化を用いて、それを MAC 値などと連携して使用することで、数十台を対象としたデモ環境を容易にオーケストレーション的に管理できるようなシステムも組めるかもしれませんね。

Cloud Foundry だけでなく、Docker/Kubernetes や OpenShift 環境においてもデータの永続化、アプリからの分離と実装場所の課題は重要だと思われます。普段お世話になっている IBM Cloud 上の Node-RED にもひとつ、そのヒントが隠されていた、ということで。ちょっと楽しいですね。

それではまた！