【Nutanix Karbon】Kubernetes 上に Node-Red を作ってみる
Xi IoT でkubernetes Apps にチャレンジする前にもう少し Karbon で遊んでみます
Xi IoT でもよく使う Node-Red をKarbon 上に実装し、Xi IoT と繋いでみる実験にチャレンジです。
Node-RedのPod/Serviceを作る
いまだに Kubernetes のまにゅふぇすと(?)yaml は慣れないですが
まずは見よう見まねで pod と service を作って、動作確認してみます
nodered_sample.yaml
apiVersion: v1 kind: Service metadata: name: node-red namespace: kon-ns spec: type: NodePort selector: app: node-red ports: - name: node-red port: 1880 nodePort: 31880 --- apiVersion: apps/v1 kind: Deployment metadata: name: node-red namespace: kon-ns spec: replicas: 1 selector: matchLabels: app: node-red template: metadata: name: node-red labels: app: node-red spec: containers: - name: node-red image: nodered/node-red:1.0.6-2 ports: - containerPort: 1880
即、作ってみる(なんていうの?)
PS > kubectl apply -f .\nodered.yaml service/node-red created deployment.apps/node-red created
案外サクッと、見覚えのあるページにつながりました
http://<KarbonクラスタIP>:31880/
Node-RedのStatefulSetを作る
StatefulSet のことはまだよく理解していないのですが、これで作っておいた方が良いと聞いたのでトライしてみます
pod を作り直してもデータが残っている永続ボリューム(PV/PVC)と言われる外付けストレージを持てるのが、うれしいことのようです
ハマったポイント
きっと k8s初心者だからなのですが、まずこの PVC を使うことによってハマったポイントから
StatefulSet で単純にボリュームをマウントしてみると、pod 作成で失敗してしまいます
PS > kubectl get all NAME READY STATUS RESTARTS AGE pod/nodered-stateful-0 0/1 CrashLoopBackOff 3 78s
pod のログを確認してみますと、何やら "permission denied" と出ています
コンテナを作って、マウントした PVC へをコピーする時の権限周りで怒られているようです
> kubectl logs pod/nodered-stateful-0 > node-red-docker@1.0.6 start /usr/src/node-red > node $NODE_OPTIONS node_modules/node-red/red.js $FLOWS "--userDir" "/data" fs.js:114 throw err; ^ Error: EACCES: permission denied, copyfile '/usr/src/node-red/node_modules/node-red/settings.js' -> '/data/settings.js' at Object.copyFileSync (fs.js:1728:3) at copyFile (/usr/src/node-red/node_modules/fs-extra/lib/copy-sync/copy-sync.js:68:8) at onFile (/usr/src/node-red/node_modules/fs-extra/lib/copy-sync/copy-sync.js:53:25) at getStats (/usr/src/node-red/node_modules/fs-extra/lib/copy-sync/copy-sync.js:48:44) at startCopy (/usr/src/node-red/node_modules/fs-extra/lib/copy-sync/copy-sync.js:38:10) at handleFilterAndCopy (/usr/src/node-red/node_modules/fs-extra/lib/copy-sync/copy-sync.js:33:10) at Object.copySync (/usr/src/node-red/node_modules/fs-extra/lib/copy-sync/copy-sync.js:26:10) at Object.<anonymous> (/usr/src/node-red/node_modules/node-red/red.js:108:20) at Module._compile (internal/modules/cjs/loader.js:778:30) at Object.Module._extensions..js (internal/modules/cjs/loader.js:789:10) npm ERR! code ELIFECYCLE npm ERR! errno 1 npm ERR! node-red-docker@1.0.6 start: `node $NODE_OPTIONS node_modules/node-red/red.js $FLOWS "--userDir" "/data"` npm ERR! Exit status 1 npm ERR! npm ERR! Failed at the node-red-docker@1.0.6 start script. npm ERR! This is probably not a problem with npm. There is likely additional logging output above.
Node-Red のユーザサイトを確認してみると
Dockerで実行する : Node-RED日本ユーザ会
「 コンテナ内のnode-redユーザ(デフォルトではuid=1000)」との記載があり、なんとなく id を 1000 にすればよさそうなので
悩んだ末にこれを追記してみます
securityContext: fsGroup: 1000
(これが Karbon の仕様であるのか、k8s ってそういうもんなのかは知らないです。。。)
完成した StatefulSet の yaml
とりあえずこれで、無事 pod が作れました
apiVersion: v1 kind: Service metadata: name: nodered-stateful spec: type: NodePort selector: app: nodered-stateful ports: - name: nodered-http port: 1880 nodePort: 31880 protocol: TCP --- apiVersion: "apps/v1" kind: "StatefulSet" metadata: name: nodered-stateful spec: serviceName: nodered-stateful selector: matchLabels: app: nodered-stateful replicas: 1 template: metadata: name: nodered-stateful labels: app: nodered-stateful spec: securityContext: fsGroup: 1000 terminationGracePeriodSeconds: 10 containers: - name: node-red image: nodered/node-red:1.0.6-2 ports: - containerPort: 1880 volumeMounts: - name: nodered-data mountPath: /data volumeClaimTemplates: - metadata: name: nodered-data spec: accessModes: [ "ReadWriteOnce" ] resources: requests: storage: 5Gi
これでpod を作り直してもユーザデータが残せるようになりました!
Karbon 上で MQTT の通信テスト
Node-Red の GUI につながったので、せっかくなので MQTT のテスト行ってみます
(将来のXi IoTの為に)
Node-Red と繋ぐ MQTTブローカーを用意してやる必要があります
お手軽 MQTTブローカーとして mosquitto というのがあるので、これを使ってみます
Eclipse Mosquitto
Karbon 上でMQTTするパターン
早速 Karbon 上に mosquitto を作ってみます
apiVersion: v1 kind: Service metadata: name: mosquitto spec: selector: app: mosquitto ports: - name: mosquitto-mqtt port: 1883 --- apiVersion: apps/v1 kind: Deployment metadata: name: mosquitto spec: replicas: 1 selector: matchLabels: app: mosquitto template: metadata: name: mosquitto labels: app: mosquitto spec: containers: - name: mosquitto image: eclipse-mosquitto ports: - containerPort: 1883
mosquitto のクラスタIPを確認し Node-Red からMQTT接続してみます
PS > kubectl get svc NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE grafana NodePort 192.199.36.69 <none> 3000:30300/TCP 8d mosquitto ClusterIP 192.199.93.240 <none> 1883/TCP 5h25m nodered-stateful NodePort 192.199.18.30 <none> 1880:31880/TCP 79m
Node-Red側で、mqttノードに mosquitto のIPとポートを登録
これで MQTT で一人 Pub/Sub できました(マッチポンプ)
ちなみに作ったフローを書き出しておきます
[{"id":"1d0bc5c2.18629a","type":"tab","label":"フロー 1","disabled":false,"info":""},{"id":"533670bc.25016","type":"mqtt in","z":"1d0bc5c2.18629a","name":"","topic":"test","qos":"2","datatype":"auto","broker":"7ad11645.de9188","x":130,"y":200,"wires":[["93a262b5.62409"]]},{"id":"93a262b5.62409","type":"debug","z":"1d0bc5c2.18629a","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","x":350,"y":220,"wires":[]},{"id":"84f0acab.6cbda","type":"mqtt out","z":"1d0bc5c2.18629a","name":"","topic":"test","qos":"","retain":"","broker":"7ad11645.de9188","x":330,"y":120,"wires":[]},{"id":"81714c3d.fe9a","type":"inject","z":"1d0bc5c2.18629a","name":"time","topic":"data/time","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":130,"y":100,"wires":[["84f0acab.6cbda"]]},{"id":"7ad11645.de9188","type":"mqtt-broker","z":"","name":"","broker":"192.199.93.240","port":"1883","clientid":"","usetls":false,"compatmode":false,"keepalive":"60","cleansession":true,"birthTopic":"","birthQos":"0","birthPayload":"","closeTopic":"","closeQos":"0","closePayload":"","willTopic":"","willQos":"0","willPayload":""}]
Karbon 外部とMQTTするパターン
VM上で mosquitto のコンテナを作って、ポート 31883 を公開してみます
(あえてポート変えてみた)
docker run -it -p 31883:1883 --name mybroker eclipse-mosquitto
Node-Red の MQTTノードも、VMの IPアドレスと 31883 に変更してやればすんなり Pub/Sub できました
ハマった時は
ちなみにうまくいかなかった時には、Node-Red(pod or serviceどちらでもOK)へシェルで入って確認するとよいですね
PS > kubectl exec -it pod/nodered-stateful-0 sh ~ $ nc -zv 172.16.101.126 31883 172.16.101.126 (172.16.101.126:31883) open
(ここでかなりつまづきました。。。。)
で、Xi IoTへ繋げたのか?
Xi IoTへMQTTを飛ばそうと試みたのですが、なんかポートがふさがっててうまく繋げなかったので、Xi IoT側の仕組みをもうちょっと勉強してみたいと思います
Nutanix Karbon公式ページこちら
www.nutanix.com