フルマネージド、オートスケーリング、サーバーレスなIoT基盤をクラウド上で構築する方法に興味はありませんか?
全3回でお届けする本シリーズ「IoT on GCP」では、デバイス登録からデータのストリーミング・長期保存、さらには分析・可視化まで、IoTワークフロー全体を取り上げます。

本番規模IoTのベストプラクティス
第1回を読み終える頃には、数百万台規模のIoTデバイスからGoogle Cloud環境へテレメトリデータを安全にストリーミングするための登録方法を理解できるようになります。
本記事は全3回シリーズの第1回です。
- 第2回:高スループットなデータストリームの適切な保存と可視化
- 第3回:IoTデータを活用した実用的な機械学習モデルの構築
シリーズを通じて、クラウドプロバイダーにはGCPを、IoTデバイスのサンプルには温度センサーを取り付けたRaspberry Piを使用します。
概要
本記事は以下の構成でお届けします。
- Raspberry Piのソフトウェアおよびハードウェアのセットアップ
- デバイス登録とクレデンシャル発行のハンズオン
- デバイス接続のテストと温度データのストリーミング
- Google Cloud IoT機能の留意点
- ストリーミングデータの保存(第2回で解説)
- ストリーミングデータの可視化(第2回で解説)
- IoTデータを活用した効果的な機械学習モデルの構築(第3回で解説)
本記事を読み進めるには、BashとPythonの基本知識、そしてGoogle Cloud Consoleの基本操作経験があれば十分です。
Raspberry Piのソフトウェアとハードウェアをセットアップする
まずはRaspberry Piを数台用意して動作させます。本記事ではPi 3を使用します。microSDカードへのOSインストールを自動化するために、Raspbian OS Imagerの利用をおすすめします。
Pythonパッケージをインストールする
デスクトップが起動し、デバイスのアップデートが完了したら、以下のコマンドを実行してGoogle Cloud IoT専用のSDKをインストールします。
pip3 install -U pyjwt paho-mqtt
先に進む前に、なぜGoogle Cloud向けの汎用Python SDKであるgoogle-api-python-clientではなくpaho-mqttをインストールするのかを押さえておきましょう。広く使われているPython SDKやgcloud GCP CLIはHTTPベースで動作します。HTTPはほとんどの操作を素早く実行するのに適していますが、接続が断続的になりやすく、データが主に接続元デバイスから外部へ流れる長時間接続でメッセージを送り続ける用途には向きません。
MQTTはpaho-mqttなどのパッケージを通じてIoTで利用されるプロトコルで、接続が不安定な状況でもデバイスが頻繁にメッセージをパブリッシュし、必要に応じてメッセージを受信できるよう設計されています。
デジタル温度センサーを接続する
必要なPythonパッケージのインストールが完了したら、Raspberry Piにデジタル温度センサーを接続します。本記事の手順に沿って進めるなら、DS18B20センサーがおすすめです。
Raspberry Piにセンサーを接続するには、以下のものが必要です。
- ミニブレッドボード
- ブレッドボード用ジャンパーワイヤー
- 抵抗器セット(4.7KΩの抵抗器が必要です)
これらの到着を待つ必要がある場合でも、シミュレーション温度をストリーミングするスクリプトを後ほど用意しているので、先に読み進めて構いません。
すでにお手元にある方は、このチュートリアルの冒頭5分間で、Raspberry Piへのセンサー接続方法と温度値が正しく取得できているかの確認手順が解説されています。
上記チュートリアルの手順に加えて、再起動のたびにmodprobeを実行する代わりに、起動時にonewireモジュールが読み込まれるよう/etc/modulesに以下を追記しておくことをおすすめします。
w1-gpio
w1-therm
IoTデバイスを登録する
ここでは、安全に登録されたデバイスを含むIoT Registryのセットアップ方法を、動作する完全な例として紹介します。これらのデバイスからGoogle Cloud IoTプラットフォームへ温度データをストリーミングしていきます。
デバイス用のレジストリを作成する
Google Cloud Consoleで以下を実行します。
- 新しいプロジェクト(例:「IoTTempStreaming」)を作成
- IoT Coreサービスに移動してIoT APIを有効化
- 「レジストリの作成」をクリックし、IoTデバイスを追加するためのレジストリを作成
GCPへストリーミングするIoTデバイスは、IoT Registryに保存された認証済みデバイスとして検証されて初めてIoT Coreにメッセージを送信できます。そのため、レジストリの作成は欠かせない最初のステップです。

メッセージの受信を待つ、新規作成されたIoT Core環境
Pub/Subトピックを作成する
IoT Coreに送信されたメッセージは、デバイス固有のdeviceIdなどの重要なメタデータとともに、内部的にPub/Subの「トピック」へ転送されます。Pub/Subは、Google Cloudが提供するフルマネージド・オートスケーリング・サーバーレスのメッセージキューシステムです。
そこで、IoT Registryの作成画面でPub/Subトピックも併せて作成し、テレメトリデータが最終的にPub/Subに到達して下流処理にまわせるようにします。
IoTレジストリの作成画面からPub/Subトピックを作成する手順は次のとおりです。
- レジストリIDを「RaspberryPiDevices」とし、リージョンはus-central1を指定
- IoTテレメトリメッセージがデフォルトで届く「sensordata」という名前のPub/Subトピックを作成
- 「追加トピック」で「temperature」という名前のPub/Subトピックを新規作成し、同じく「temperature」という名前のIoTサブフォルダにパブリッシュされたメッセージがここに届くよう設定
この設定により、特定のIoTサブフォルダにパブリッシュされた温度メッセージのみが「temperature」Pub/Subトピックに届き、それ以外の(想定外の)テレメトリイベントはデフォルトの「sensordata」トピックに届くことが保証されます。
また、詳細オプションを展開してHTTPのチェックを外し、MQTTプロトコルのみを許可することもおすすめします。

温度センサーデータのストリーミング向けIoT Coreレジストリ設定
作成後、レジストリは次のような状態になります。

正常にセットアップされたIoT Coreレジストリ
登録済みデバイスを作成する
デバイス接続をテストする
ここからは、以下の「publish_temps.py」というスクリプトを実行してデバイス接続をテストしましょう。107行目と108行目のどちらをコメントアウトするかによって、デバイスから取得した実温度値とシミュレーション温度値のいずれかをストリーミングできます。
(このスクリプトは、Google Cloudの2つのサンプルスクリプト(#1と#2)を改変したものです)
$ pwd
/home/pi/GCP/
$ ./publish_temps.py
このスクリプトには多くの処理が詰まっています。安全な接続とデータストリーミングの仕組みを深く理解するために、コードに一度目を通すことを強くおすすめします。
スクリプトを実行すると、次のような出力が表示されるはずです。

MQTT経由でGCP IoT Coreにストリーミングされる実際の温度値
このスクリプトをcrontabジョブで再起動時に実行(起動時にonewireモジュールが読み込まれるよう30秒のスリープを先頭に入れる)するように設定しておけば、想定内・想定外を問わず再起動が発生してもIoTデバイスはストリーミングを再開します。
$ crontab -e
@reboot sleep 30 && /home/pi/GCP/publish_temps.py -c /home/pi/GCP/gcp_iot_config.txt >> /home/pi/GCP/publish_temps.log 2>&1
ご家庭内に設置するすべてのRaspberry Piデバイスに対して、オンボーディングとストリーミングのプロセスを繰り返してください。これで大規模なIoTデータを扱う準備に大きく近づきました!
データがストリーミングされていることを確認する
Pub/Subに到達するテレメトリデータを確認することで、メッセージがGoogle Cloudに届いていることを手早く検証しましょう。
- 「temperature」トピックに対するPub/Subサブスクリプションを作成
- そのサブスクリプションに移動
- メッセージを表示をクリックし、Pullのラジオボタンを選択
メッセージが届くと、本文に含まれる温度とタイムスタンプ情報に加えて、どのデバイスから値が送信されたかを一意に識別する属性メタデータも確認できます。属性メタデータは、分析やエンドユーザー向けダッシュボードに役立つだけでなく、不正利用やハッキングされたデバイスを特定して遮断する用途にも有用です。

受信した温度テレメトリメッセージを表示するためのPub/Subサブスクリプションの作成
「temperature」トピックへのサブスクリプションは次のように表示されます。

「temperature」Pub/SubトピックへのPub/Subサブスクリプションでメッセージを表示
「PULL」をクリックすると、メッセージとその属性が表示され始めます。

Pub/Subトピックに届きPub/Subサブスクリプションに到達する温度データ:メッセージ本文

Pub/Subトピックに届きPub/Subサブスクリプションに到達する温度データ:一意に識別する属性
ここまで到達できた方、本当におめでとうございます!IoTデバイスの実データがPub/Subに届く様子を目にするのは胸が躍りますが、まだ入り口に立ったに過ぎません。
このデータを真に活用するには、必要に応じてデータを変換し、データウェアハウスへ移動・バッチロードして分析する必要があります。これらの処理は、初期テストからペタバイト規模の本番運用、さらにその先まで、開発のあらゆる段階で信頼性高く、スケーラブルに、コスト効率よく機能するGCPサービス群のエコシステムによって、ほぼ、あるいはまったくインフラ運用の手間をかけずに行わなければなりません。その実現方法を知りたい方は、第2回・第3回もぜひお楽しみに!
次回:保存と可視化
第2回もぜひご期待ください。大規模なストリーミングIoTデータを比較的容易に実用へつなげられる、適切なETL・保存・可視化サービスについて解説します。
Google Cloud IoT機能の留意点
フルマネージドGCPサービスにおけるdeviceIdの扱いを改善するには
お気づきかもしれませんが、上記のPythonスクリプトはメッセージ本文にdevice_idのキー・値ペアをストリーミングしています。これは、IoT Coreがストリーミング元デバイス固有のキー・値ペアとの紐付けによってPub/Subメッセージに付与するdeviceId属性と実質的に重複しています。
では、なぜハッキングされたデバイス上で簡単に偽装でき、長期保存先にメッセージが移されたときにデータウェアハウスを汚染しかねないdevice_idを、わざわざスクリプトから送信させるのでしょうか?
少し話が先走りますが、第2回で見るように、Pub/Subメッセージを変換しつつBigQueryへ移送できる、フルマネージド・オートスケーリング・ほぼサーバーレスな便利なワークフローがあります。これはDataflow(Apache BeamのGoogle Cloudによるフルマネージド版)を使うものです。
残念ながら、Dataflowで利用できるGCP製のデフォルト「Pub/Sub-to-BigQuery」テンプレートには、メッセージ属性をBigQueryに移す手段が用意されておらず、移動できるのはメッセージ本文の内容のみです。複数のGCPエンジニアに確認しましたが、デフォルトテンプレート向けにカスタムのDataflow JavaScript UDFを書いて、BigQueryなどのDataflowシンクにメッセージ属性を追加することはできないとのことでした。代わりにJavaのDataflowジョブをゼロから書く、あるいは既存のGCP製テンプレートを改変するという手もありますが、いずれも時間のかかる作業で、テンプレートの継続的な保守と更新も必要となるため、ほとんどのGCPユーザーにとっては避けたい選択肢でしょう。
そのためデフォルト構成では、Pub/Subに到達して目的のデータシンクへ送られるIoTメッセージとそのメッセージのdeviceIdを、シンプルかつ安全に紐付ける手段がありません。
この見落としについてはGCPに指摘済みで、それを受けてIoTユースケースの実現に欠かせない——というよりも必須の——これらの値をデフォルトテンプレートが渡せるようにするための公開機能リクエストが起票されました。このFRが対応され次第、本記事も更新する予定ですが、それまではデモ用途に限り、デフォルトで備わっているべきDataflowテンプレートを書き直すよりも、メッセージ本文を通じてdevice_idを送信する形でテストするほうがはるかに簡単です。
デバイス固有のクレデンシャル発行を理想的に行うには?
1台のIoTデバイスを登録するプロセスは、一般的に次のように説明されます。
- GCPでIoT権限に紐付けた公開鍵・秘密鍵のペアを作成
- これらのファイルを工場でデバイスにプロビジョニング・配置
- 工場でそのクレデンシャルをIoT Registryに登録
- その鍵ペアを使ってIoT API呼び出しを行い、データをクラウドへストリーミング
しかしこの手順だけでは理想的とは言えません。実際のIoTユースケースでは数百万台のデバイスがクラウド環境にストリーミングするからです。これほど大規模なフリートでは、各デバイスに固有のクレデンシャルセットを付与する必要があります。デバイスやそのGoogle Cloudクレデンシャルが侵害されて不正に利用された場合に、フリート内の他デバイスに影響を与えずに該当のクレデンシャルを無効化できるようにするためです。
GCPはこの機能を備えており、上記スクリプトで見たように、デバイス固有のトピックへのパブリッシュのみを許可する設定もサポートしています。とはいえ、現状のクレデンシャル発行手法では、数百万台ものデバイスについて鍵の作成・配布・登録を統制するのは大きな課題です。
デバイス固有のクレデンシャル作成を、可能な限りシンプルに行うにはどうすればよいでしょうか?数百万件もの証明書を事前に作成し、製造時にそれぞれをデバイスへ正確に配置する手間をかけずに済ませられるでしょうか?重複なく確実にこれらのファイルを配置することを、メーカー任せにしたいでしょうか?
あるいは、デバイスが製造ラインを流れてソフトウェアとクレデンシャルでブートストラップされる際に、メーカーが新しいクレデンシャルをオンデマンドで作成するためにIoT RegistryへAPI呼び出しを行わなくても、デバイス登録と認証情報発行を行えるでしょうか?IoT登録を支えるAPI Gatewayへの接続が切れた場合、デバイスの製造ラインはどうなってしまうのでしょうか?
こうした方法は複雑でミスが起きやすく、メーカーに不要な負担を強いるため、できれば避けたいところです。
セキュアで合理的にスケールするデバイス登録システムとして、GCPに対応してほしい指針は次のとおりです。
- すべてのIoTデバイスに配置される単一のIoT証明書を作成する。「ブートストラップ」証明書と呼ばれるこの証明書には権限ポリシーが紐付けられており、デバイスは(a)リクエストが承認された場合にデバイス固有のクレデンシャルを作成・取得するためのリクエストを発行すること、および(b)自身をIoT Registryに追加することのみが許可される。
- GCP IoT Coreプラットフォームは、クレデンシャル作成リクエストを受信して承認すると、新しい鍵ペアを作成する。紐付くIoT権限は——現状のGoogle Cloudと同様——デバイスがデバイス固有のトピックにのみメッセージをパブリッシュできるよう制限すべきである。
- デバイス固有のクレデンシャル作成の許可は、検証ステップによって制御されるべきである。これは自分で作成するCloud Functionで、リクエストに一意の識別子を含めることを必須とし、ホワイトリスト(例:製造済みのシリアル番号や使用済みのMACアドレスのリスト)やブラックリスト(例:侵害された、不正利用された、あるいはすでに登録済みのデバイスのシリアル番号リスト)と照合できるようにする。
- 検証ステップでデバイス固有の証明書リクエストが承認された場合、デバイスはIoT Registryに登録され、新しいクレデンシャルファイルがデータストリーミング用にデバイスへ配信される。
このワークフローであれば、IoTデバイスメーカーは各デバイスにブートストラップ証明書を組み込むだけで済みます。データストリーミングを可能にするデバイス固有の鍵ペアは、必要であれば製造工場内で即座に作成・取得することもできますし、エンドユーザーの手に渡った後で作成することもできます。
クレデンシャルをいつ取得するかにかかわらず、メーカーは利用者側が提供するソフトウェアをデバイスにブートストラップするだけで済み、そのソフトウェアは以下の条件下で、ブートストラップ証明書を使ったデバイス固有の鍵ペア作成プロセスを実行します。
- デバイスが起動したとき
- インターネット接続が利用可能なとき
- デバイス固有の鍵ペアが見つからないとき
残念ながら、こうした機能は(現時点では)用意されていません。とはいえ、大規模なデバイス登録の話を別にすれば、Google Cloud IoTは、下流のフルマネージドなメッセージ処理サービス(第2回で解説)と組み合わせることで、IoT領域における強力でセキュア、かつ容易にスケールできるクラウドベースのソリューションとなります。