#はじめに
AIカメラ等のプロジェクトでほぼ必須(だと思います)の「Greengrass Coreデバイス上でLambda(boto3)を動かしローカルファイルをS3にアップロードする」手順と注意点をまとめました。エッジコンピューティングの基礎でもある機能で、一見すごく簡単そうですが、筆者自身かなりハマってしまいました。ラズパイの初期設定から最後の画像のアップロードまでハマりどころが9つあるのでそれを実際の手順にそって解説しています。
(ちなみにGreengrassはversion1を使っています)
#今回やることの大まかな流れ
初期設定(OSインストール、ラズパイの初期設定、PCからラズパイへSSH接続、Greengrass Coreのインストール&Greengrass初期設定、Filezilla等FTPソフトウェアでラズパイに接続)
↓
Lambdaの作成
↓
Greengrass Groupの設定
↓
ラズパイの追加設定
↓
動作確認(IoT CoreからGreengrass CoreデバイスにMQTTメッセージを送ってLambdaを起動)
#9のハマりどころ
Greengrass Core LambdaでS3にローカルファイルをアップロードしたい場合に気をつけたい注意点は以下の10個です。
###初期設定時
① ssh接続のときsudo sshとしない
###Lambda作成時
② Lambda作成時に必ずGreengrass SDKとまとめてZIPファイルにしてアップロードする
③ Lambdaハンドラーを「Pythonファイル名.関数名」と指定する
④ Lambdaエイリアスには「$LATEST」を指定しない
⑤ Lambdaの新しいバージョンを発行したら必ずエイリアスのバージョンも変える
###Greengrass Groupの設定
⑥ 「作成したLambdaの登録」、「リソースの追加」、「サブスクリプションの追加」、「IAMロール&ポリシーの追加」の4つを忘れない
⑦ GreengrassのシステムlogとLambdaのlogを有効にする
###ラズパイの追加設定
⑧ リソースパスは実際にラズパイのLinuxOS上に存在しなくてはいけない
⑨ リソースパスで指定したパスに「chmod 775」でアクセス(readとwrite)ができるようにする
これらの注意点は実際に手順を説明していく上で詳しく説明していきます。
※初期設定に関しては色々なところで説明があるので、ポイントの箇条書きにとどめて、内容はかなり省かせていただきます。
#1. 初期設定
##1-1. ディスクイメージのダウンロードとフォーマッティング
Raspbian OS GUI版が2GBとファイルサイズもそれほど大きくなく十分な機能があるのでおすすめです。
RaspbberyPi OSダウンロード
また慣れないうちはCLI版じゃなくGUI版を落としておいて、スクリーンとキーボード&マウスを用意しておくのが無難です。
ラズパイを初期化したいときが大抵くるのでディスクイメージを複数保存しておくと便利です。フォーマッターはBalena Etcherを使っていますが早くて快適です。
##1-2. ラズパイの初期設定
まずデスクトップ右上のアイコンからwifiの設定(SSID、パスワード)をします。LANケーブルの方はケーブルをラズパイに繋ぎます。
ラズパイのターミナルを開いて
raspi-config
この画面になるので、「Interface Options」からSSH接続をONにします。
##1-3. PCからSSH接続
###注意点①ssh接続のときsudo sshとしない
sudo ssh pi@xxx.xxx.xxx.xxx
とやると一応
password?
|
といった感じでパスワードを聞いて来ますが、何を入れてもaccess deniedと表示されます。SSHの設定かな?とsshの設定ファイルに飛んでいじってみたり、沼にハマることがあるので注意です。
ラズパイのIPアドレスはラズパイのターミナル上で
hostname -I
で表示します。
##1-4. Greengrass CoreのインストールとGGG(Greengrass Group), GGC(Greengrass Core)の作成
こちらにAWS公式と同じ手順をまとめています。ここで作成する
Greengrass Group名、Greengrass Core名等を入力します。
#2. Lambdaの作成
##2-1. Lambdaに上げるPythonファイルの作成とSDKのダウンロード
今回使用するコードはこちら。Chromiumでダウンロードしてきたマリオの画像をアップロードする想定です。このコードをコピペしてtest.py
という名前で保存してください。
import boto3
s3= boto3.resource('s3')
#S3にあげたいファイルが存在するローカルのパス(絶対参照のみ)
filePath='/home/pi/Downloads/mario.jpeg'
#ファイルをあげたいS3のバケットの名前
bucketName = 'BUCKET_NAME'
#S3バケットの入れたいフォルダとファイル名(Key)を指定
s3Key = 'Pictures/GameCharacter/mario.jpeg'
def function_handler(event, context):
# 画像ファイルの場合#をとる
#data = open(filePath, mode='rb')
#s3.Bucket(bucketName).put_object(Key = s3Key, Body = data)
# テキストファイルの場合#をとる
#data = open(filePath, mode='r')
#s3.Bucket(bucketName).put_object(Key = s3Key, Body = data.read())
return
Pythonファイルができたら次はSDKをダウンロードしていきます。
AWSのGithubからGreengrass Core SDK Pythonをダウンロードします。ダウンロードしたら先程のPythonファイルとこのSDKをFinderで選択して圧縮し、.zip
ファイルにします(こちらの記事を参照してください)。
##2-2. ZIPファイルをLambdaに上げる
AWSコンソールからLambdaに飛びます。画像のようにお気に入りを登録しておくと便利です。
左側から「関数」を選んで右側のオレンジの「作成」のボタンを押します。
1から作成を選び適当に関数名を入力します。ランタイムには「Python3.7」を選び、「作成」を押します。
次にコードソースの「アップロード」から「zipファイル」を選び先程圧縮したPythonファイルとSDKのZIPファイルをアップロードします。
###注意点② Lambda作成時に必ずGreengrass SDKとまとめてZIPファイルにしてアップロードする
これが意外と忘れがちなので注意です。これを忘れるとlogに
「ローカルのサーバーから認証情報が取れませんでした」
といった内容のlogが吐かれ、一見SDKの上げ忘れだと気づかないので注意が必要です。
※S3にあらかじめGreengrass SDKをZIPファイルであげておくとそこからLambdaにアップロードができるので便利です。
その後、画像のように情報を入力し、「ランタイムの設定」から「ハンドラー」を、
test.function_handler
とします。
###注意点③ Lambdaハンドラーを「Pythonファイル名.関数名」と指定する
ハンドラーとはLambdaの中のどのPythonファイルを開くかを「.」の右側で指定して、Pythonファイルの中のどの関数を扱うかを「.」の右側で指定しています。一文字でも間違うとエラーになるので注意してください。
##2-2.の続き
その後右上の「新しいバージョンを発行する」を押します。Description(メモのようなもの)を必要なら書いて「パブリッシュ」を押します。その後「エイリアスの作成」を押します。
エイリアスの名前は全て大文字にするのをお勧めします(AWS公式でも色々派閥があるみたいですが)。TEST
とかDEV
とかわかりやすい名前をつけます。ここではTEST
とします。「バージョン」は一番新しい(今は作成したばかりなので1しかないはずですが)ものを選びますが、ここで注意が必要です。
###注意点④ Lambdaエイリアスには「$LATEST」を指定しない
Greengrassは設計思想上、$LATEST
を採用していません(2021年3月現在)。$LATEST
はimmutabilityの設計思想にもとるとのことです(AWSの公式ドキュメントに書いてありました)。$LATEST
を選ぶとGreengrass Groupのデプロイでエラーが出ますが、これまたlogをよくみないと原因がわからないので初めから気をつけましょう。
###注意点⑤ Lambdaの新しいバージョンを発行したら必ずエイリアスのバージョンも変える
これも意外と忘れがちです。新しいバージョンパブリッシュ後、画面上部の作成した関数名をクリックし、
今度は画面下部にある「エイリアス」タブから自分の関数名の左にある○を選択し「編集」をクリック。
バージョンを最新にして「保存」を押します。これでエイリアスの紐づけもできました。これをしておくとGreengrass Groupのデプロイの際にLambdaのバージョンを変えてあげる必要がなくなります。
これでLambdaの作成は完了です。
#3. Greengrass Groupの設定
AWSコンソールからAWS IoTに飛び、「グリーングラス」「クラシック(V1)」「グループ」に行き、先程作成したGreengrass Groupをクリックします。
###注意点⑥ 「作成したLambdaの登録」、「リソースの追加」、「サブスクリプションの追加」、「ポリシーの追加」の4つを忘れない
Greengrassの設定は主にGroupの設定からおこないます。今回はLambdaの登録に加えてLambdaにローカルファイルへのアクセスを許可するためのリソースの追加、エッジデバイスとのMQTT通信に許可を与えるサブスクリプションの追加、Greengrass Group自体にIAM権限を与えてやるポリシーの追加を忘れずにやっていきます。
##3-1. Lambdaの追加
Lambdaタブから「Lambdaの追加」→「既存のLambdaを追加」で先程作成したLambdaを選択します。
作成したエイリアスを選択して「確定」をクリックします。
##3-2. リソースの追加
「リソース」から「ローカルリソースの追加」をクリック。
「リソース名」を入力し、「リソースタイプ」はボリュームを選択(カメラ等を追加する場合はデバイスを選択します)。
ソースパス(Lambdaにアクセスを許可するフォルダ)とデスティネーションパス(Lambdaコンテナ上仮想フォルダ)は今回は画像のように
#Lambdaにアクセスを許可したいフォルダ
/home/pi/Downloads
#Lambdaコンテナが使用するためのフォルダ(今回は使いませんが、必須です)
/Lambdadirectory
としました。グループオーナーのファイルアクセス許可は「自動的に追加」を選択(詳しい説明はこちら)。
最後に画像のようにLambdaをアタッチして最後に「アップデート」をクリックしてリソースの追加は完了です。
##3-3. サブスクリプションの追加
今度はサブスクリプションの追加をしていきます。GreengrassのLambdaは通常のLambdaを少し振る舞いが異なります。常時実行LambdaとオンデマンドLambdaの2種類があって(デフォルトではオンデマンドLambdaです)、オンデマンドLambdaはLambdaにMQTT通信でメッセージが届いたらinvokeされます。
「サブスクリプション」から「サブスクリプションの追加」をクリック。ソースには「IoT Cloud」を選びます。ターゲットには先程追加したLambdaを追加します。その後「次へ」をクリック。
トピックフィルターはなんでも良いですが、覚えやすいinvoke/test
にしました。ワイルドカード(#
)を使うこともできますが、そうすると大抵Lambdaが意図せず頻繁にキックされてしまうので注意が必要です。「次へ」から「完了」をクリック。
これでサブスクリプションの追加は完了です。
##3-4. IAMロール&ポリシーの追加
最後にポリシーを追加していきます。「設定」から「グループロール」の「・・・」をクリックして「IAMロールを設定」をクリック。
「Greengrass_ServiceRole」を選択し「保存」をクリック(このロールはGreengrassのクイックスタートインストール時に作成されるロールです)。
「IAM」サービスから今指定したロールにAdministratorAccessポリシーを付与しておくと楽です(実験段階では権限をゆるく設定しておきます)。
###注意点⑦ GreengrassのシステムlogとLambdaのlogを有効にする
この設定タブでlogファイルの設定ができます。デフォルトだとlogをはかない設定になっていますが、オススメはデバッグレベルのlogです。GreengrassとLambdaどちらもデバッグレベルのlogに設定しましょう。CloudWatch、ローカル(ラズパイ)どちらもにlogがはけます。自分はデバッグはラズパイでやって、記録用のlogはCloudWatchにはかせるため以下のように設定しています。
ちなみにローカルのlogは
#ルートユーザーに切り替える(/varへのアクセスはルート権限が必要なため)
sudo su
cat /greengrass/ggc/var/log/user/[リージョン]/[アカウントID]/[関数名].log
で見られます。
###注意点⑧ リソースパスは実際にラズパイのLinuxOS上に存在しなくてはいけない
デスティネーションパスはLambdaが仮想的に使うフォルダなのでラズパイのOS上に存在している必要はありませんが、リソースパスは存在している必要があります。
#4. ラズパイの追加設定
そしてここで最後の注意点があります。
###注意点⑨ リソースパスで指定したパスに「chmod 777」でアクセス(readとwrite)ができるようにする
Linuxのデフォルト設定だとGreengrassがフォルダに対してアクセスができないのでLinux側でも特定フォルダに対してアクセスを許可してやる必要があります。
chmod 777 /home/pi/Downloads
でDownloadsフォルダに対してのreadとwriteを許可します。
これでラズパイの追加設定も完了したので、AWSコンソールに戻ってGreengrass Groupのデプロイをしていきます。
先ほどと同様にGreengrass Groupの「アクション」から「デプロイ」を選択します。ステータスがin progress、その後successfully completedに変わったらデプロイ完了です。
##4-1. アップロードしたいファイルをラズパイの所定のフォルダに置く
3-2で指定したフォルダにアップロードしたいファイルを置きます。自分の場合はmario.jpegをDownloadsフォルダに置きます。
#5. 動作確認(IoT CoreからGreengrass CoreデバイスにMQTTメッセージを送ってLambdaを起動)
最後に動作確認です。IoT Coreの「テスト」タブからMQTTテストクライアントを開きます。そしてワイルドカード(#
)にサブスクライブします(これでシャドウの更新等もみられるので便利です)。
シャドウに関するやりとりが流れた後、
デフォルトでGreengrass Groupに付属しているHello World Lambdaが機能しているはずなので、下のように5秒おきにメッセージが届いています(Greengrassのクイックスタートインストール時の「Hello World Lambdaをインストールしますか?」に「Yes」と答えている必要あり)。
次にGreengrass CoreデバイスのLambdaをキックするためにMQTTメッセージを送ります。トピックは3-3で指定したinvoke/test
です。最初に「トピックにパブリッシュ」を選んでinvoke/test
を入力し「パブリッシュ」を押します。
これまでのプロセスが全て成功しているとS3内にファイルがアップロードされているはずです。
無事指定したS3バケットのPictures/GameCharacter
配下にアップロードできていました。
#6. もしアップロードができていなかったら
・注意点の①〜⑨を見直す
・リソースパスの指定など、手打ちの箇所で誤字が許されない箇所が多いので、その打ち間違えがないか確認する
・注意点⑦で設定したlogを確認する
を試してみてください。
#さいごに
AIカメラ等のプロジェクトではほぼ使うであろう「Greengrass LambdaでローカルファイルをS3にアップロード」とその注意点をまとめました。軽い画像ファイルならIoT Coreに直接MQTTで送ってRuleで処理というのも簡単だし良さそうですが、大きめのファイルやRuleをかませないファイルは今回のやり方が良さそうです。Lambdaにもっと処理を足したり新しいLambdaを足していけばエッジコンピューティングも実装できます。