はじめに
会社の業務でAWS IoT Greengrassについて勉強したので、Ubuntu搭載デバイスとAWS IoTを利用したアプリケーションを紹介したいと思います。
今回はGreengrassのLambdaを作成してデバイスへデプロイする方法を紹介します。
過去の記事
UbuntuにAWS IoT Greengrassをインストールする
Azure IoT Edgeを使った記事もあるので興味のある方は是非ご覧ください。
環境
動作確認済デバイス(OS)
-
e-RT3 Plus F3RP70-2L1(Ubuntu 18.04 32bit)
横河電機のエッジコントローラです。AWS IoT Greengrassの認定デバイス2に登録されています(e-RT3のページはこちら)。 -
Raspberry Pi 4 Model B (Ubuntu Server 20.04 32bit)
これらのデバイスでは armhf アーキテクチャのパッケージが動作します。
また、Windows 10 搭載のPCでデバイスを操作しています。
Lambdaとは
Lambdaとは、イベントの発生をトリガーとしてコードを実行するサービスです3。
AWS IoT GreengrassではGreengrass CoreをインストールしたエッジデバイスにLambdaをデプロイして実行することができます4。
これにより、クラウドからのメッセージやローカルイベントをトリガーとして、エッジデバイスで処理を行うことができます。
Greengrass Coreで実行するLambdaには以下の2つの種類があります5。
-
On-demand Lambda
呼び出されたときにコンテナを起動する方式です。同時に複数呼び出されると自動的にコンテナを起動してスケールするため、同時に処理を行うことができます。 -
Long-lived Lambda
Greengrass Coreの起動時に一つだけコンテナを起動する方式です。同時に複数呼び出されるとタスクがキューに入れられ一つずつ順番に処理されます。
今回は2つの種類のLambdaをデプロイして動作の違いについて確認してみたいと思います。
作業の流れ
AWSの公式ドキュメント67を参考に、以下の流れで作業を進めます。
-
Lambda関数コードの作成
PC上でLambda関数コードを作成して、SDKとともにパッケージ化します。 -
Lambdaの作成とコードのアップロード
Lambdaを作成してLambda関数コードをクラウドにアップロードし、設定を行います。 -
Lambdaのデプロイ
クラウドからエッジデバイスにLambdaをデプロイします。
1. Lambda関数コードの作成
PCでPythonのLambda関数コードを作成してSDKとともにパッケージ化します。
-
PCでLambda関数コードを作成します。
今回はAWS IoT Greengrass Core SDK for Python8のexamplesを参考にして作成した以下のPythonコードを使用します(SDKのライセンスはこちら)。「HelloWorld.py」という名前で保存してください。
このLambdaは呼び出されるとfunction_handler関数を実行して、MQTTメッセージ(Hello world from e-RT3 / Raspberry Pi!+現在時刻)を「hello/world/response」トピックに送信し、5秒間スリープします。HelloWorld.pyimport time import datetime import greengrasssdk # Creating a greengrass core sdk client client = greengrasssdk.client("iot-data") def function_handler(event, context): client.publish( topic = "hello/world/response", queueFullPolicy="AllOrException", payload="Hello world from e-RT3 / Raspberry Pi! " + datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S') ) time.sleep(5) return
-
SDKをダウンロードします。
ダウンロードページのAWS IoT Greengrass Core SDK for Pythonをクリックします。
GitHubのページに飛びます。「Code」ボタンを押してメニューを開き、「Download ZIP」を押してファイルをダウンロードします。
-
Lambda関数コードをパッケージ化します。
ZIPを解凍してaws-greengrass-core-sdk-python-master\greengrasssdk
フォルダと手順1で保存したHelloWorld.py
を同一のフォルダにコピーします。
greengrasssdk
フォルダとHelloWorld.py
を一つのZIPファイルに圧縮します。ここでは「HelloWorld.zip」という名前で圧縮します。
2. Lambdaの作成とコードのアップロード
クラウド上でLambdaを作成してコードをアップロードし、設定を行います。
-
AWSにログインして左上のサービスメニューをクリックします。検索窓に「lambda」と入力して「Lambda」をクリックします。
-
「一から作成」を選択して関数に任意の名前をつけ、ランタイムに「Python3.8」を指定して、「関数の作成」をクリックします。
-
Lambda関数コードをアップロードします。
関数コードの「アクション」メニューを開き、「.zipファイルをアップロード」をクリックします。
アップロードボタンを押してLambda関数コードの作成の章で作成した「HelloWorld.zip」をアップロードし、「保存」をクリックします。
-
ランタイムの設定を行います。
ランタイム設定の「編集」をクリックします。
ランタイムに「Python 3.8」、ハンドラに「HelloWorld.function_handler」と入力して「保存」をクリックします。
-
Lambda関数を発行します。
「アクション」メニューの「新しいバージョンを発行」をクリックします。
バージョンの説明を入力し、「発行」をクリックします。
-
Lambda関数バージョンのエイリアスを作成します。
「アクション」の「エイリアスの作成」をクリックします。
任意のエイリアス名を入力して「保存」をクリックします。
3. Lambdaのデプロイ
作成したLambdaをエッジデバイスにデプロイします。
-
追加するLambdaを選択します。
「既存のLambdaの使用」をクリックします。
作成したLambdaを選択し、「次へ」をクリックします。
作成したエイリアスを選択し、「完了」をクリックします。
-
MQTTサブスクリプションの設定を行います。
-
クラウドからLambdaへ「hello/world/trigger」トピックのメッセージが送信されるようにします。
グループのページの左側のメニューから「サブスクリプション」を選択し、「サブスクリプションの追加」をクリックします。
ソースに「IoT Cloud」、ターゲットに「HelloWorld」を選択し、「次へ」をクリックします。
トピックのフィルターに「hello/world/trigger」と入力し、「次へ」をクリックします。
「完了」をクリックします。
-
Lambdaからクラウドへ「hello/world/response」トピックのメッセージが送信されるようにします。
同様に「サブスクリプションの追加」をクリックし、ソースに「HelloWorld」、ターゲットに「IoT Cloud」を選択して「次へ」をクリックします。
トピックのフィルターに「hello/world/response」と入力し、「次へ」をクリックします。
「完了」をクリックします。
-
-
Lambdaの設定を行います。
「...」をクリックし、「設定の編集」をクリックします。
タイムアウトを「25」に設定し、Lambdaのライフサイクルには「オンデマンド関数」(On-demand Lambda)か「存続期間が長く無制限に稼働する関数にする」(Long-lived Lambda)のどちらかを選択して「更新」をクリックします。
ライフサイクルの種類によるLambdaの動作の違いについては、この後の動作確認の章で説明します。
-
Lambdaをエッジデバイスにデプロイします。
まず、エッジデバイスのGreengrassデーモンを起動しておきます。
sudo systemctl start greengrass
「アクション」メニューから「デプロイ」をクリックします。
以下の画面が表示された場合は「自動検出」をクリックします。
デプロイが開始されます。左側のデプロイメニューから進捗状況を確認できます。デプロイが正常に終わると下図のようになります。
4. 動作確認
クラウドからメッセージを送信してLambdaを呼び出し、応答をコンソール上で確認します。
-
Lambdaからのメッセージを見るための設定を行います。
ナビゲーションペインの「テスト」をクリックします。
エッジデバイスのLambdaから送信される「hello/world/response」トピックのメッセージを見るために、トピックのサブスクリプションに「hello/world/response」、サービスの品質に「0」、MQTTペイロード表示に「ペイロードを文字列として表示」を指定し、「トピックへのサブスクライブ」をクリックします。
-
エッジデバイスのLambdaにメッセージを送信します。
エッジデバイスのLambdaを呼び出すために、トピックに「hello/world/trigger」と入力し「トピックに発行」を連続で数回クリックします。
-
エッジデバイスのLambdaから送信されたメッセージを確認します。
-
On-demand Lambdaの場合
On-demand Lambdaはメッセージを受信するとコンテナを自動的に起動して処理を実行するため、複数のメッセージを受信するとその分だけコンテナが作られて同時に処理が行われます。
そのため、ボタンを押すとすぐにLambdaからメッセージが届きます。
-
Long-lived Lambdaの場合
Long-lived Lambdaは起動時に生成した一つのコンテナで処理を行うため、複数のメッセージを受信するとタスクはキューに入れられて一つずつ処理されます。
今回のLambdaはメッセージを送信した後5秒間スリープするため、ボタンを連続して押すと5秒おきにLambdaからメッセージが届きます。
-
※Lambdaの設定を変更した場合は再度デプロイを行ってください。
まとめ
Lambda関数コードの作成からLambdaの作成、デバイスへのデプロイ、動作確認までを行いました。
また、Lambdaの種類による動作の違いについても確認しました。