はじめに
今回はAWS IoTで何ができるのかを学習するにあたり、以下のことを実施しました。自身の記録用として残していますが、どなたかの学習のヒントになれば幸いです。
- AWS IoT Greengrassって何?を理解するために、いくつかのサイトでイメージをつかむ。
- 実際に手を動かして、つかんだイメージを少し具体的に理解する。
参考サイト
「はじめに」の2点を実施する際に、以下のサイトをメインに参考にしました。どちらも非常にわかりやすかったです。
-
EurekaBox コラム AWS Greengrass
→3つコラムをすべて読むと1時間くらいかかりますが、とても読みやすく整理されています。 -
AWS IoT Greengrass V2 入門ハンズオン
→基本的にはこちらのハンズオンにしたがって実施。
やってみる
コラムを読んだ後にこちらのハンズオンを実施したので、Greenglassの使い方がより具体的にイメージできました。今回のハンズオンで構成する内容は以下の図の内容になります。「Greengrass client software」がすべて単一のCloud9上に構築されるので、エッジデバイスとIoTデバイスを意識しながら進めていくのがポイントかなと思いました。(EurekaBox コラムを読んでイメージが持ててたのでよかった!)
なお、今回の記事では細かいステップ(Cloud9で設定した部分など)は割愛して、より覚えておきたい部分をメインに記載してます。ですのでハンズオンを実際に実施する場合はぜひ公式URLを参照してください。
環境の用意
まずはハンズオン用の環境を用意します。上述の通り今回はCloud9を利用していきますが、Cloud9セットアップ用のCloudFormationテンプレートは公式ハンズオンの中で用意されているので、こちらを利用します。
テンプレートの実行結果として以下のようなリソースが作成されました!こちらのCloud9を利用していきます。
次にGreengrassのServiceRoleを作成していきます。Cloud9ターミナルからロールを作成します。
aws iam create-role --role-name Greengrass_ServiceRole --assume-role-policy-document '{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": "greengrass.amazonaws.com"
},
"Action": "sts:AssumeRole",
"Condition": {
"ArnLike": {
"aws:SourceArn": "arn:aws:greengrass:[region]:[account-id]:*"
},
"StringEquals": {
"aws:SourceAccount": "[account-id]"
}
}
}
]
}'
作成したロールにAWSGreengrassResourceAccessRolePolicy
ポリシーをアタッチします。
aws iam attach-role-policy --role-name Greengrass_ServiceRole --policy-arn arn:aws:iam::aws:policy/service-role/AWSGreengrassResourceAccessRolePolicy
さらに以下のコマンドでロールとアカウントを結び付けます、ここではaws greengrassv2
コマンドを用いています。
aws greengrassv2 associate-service-role-to-account --role-arn [role-arn] --region [region]
AWS IoTコンソールからロールとアカウントが紐づけられたことが確認できます。ひとまず環境セットアップはここまでです。
Greengrassのセットアップ
次にGreengrass自体のセットアップを実施していきます。以下の図のように、まずはAWSコンソールでAWS IoT Coreの初期設定を行い、次にCloud9からGreengrassV2をインストールします。
まずはコンソールからCore Devicesの設定を行っていきます。デフォルト値で以下のように進めていきます。
Step3の画面でCloud9(コアデバイス)で実施するGreengrassのインストーラー実行コマンドが表示されるので、コピーしてCloud9で実行します。
AWSコンソール画面に戻って、コアデバイスを確認すると追加したデバイスが表示されています。
つまり、GreengrassのコアデバイスとAWS IoT Core(コンソール)の接続が完了したことになります。ちなみに上記インストーラーの実行により、Things、ポリシー、デバイス証明書などもプロビジョニングされています。
次に再度IAMのセットアップを実施します。ここでは以降のハンズオンで必要な以下のアクションを許可するポリシーを作成します。
- カスタムコンポーネントのパブリッシュ (S3 を使用)
- MQTT ブリッジ
以下が作成するポリシー。ポリシー名はworkshop_s3_iot_gg_policy
。
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "S3BucketActions",
"Effect": "Allow",
"Action": [
"s3:CreateBucket",
"s3:ListAllMyBuckets",
"s3:GetBucketLocation",
"s3:PutObject",
"s3:GetObject"
],
"Resource": ["arn:aws:s3:::*"]
},
{
"Effect": "Allow",
"Action": ["iot:*"],
"Resource": "*"
},
{
"Sid": "GreengrassActions",
"Effect": "Allow",
"Action": ["greengrass:*"],
"Resource": "*"
}
]
}
上記ポリシーを既存のGreengrassV2TokenExchangeRole
にアタッチします。
コンポーネントの作成
次に、コンポーネントと呼ばれるモジュール化されたアプリケーションを開発し、デプロイしていきます。このアプリケーション部分はGreengrass Core(今回はCloud9)で実行されるロジックである理解です。今回はCloud9でコンポーネントを作成していますが、この部分はおそらくLambdaとかでも書けるはずです。以下の図のLambda Functionの部分を今回はCloud9で直接開発するイメージでしょうか。
開発するコンポーネント(アプリロジック)は以下です。詳細な開発手順(フォルダ作成とか)は公式ハンズオンを参照してください。
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
# SPDX-License-Identifier: MIT-0
import sys
import datetime
import time
while True:
message = f"Hello, {sys.argv[1]}! Current time: {str(datetime.datetime.now())}."
# Print the message to stdout.
print(message)
# Append the message to the log file.
with open('/tmp/Greengrass_HelloWorld.log', 'a') as f:
print(message, file=f)
time.sleep(1)
なお、同じCloud9上で開発しちゃっているので少し分かりづらいですが、この時点ではまだGreengrass Core(デバイス)にはこのコンポーネント(アプリ)はデプロイされていません。
デプロイするにはレシピと呼ばれるYAML
もしくはjson
で書かれたファイルが必要です。ハンズオンではjsonで記載しています。
{
"RecipeFormatVersion": "2020-01-25",
"ComponentName": "com.example.HelloWorld",
"ComponentVersion": "1.0.0",
"ComponentDescription": "My first AWS IoT Greengrass component.",
"ComponentPublisher": "Amazon",
"ComponentConfiguration": {
"DefaultConfiguration": {
"Message": "world"
}
},
"Manifests": [
{
"Platform": {
"os": "linux"
},
"Lifecycle": {
"Run": "python3 -u {artifacts:path}/hello_world.py '{configuration:/Message}'\n"
}
}
]
}
いよいよデプロイです。以下のコマンドでデプロイします。
sudo /greengrass/v2/bin/greengrass-cli deployment create \
--recipeDir ~/environment/GreengrassCore/recipes \
--artifactDir ~/environment/GreengrassCore/artifacts \
--merge "com.example.HelloWorld=1.0.0"
デプロイ後に以下のようなコマンドでログが見れたらデプロイに成功しています。
さて、ここまででGreengrass Coreのデバイスにデプロイは完了していますが、実際には他に複数のデバイスが存在しており、同じロジックを適用したいケースもあるはずです。そのような場合はこの作成したコンポーネントをS3にアップロードして、AWSコンソールからデプロイします。この部分の手順については公式のハンズオンの他のデバイスにデプロイするためにコンポーネントを AWS にパブリッシュするを参照してください。
手順を正常に完了すると、以下のようにコンソールからコンポーネント一覧で確認することができるようになり、
指定するデプロイ先にコンポーネントをデプロイできます。
メッセージのPub/Subの実装
次に各コンポーネント間でメッセージ交換を行うためのPub/Subの実装をしていきます。以下の図がイメージつきやすいでしょうか。
(※引用 Eureka Box(ユーリカボックス)【体験版】AWS Greengrass =連載第2回=
https://member.eureka-box.com/products/4/categories/4011892/posts/13450002)
メッセージ交換は「Pub/Sub型のトピック通信モデル」で行われます。ご存知の方は多いかと思いますが、Pub/Sub型の通信は基本的に、データを送る人(Publisher)がトピックと呼ばれるメッセージの内容を送ると、そのトピックに興味を持っている人、トピックを購読したい人(Subscriber)にデータが配信されるという仕組みです。
ハンズオンでは以下を実装していきます。
- センサーデータを読み込んでトピックに発行し続けるコンポーネント(Publisher)
- そのトピックのログを購読してメッセージを受信するコンポーネント(Subscriber)
なお、このハンズオンでは上記のどちらもGreengrass Core(Cloud9上)にデプロイされます。実際のセンサーを積んだデバイスも、現状はCloud9が肩代わりしているようなイメージです。
パブリッシャーコンポーネントの実装
こちらの内容も詳細は公式ハンズオンを参照してください。大まかな手順は以下です。
- センサーの動きをするダミーのスクリプト(
dummy_sensor.py
)を作成する。 - メッセージをPublishするPublisherコンポーネント(
example_publisher.py
)を記述する。 - デプロイするためのレシピファイル(
com.example.Publisher-1.0.0.json
)を作成する。 - デプロイコマンドを実行してコンポーネントデプロイする。
サブスクライバーコンポーネントの実装
こちらの内容も詳細は公式ハンズオンを参照してください。大まかな手順は以下です。
- メッセージをSubscribeするSubscriberコンポーネント(
example_subscriber.py
)を記述する。 - デプロイするためのレシピファイル(
com.example.Subscriber-1.0.0.json
)を作成する。 - デプロイコマンドを実行してコンポーネントデプロイする。
デプロイ後に以下のコマンドを実行して受信しているメッセージが表示され続ければ成功です。
Greengrass Coreデバイスを各IoTデバイスのゲートウェイとして機能させる実装
ここまでの実装では、GreengrassCodeデバイス(Cloud9)のみで完結するような構成ですが、実際は複数のデバイスからメッセージを受け取るな利用シーンは多いはずです。以降の手順ではMQTTブリッジを導入することにより、Greengrass Coreデバイスをゲートウェイとして利用するような構成を構築していきます。MQTTとはGreengrassで用いられる通信プロトコルです。
まずはMQTTを利用するために、MQTTブローカーをGreengrassCoreデバイスにデプロイします。コンソール画面から以下のコンポーネント(これらはAWSによりパブリックコンポーネント
として用意されています)を選択します。
※☑がついていないコンポーネントは、以降のハンズオンでデプロイしたものです。この時点では無視してください。なお、デプロイ時の詳細手順は公式ハンズオンを参照してください。
次にGreengrassCoreにメッセージを送るデバイスを作成します。ただしこのハンズオンではやはりCloud9で模擬的にデバイスを作成しているので、この部分が若干わかりづらく感じるかもです。具体的にはMosquitto
クライアントというものを利用して、デバイスのシュミレーションをしています。作業環境はCloud9です。
以下のように模擬クライアントを作成していきます。
cd ~/environment
mkdir -p devices
cd devices
THING_NAME=MyClientDevice1
aws iot create-thing --thing-name $THING_NAME
CERTIFICATE_ARN=$(aws iot create-keys-and-certificate --private-key-out $THING_NAME.key --certificate-pem-out $THING_NAME.crt --query "certificateArn" --out text --set-as-active)
aws iot attach-thing-principal --thing-name $THING_NAME --principal $CERTIFICATE_ARN
次に模擬クライアント(Cloud9)からGreengrassCore(Cloud9)へMQTTを使った通信のテストを実施します。
mosquitto
クライアントをインストールし、
sudo apt install mosquitto-clients
ローカルブローカーサーバー証明書の CA 証明書を取得します。これは、クライアントがブローカーのエンドポイントを検証するために使用されます。
cd ~/environment/devices
sudo cp /greengrass/v2/work/aws.greengrass.clientdevices.Auth/ca.pem .
sudo chmod 444 ca.pem
以下のコマンドでサブスクライブを開始し、
cd ~/environment/devices
mosquitto_sub -h localhost -p 8883 -q 0 -t clients/+/hello/world --cafile ca.pem --cert MyOtherClientDevice1.crt --key MyOtherClientDevice1.key -i MyOtherClientDevice1
さらに以下のコマンドでメッセージを発行します。
cd ~/environment/devices
mosquitto_pub -h localhost -p 8883 -q 0 -t clients/test/hello/world --cafile ca.pem --cert MyClientDevice1.crt --key MyClientDevice1.key -m "{\"message\": \""$2" @ "$(date +"%m-%d-%Y-%H-%M-%s")"\"}" -i MyClientDevice1
サブスクライバー側のターミナルで無事にメッセージ受信を確認できました。
この時点でGreengrassCore(ローカルブローカー)から AWS IoT Core にメッセージをリレーするよう Bridge コンポーネントを設定をしたため、AWSマネジメントコンソール にアクセスしclients/#
をサブスクライブすることでテストすることができます。同じメッセージが確認できます。
Greengrass Coreに機械学習コンポーネントをデプロイ
さらにハンズオンではAWSパブリックに用意されている機械学習のコンポーネントもデプロイし、エッジデバイスで機械学習させ、その結果をAWSコンソールで確認するような手順も含まれています。この場合はAWSにより準備されているコンポーネントをデプロイしているだけなので簡単にできるので、ぜひ公式ハンズオンを参照してやってみてください。画像分類の機械学習コンポーネントをデプロイしています。
つまづいたポイント
上記までのハンズオン内容の記載には含んでいませんが、オプションで6.2 独自の MQTT ブローカー [Mosquitto] (Optional)を実施した際に、メッセージの発行がうまくできませんでした。継続調査をしたいと思います。同じところでハマった方などいましたら、記事などUP頂けると助かります!
おわりに
今回はハンズオンに習って一通りGreengrassを使っていました。概念を理解した後に実際に手を動かしてみると、やはりより具体的な利用イメージがわきました。実際の利用ケースではコンポーネント実装をLambda側で開発したり、IoTデバイスを複数用意したりすると思います。そのような本番ワークロード経験を積んでいきたいです。
以上。