この文書について
先日ベータ版が公開されたAWS IoT(AWS上でサーバーインスタンスを自分で用意する事なくMQTTブローカー(+α)のサービスを利用できる)をRubyクライアント(ruby-mqtt)から試してみた個人的なメモです。
本家のクイックスタートを見つつ、AWS IoT Message BrokerのMQTTでpub/subをやってみたも参考にさせて頂きつつやってた覚書ですが、現時点(2015/10/14)でAWS IoTはベータ版であり、今後サービスの仕様が変わる可能性があるため、できるだけ本家のドキュメントを参照される事をおすすめします。
AWS IoTではクライアント側のSDKも提供されているようですが、今回はオープンソースで公開されているMQTTクライアントを使ってPub/Subを試してみます。
AWS IoTの概念についてはLearn how AWS IoT works with this interactive tutorialで図解入りでわかりやすく説明されているので、こちらを参照。以下は同ページのスクリーンショット。RGBのスイッチの状態がMQTTブローカーを通して別のデバイスやストレージ、AWS上の別のサービスと連携する様子が示されています。
AWS CLIの準備
すでに最新のAWS CLIをインストール済みの場合は、この項目は飛ばしてかまいません。
$ sudo pip install awscli --upgrade
なお、AWS CLIの詳細なインストール方法に関してはGetting Set Up with the AWS Command Line Interfaceを参照のこと。
Thingを登録する
MQTTクライアントからMQTTブローカーに接続するには Thing
を登録する必要があるとのこと。以下のようにして sample_things
という名前で登録しました。
$ aws iot create-thing --thing-name "sample_things"
現在登録されているThingのリストは以下のコマンドで確認できます。
$ $ aws iot list-things
{
"things": [
{
"attributes": {},
"thingName": "sample_things"
},
{
"attributes": {},
"thingName": "my_things"
}
]
}
先ほど登録した sample_things
の他に以前私が登録した my_things
も表示されています。
AWS IoTとThing間でのセキュアな通信のための準備
証明書の用意
先ほど登録した Thing
と AWS IoT
間のセキュアな通信のために、X.509証明書を作成します。
以下のコマンドで、証明書とキーペアを cert.json
というファイルに書き出します。
$ aws iot create-keys-and-certificate --set-as-active > cert.json
cert.json
の中身はJSONフォーマットですので、ファイルから秘密鍵と公開鍵をそれぞれ thing-public-key.pem
と private-key.pem
というファイルに書き出します。
(なお、ローカルに jq
コマンドがインストールされていない場合は $ brew install jq
すること)
$ cat cert.json | jq .keyPair.PublicKey -r > thing-public-key.pem
$ cat cert.json | jq .keyPair.PrivateKey -r > private-key.pem
証明書を cert.pem
という名前のファイルとして書き出します。
$ aws iot describe-certificate --certificate-id "<here-is-your-certificate-id>" --output text --query certificateDescription.certificatePem > cert.pem
'<here-is-your-certificate-id>' の部分に先ほどの cert.json
の最終行付近にある "certificateId"
として与えられた文字列を入れて実行します。
AWS IoTポリシーを作成して証明書に紐付ける
以下のような内容で policy.json
というファイルを新規に作成します。
{
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Action":["iot:*"],
"Resource": ["*"]
}]
}
作成したファイルへのパスをコマンド引数に渡して PubSubToAnyTopic
という名前のポリシーを作成します。
$ aws iot create-policy --policy-name "PubSubToAnyTopic" --policy-document file://policy.json
作成した証明書とポリシーを紐付けます。
$ aws iot attach-principal-policy --principal "<certificate-arn>" --policy-name "PubSubToAnyTopic"
'<certificate-arn>' のところには、先ほどの cert.json
中で "certificateArn"
として渡された文字列( "arn:aws:iot:ap-northeast-1::..."
) を入れます。
証明書をThingに紐付ける
さて、最後に証明書とThingを紐付けます。
$ aws iot attach-thing-principal --thing-name "<thing-name>" --principal "<certificate-arn>"
<thing-name>
のところには最初に登録したThingの名前が入ります。今回で言えば sample_things
になりますね。
<certificate-arn>
のところには、先ほどと同じく cert.json
の中で、"certificateArn"
として与えられた文字列( "arn:aws:iot:ap-northeast-1::..."
)が入ります。
お疲れ様でした、これでAWS IoTを使ってPub/Subする準備が整いました。
Ruby ClientでPub/Subしてみる
MQTT クライアントライブラリのインストール
AWSのクイックスタートではMosquittoのPub/Subクライアントを使ってテストしていますが、私はRubyプログラマなのでRubyを使ってやってみます。
MQTTのRubyクライアントとしてはgithub.com/njh/ruby-mqttがあります。
インストールはgemで
$ gem install mqtt
ルート証明書のダウンロード
また、ルート証明書を rootCA.pem
というファイル名でカレントディレクトリに落としておきます。
$ wget https://www.symantec.com/content/en/us/enterprise/verisign/roots/VeriSign-Class%203-Public-Primary-Certification-Authority-G5.pem -O rootCA.pem
MQTTブローカーエンドポイントの確認
それと、MQTTブローカーのエンドポイントはAWSのアカウントごとに用意されています。自分のアカウントのエンドポイントを確認するには、以下のようにします。
$ aws iot describe-endpoint
{
"endpointAddress": "AAAAAAAAAAA.iot.ap-northeast-1.amazonaws.com"
}
この場合は AAAAAAAAAAA.iot.ap-northeast-1.amazonaws.com
が自分のアカウントのエンドポイントということになります。
ポートは共通で 8883
です。
Ruby製Subscriberの用意
データを待機するSubscrberは以下のように書きました。
require "mqtt"
MQTT::Client.connect(host: "AAAAAAAAAAA.iot.ap-northeast-1.amazonaws.com",
port: 8883,
ssl: true,
cert_file: "cert.pem",
key_file: "thing-private-key.pem",
ca_file: "rootCA.pem") do |client|
client.subscribe("topic/test")
topic,message = client.get #ここでブロックする
p [topic, message]
end
Ruby製Publisherの用意
データを送信するPublisherは以下のように
require "mqtt"
MQTT::Client.connect(host: "AAAAAAAAAAA.iot.ap-northeast-1.amazonaws.com",
port: 8883,
ssl: true,
cert_file: "cert.pem",
key_file: "thing-private-key.pem",
ca_file: "rootCA.pem") do |client|
client.publish("topic/test", "From Ruby!")
end
実際にPub/Subしてみる
まずは sub.rb
を実行。
$ ruby sub.rb
この時点でSubscriberがデータを待機してブロックします。
続いて pub.rb
を実行。
$ ruby pub.rb
pub.rb
はデータをパブリッシュしたらすぐに終了します。直後にブロックしていた sub.rb
側で以下のように受信したデータを表示します。
$ ruby sub.rb
["topic/test", "From Ruby!"]
料金
AWS IoTの課金体系については、この文書を書いている段階で以下のように公表されています。
- US East (N. Virginia): $5 per million messages
- US West (Oregon): $5 per million messages
- EU (Ireland): $5 per million messages
- Asia Pacific (Tokyo): $8 per million messages
東京リージョンだけ、ちょっとお高いですね。ただ実装するアプリケーションがリアルタイム性を重視するなら、やはり日本国内では東京リージョンを使うことになるでしょう。
感想など
最初の手順が若干必要ですが、順を追って一つづつやっていけば簡単にMQTTブローカーを利用できるようになります。EC2で自分でサーバーインスタンスを立ち上げる必要もなく、またサーバーインスタンスの保守・運用についても考慮することなくセキュリティを考慮されたMQTTブローカーが使用できるというのは、これからMQTTを使ったアプリケーション開発を始める人にとってはとっても楽チンで、とりあえずMQTTを使って端末間の通信を実現したい場合には第一候補になるサービスと感じました。
ただ、本当にシビアな、多数のクライアントから多数のメッセージが送られてくるような場合は、どこかで自前のサーバーを用意したほうが安くつく分岐点があるのだろうと予想しますが、その分岐点がどこになるかは今の私にはわかりません。
AWS IoTは純粋なMQTTブローカーとしても使用できますが、やはりAWSでMQTTする場合の最大の魅力は、AWSの他のサービスとの連携だと思います。次回以降でそのあたりも色々やってみたいと思います。それと Shadow
という機能も気になりますね。こっちも色々やってみます。