[IoT] Docker on JetsonでMQTTを使ってCloud IoT Coreと通信する
ドーモ、好きなキリンはPhippy<sup>1</sup>な吉海です。今回はみんな大好きJetsonからDockerを使ってメッセージをMQTTでCloud IoT Coreに送信する方法をご紹介します。JetsonはNVIDIAが開発したエッジデバイスでGPUを搭載しています。Raspberry Piを知っている人であれば、強いRaspberry Piを想像すると分かりやすいかと思います。Cloud IoT CoreはGoogleが提供しているIoTのエッジデバイスの接続、管理、データ取り込みを行うためのフルマネージドサービスです。
なぜCloud IoT Coreを使うのか
今回はフルマネージドのMQTTのブローカ−として、Cloud IoT Coreを使いました。Cloud IoT Core<sup>2</sup>はCloud Pub/Subと簡単に連携することが出来るので、IoTのエッジデバイスからメッセージをCloud Pub/Subに送り各種Googleのサービスと連携することが容易に出来ます。
構成
Jetsonで動作しているDockerコンテナ上のMQTTクライアントからCloud IoT Coreのトピック3にメッセージをパブリッシュしてCloud IoT Coreと連携しているCloud Pub/Subのトピックでサブスクライブする構成です。
手順
- Cloud IoT Core
- Cloud IoT Core API を有効にする
- レジストリと端末を作る
- Jetson
- Dockerイメージの作成
Cloud IoT Core API を有効にする
まず、Cloud IoT Core API を有効にする必要があるので、公式のGetting StartedのBefore you beginを参考にCloud IoT Core API 有効にしましょう。
図2. Cloud IoT Core API を有効にする
レジストリと端末を作る
次にIoT Coreにレジストリと端末を作成していきます。端末はレジストリに紐づくので、先にレジストリを作ります。
公式のCreating a device registryを参考にレジストリの作成のページを開き、必要な情報を入力しましょう。
レジストリIDに適当な値、リージョンを選択、プロトコルはMQTTを選択、Cloud Pub/Subは既存のトピックを選択するか、新しいトピックを作成して指定することが出来ます。Stackdriver Loggingはデバッグしやすくするために私はDebugにしました。動作がおかしい場合にログを確認することがあるのでエラー以上には設定したほうがいいと思います。
レジストリが作成できたら、次は公式 Creating or editing a deviceを参考にレジストリの詳細画面に移動して端末を作成していきます。
図4. 端末の作成
端末IDに適当な値、端末との通信は許可、認証は手動で入力、公開鍵の形式はRS256、公開鍵の値には公式 Creating Public/Private Key PairsのGenerating an RS256 keyを参考に公開鍵を作成して、rsa_public.pemという名前の公開鍵の値を貼り付けてください。
Dockerイメージの作成
Jetsonの環境を汚さないようにDockerを使ってMQTTのクライアントを動かします。Dockerのイメージとイメージを動かすマシンのCPUのアーキテクチャを合わせる必要があるので、arm64v8のイメージをFROMにしたDockerfileを作成します。MQTTのクライアントは公式がサンプルを提供しているので、それを使います。
手順を簡略化するために、Jetson上でDocker buildをしてそのままそのイメージを使う方法をご紹介します。
手順1. Google Cloud Platform Python Samplesをgit pull して、iot/api-client/mqtt_exampleに移動する
git pull git@github.com:GoogleCloudPlatform/python-docs-samples.git
cd python-docs-samples/iot/api-client/mqtt_example
手順2 下記の内容をコピーしてDockerfileを作成する
FROM arm64v8/python:3.7.1-stretch
COPY requirements.txt /tmp
RUN pip install -r /tmp/requirements.txt && rm -f /tmp/*
# cloudiot_mqtt_example.pyの--ca_certsに指定するroots.pem
RUN curl -o /etc/roots.pem https://pki.google.com/roots.pem
手順3 Docker buildしてイメージを作る
docker build -t mqtt .
動作確認
先程作成したイメージを実行して、メッセージをパブリッシュしてみましょう。
パブリッシュ
docker run -it -v `pwd`:/opt mqtt python /opt/cloudiot_mqtt_example.py \
--project_id={project_id} --device_id={device_id}--private_key_file=/opt/mqtt/rsa_private.pem \
--registry_id={registry_id}--algorithm=RS256 \
--ca_certs=/etc/roots.pem --cloud_region={レジストリと同じリージョン}
{project_id}、{device_id}、{registry_id}、{レジストリと同じリージョン}は、適切な値に書き換えて実行してください。
次にgcloud コマンドを使ってCloud Pub/Subのトピックをサブスクライブしてみましょう。
サブスクライブ
gcloud beta pubsub subscriptions create --topic {cloud iotと連携しているトピック名} {your-subscriptions}
gcloud beta pubsub subscriptions pull --auto-ack {your-subscriptions}
{your-subscriptions}には好きななサブスクリプション名を設定してください。サブスクライブするのに必ずサブスクリプションを作る必要があります。
パブリッシュしたメッセージがサブスクライブ出来ている場合は、下記のような結果が得られるはずです。
┌─────────────────────────┬─────────────────┬───────────────────────────────────┐
│ DATA │ MESSAGE_ID │ ATTRIBUTES │
├─────────────────────────┼─────────────────┼───────────────────────────────────┤
│ jetson/jetson-payload-3 │0000000000000000 │ deviceId=jetson │
│ │ │ deviceNumId=0000000000000000 │
│ │ │ deviceRegistryId=jetson │
│ │ │ deviceRegistryLocation=asia-east1 │
│ │ │ projectId=test │
│ │ │ subFolder= │
└─────────────────────────┴─────────────────┴───────────────────────────────────┘
備忘録
Cloud IoT Coreのトピックについて
Cloud IoT Coreにはデフォルトで下記のトピックが用意されています。トピックはパブリッシュ用とサブスクライブ用で分かれているようです。なので、パブリッシュ用のトピックにサブスクライブしたりするとエラーになるので気をつけてください。自分はこれで少しハマりました。ちなみにサンプルのプログラム上だとエラーが発生しないが、Cloud IoT CoreのStackdriver Loggingにエラーが記録される場合があるので気をつけてください。
パブリッシュ用
- events
- status
サブスクライブ用
- commands
- config
ちなみにログはレジストリの詳細のページのログを表示で確認することが出来ます。
図5. ログを表示
さいごに
弊社ではJetsonなどのエッジデバイス使ったIoT開発が本格始動しており、IoTをやりたいエンジニアを求めています!あとPhippyの笑顔を守りたいエンジニアも絶賛募集中です!
注釈
- Phippy 1ページしかないシンプルなPHPのアプリケーション。見た目はキリン https://www.cncf.io/phippy/
- Cloud Pub/Sub Googleが提供しているフルマネージドのメッセージキューイングのサービス https://cloud.google.com/pubsub/?hl=ja
- トピック パブリッシャーによるメッセージの送信先となる、名前付きのリソース。メッセージの送り先住所のようなもの
その他の記事
Other Articles
関連職種
Recruit