概要
ちょっとした検証で、GCP Cloud IoT CoreにGolangでMQTT接続したかったんですが思いの外苦労したので、記録に残します。
ネットワーク関係はつながるまでが大変でつながる設定ができてしまうと簡単なのを再確認しました。
今回の検証から作ったコードは会社のリポジトリに置いてます: https://github.com/fusic/gcp-iot-core-golang-sample
パラメーターとかをうまいこといじると簡単に流用できるはずです。
基本情報
事前に会社の先輩(@Kta-M)がわかりやすく情報をまとめてくださってたのでそれをまず引用させてもらいます:
### IoT Core概要
https://cloud.google.com/iot/docs/
Cloud Pub/Subとデバイスとの仲介をするためのサービス、というイメージ。
Pub/Subはメッセージングサービス。AWSでいうとKinesisが対応付けられるらしい。
https://dev.classmethod.jp/cloud/aws/aws-gcp-fit-and-gap-2016-07/
Topicを作成してそこにメッセージを送り、そのTopicをSubscribeすることでデータを得られる。
IoT Coreは、デバイス管理機構とデータ送信用のエンドポイントを提供して、
デバイスからのデータをPub/Subの指定されたTopicに流す。
MQTTS接続パラメータ
- host: mqtt.googleapis.com
- port: 8883
- clientID: "projects/[プロジェクトID]/locations/[リージョン]/registries/[レジストリID]/devices/[デバイスID]"
- username: "unused"
- password: jwtを使って生成
- iat: 現在時刻のUnixTime,
- exp: 現在時刻+60分のUnixTime : 有効期限。期限を過ぎると接続が解除されるので、都度接続確認を行なう。
- aud: projectID
- Signin Method: SigningMethodRS256
- SigningKey: 添付のpem
https://github.com/GoogleCloudPlatform/nodejs-docs-samples/blob/master/iot/mqtt_example/cloudiot_mqtt_example_nodejs.js
#### JWT(Json Web Token)
- https://jwt.io/
- https://github.com/dgrijalva/jwt-go
- https://godoc.org/github.com/dgrijalva/jwt-go#NewWithClaims
- https://kamichidu.github.io/post/2017/01/24-about-json-web-token/
- https://qiita.com/kaiinui/items/21ec7cc8a1130a1a103a
※ exp
ですが、公式のドキュメントなどを見ると 20分
という数字のほうが使われるので実際はこちらの数字の方がいいのかもしれません。
実装の苦労とか
公式のトラブルシューティングにもかいてあるんですが、MQTT 3.1.1を指定しないといけません:
If the device disconnects immediately after connecting, verify that your MQTT client library is using MQTT 3.1.1. Many libraries default to MQTT 3.1, which is not supported by Cloud IoT Core and will cause the device to be disconnected immediately. The version is typically set in the MQTT library's client options when first connecting.
(抄訳: デバイスで接続がすぐに切断される場合はMQTTのクライアントライブラリがMQTT 3.1.1を使っているのを確認しましょう。 多くのライブラリの初期設定は3.1ですが、Cloud IoT Coreでサポートされないためすぐに切断されます。プロトコルのバージョンは最初に接続する時に設定される場合が多いです。)
ドキュメントに書いてある通り、paho系のライブラリも、接続クライアントを生成する前に指定します。
プロトコルのバージョンを確認するのは大事ですね。
一日くらいずっと↑の問題で悩んでいたんですが、それの検証でnode.jsのサンプルを動かしたりとなかなか大変でした。
それから、pem形式になっている秘密鍵を読み込むのもけっこうめんどうでした。
pem形式の読み込みはjwt-goで提供している関数を使うと簡単にできました。
あんまり今回とは関係ないんですが、MQTT接続時のタイムアウトは5秒くらいもたないとつらいという知見も得ました。
何も考えずに1秒以下に設定したところテストで落ちるという醜態を晒してしまったので。
GolangのJSON Web Tokenに関してはいい記事があったので簡単にできてとても助かりました。