Raspberry Piを使ってAWS GreengrassにLambda関数をデプロイしてみた
まいど、大阪の市田です。
少し前の9月21日に、AWS Greengrassが東京リージョンで利用可能になりました。
AWS Greengrassが、アジアパシフィック (東京)リージョンで利用可能になりました。 | Amazon Web Services ブログ
そこで、遅ればせながら東京リージョン上陸記念として、GreengrassコアデバイスにLambda関数をデプロイしてみたので、ご紹介したいと思います。
概要
内容としては、下記のチュートリアルに沿ったものですがハマったポイントもあったので、それを踏まえてご紹介したいと思います。
Tutorial: Deploying a Simple Lambda Function to AWS Greengrass - AWS Greengrass
GreengrassグループとGreengrassコアの作成
それでは最初に、GreengrassグループとGreengrassコアを作成します。
「Use easy creation」をクリックします。
グループ名は任意のものを付けて下さい。
次にGreengrassコアの名前を付けます。デフォルトでは「グループ名_Core」という形になります。必要に応じて変更して下さい。
「easy creation」で作成される内容が表示されるので、問題無ければ「Create Group and Core」をクリックします。
グループとコアの作成が完了したら、Greengrassコアのデバイスで利用する各種証明書と、Greengrassコアの実行ファイル一式をダウンロードします。
証明書類のダウンロードリンクは3つありますが、デバイスの証明書「A certificate for this Core」と秘密鍵「A private key」の2つで構いません。
この証明書はデバイス毎に一意なものになるので、必ずダウンロードするようにしましょう。
また、Greengrassコアの実行ファイルはデバイスの種類に応じたものをダウンロードしてください。今回は「Raspberry Pi」を使うので「ARMv7l」を選択します。
Raspberry Piの準備
次にRaspberry Piの準備をします。Raspberry Piは以下の内容で用意しました。
- モデル:Raspberry Pi 3 Model B
- OS:Raspbian Jessie 2017-07-05
- カーネルバージョン:4.9.35-v7+ (
apt-get dist-upgrade
実施済み)
下記ドキュメントでは「Raspbian Jessie 2017-03-02」がサポート対象となっていますが、今回は「Jessie」の最新バージョンを利用しました。
尚、最新の「Stretch」でもチュートリアルの内容が動作することを確認しましたが、その他の部分で動作しない可能性があるので予めご注意下さい。
Tutorial: Deploying a Simple Lambda Function to AWS Greengrass - AWS Greengrass
それでは、最初に専用のユーザとグループを作成します。
$ sudo adduser --system ggc_user $ sudo addgroup --system ggc_group
次に、ドキュメントではrpi-update
コマンドでカーネルを4.9に更新することになっていますが、既に4.9のカーネルを利用しているので、カーネルのアップデートはスキップします。
rpi-update
コマンドでカーネルをアップデートすると、公開されている最新のカーネルに更新されてしまうので、2017年10月時点ではGreengrassコアが起動できなくなります。
もし誤ってアップデートしてしまった場合は、下記のコマンドで元のバージョンに戻すことが可能です。
$ sudo apt-get install --reinstall raspberrypi-bootloader raspberrypi-kernel
尚、Raspbianのカーネルアップデートについては、下記に詳細が記載されています。
Updating the kernel - Raspberry Pi Documentation
次にsqlite3
をインストールします。
$ sudo apt-get install sqlite3
dpkgコマンドで確認して、正常にインストールできていればOKです。
$ dpkg -l sqlite3 Desired=Unknown/Install/Remove/Purge/Hold | Status=Not/Inst/Conf-files/Unpacked/halF-conf/Half-inst/trig-aWait/Trig-pend |/ Err?=(none)/Reinst-required (Status,Err: uppercase=bad) ||/ Name Version Architecture Description +++-======================-================-================-================================================= ii sqlite3 3.8.7.1-1+deb8u2 armhf Command line interface for SQLite 3
次にハードリンク/ソフトリンクの保護を行います。
/etc/sysctl.d/98-rpi.conf
に下記の2行を追記します。
fs.protected_hardlinks = 1 fs.protected_symlinks = 1
設定を反映するために再起動します。
$ sudo reboot
次のコマンドで設定が確認できればOKです。
$ sudo sysctl -a | grep "fs.protected_hardlinks" 以下を確認 fs.protected_hardlinks = 1
$ sudo sysctl -a | grep "fs.protected_symlinks" 以下を確認 fs.protected_symlinks = 1
Greengrassコアソフトウェアの展開
次にRaspberry PiにGreengrassコアをセットアップします。 ダウンロードしておいたGreengrassコアの実行ファイルをRaspberry PiにSCPで保存します。
$ scp greengrass-linux-armv7l-1.1.0.tar.gz pi@xx.xx.xx.xx:/home/pi/
コピーできたらRaspberry PiへSSHログインして、ファイルを展開します。
$ sudo tar -zxf greengrass-linux-armv7l-1.1.0.tar.gz -C /
次に各種証明書を同じ要領でRaspberry Piにコピーします。
$ scp xxxxxxxxxx-certificate.pem.crt pi@xx.xx.xx.xx:/home/pi/ $ scp xxxxxxxxxx-certificate.pem.key pi@xx.xx.xx.xx:/home/pi/
ルートCA証明書はSymantec/Verisignのものをダウンロードします。SCPするのは面倒なのでRaspberry Piから直接ダウンロードしてしまいましょう。
$ wget https://www.symantec.com/content/en/us/enterprise/verisign/roots/VeriSign-Class%203-Public-Primary-Certification-Authority-G5.pem -O root-ca.pem
これらの各ファイルは、/greengrass/certs
ディレクトリに全て設置します。
$ sudo mv cloud.pem.* /greengrass/certs/ $ sudo mv root-ca.pem /greengrass/certs/
尚、Greengrassコア実行ファイルのバージョンによって、構成が異なるので注意して下さい。最新バージョンは「v1.1.0」です。
ドキュメント上では「v1.0.0」と「v1.1.0」をタブで選択表示できるので、利用バージョンに合わせて読み替えて下さい。
Greengrassコアソフトウェアの設定
次にGreengrassコアソフトウェアの設定を行っていきます。まず最初にGreengrassコアのARNを確認しておきます。
GreengrassのマネジメントコンソールでGroups
から、該当のグループをクリックします。
Cores
から該当するコアをクリックします。
Detailにある「Thing ARN」の内容を控えておきます。
次にAWS IoTのエンドポイントも確認しておきます。マネジメントコンソールの「Settings」から確認できます。
これで必要な情報が確認できたので設定ファイルを修正します。ファイルは/greengrass/config/config.json
です。
これを下記のように修正します。
caPath
、certPath
、keyPath
は先程SCPでコピーした各証明書ファイルを指定します。パスは/greengrass/certs/
からの相対パスで記載します。
「thingArn」と「iotHost」は先程控えておいたものを指定します。
「ggHost」のAWS_REGION_HERE
には、東京リージョンで試しているのでap-northeast-1
を指定しましょう。また、Raspberry Piはsystemdに対応しているのでuntime::cgroup::useSystemd
はyes
にします。
{ "coreThing": { "caPath": "root-ca.pem", "certPath": "cloud.pem.crt", "keyPath": "cloud.pem.key", "thingArn": "arn:aws:iot:ap-northeast-1:xxxxxxxxxxxx:thing/MyGroup_Core", "iotHost": "xxxxxxxxxxxxx.iot.ap-northeast-1.amazonaws.com", "ggHost": "greengrass.iot.ap-northeast-1.amazonaws.com" }, "runtime": { "cgroup": { "useSystemd": "yes" } } }
Greengrassコアの起動
Raspberry Pi側の準備が整ったのでGreengrassコアを起動します。
$ sudo /greengrass/ggc/core/greengrassd start
正常に起動できると、下記のように出力されてGreengrassデーモンのPIDが表示されます。
Setting up greengrass daemon Validating execution environment Found cgroup subsystem: cpu Found cgroup subsystem: cpuacct Found cgroup subsystem: blkio Found cgroup subsystem: memory Found cgroup subsystem: devices Found cgroup subsystem: freezer Found cgroup subsystem: net_cls Starting greengrass daemon Greengrass successfully started with PID: 1293
また/etc/fstab
に下記の設定も追記しておきましょう。
cgroup /sys/fs/cgroup cgroup defaults 0 0
Lambda関数の作成
次に、Raspberry Pi(Greengrassコアデバイス)上で実行するLambda関数を作成します。Lambdaのコンソール画面から作成していきます。
今回は予め用意されているサンプルのブループリントを利用するので、Greengrassで検索します。
Python版を選びます。
関数の名前は適当に付けて下さい。IAM Roleは今回は新規に作成しました。
IAM Roleのポリシーはデフォルトです。
IAM Roleの作成が完了すれば元の画面に戻ります。
問題なければ「Create function」で作成します。
作成できたら、新しいバージョンを発行します。Greengrassコアではこのバージョンを指定してLambda関数をデバイスにデプロイすることができます。
バージョンの説明は適当なものを記入してください。
Lambda関数をグループ定義に追加する
先程作成したLambda関数をGreengrassグループに追加して関連付けます。
これまでと同じようにGreengrassのマネジメントコンソールから該当のグループを選択します。
「Lambdas」をクリックします。
「Add your first Lambda」をクリックします。
作成したLambda関数を使うので「Use existing Lambda」を選択して下さい。
先程作成したLamnbda関数を選択します。
デプロイしたいバージョンを選択して「Finish」で完了します。(今回は1つしかありませんが)
次に、チュートリアル用として、デプロイしたLambda関数の設定を修正します。追加したLambda関数を選択してください。
次に「Make this function long-lived and keep it running indefinitely」を選択して「Update」をクリックします。
これにより、このLambda関数はGreengrassコアデバイス上で動き続けるようになります。
また、このLambda関数は下記のように5秒ごとにメッセージをパブリッシュするので、正常にデプロイできれば「永続的に5秒間隔でメッセージをパブリッシュ」します。
def greengrass_hello_world_run(): if not my_platform: client.publish(topic='hello/world', payload='Hello world! Sent from Greengrass Core.') else: client.publish(topic='hello/world', payload='Hello world! Sent from Greengrass Core running on platform: {}'.format(my_platform)) # Asynchronously schedule this function to be run again in 5 seconds Timer(5, greengrass_hello_world_run).start() # Execute the function above greengrass_hello_world_run()
サブスクリプションをグループ定義に追加する
ドキュメントに記載がありますが、Greengrassコアはデバイス、Lambda関数、AWS間でMQTTによりメッセージを渡すことが可能です。
その為、ここではサブスクリプションの設定を行います。該当するGreengrassグループの画面から「Subscriptions」を選択します。
「source」に作成したLambda関数を選択します。
「target」には「Services」から「IoT Cloud」を選択します。
この状態で「Next」をクリックします。
オプションでトピックフィルタを設定できます。テストなのでワイルドカードトピックでもよいかと思いますが、ドキュメントにならってhello/world
というトピックフィルタを設定してみます。
最後に「Finish」をクリックします。
グループのデプロイ
ここまでGreengrassグループとコアの定義を行ってきましたが、これらの定義情報はまだAWS上にのみ存在している状態です。その為、GreengrassコアデバイスであるRaspberry Piにこれらを展開していきます。
Greengrassグループのコンソールで「Deployments」を選択して、「Actions」から「Deploy」をクリックします。
次の画面では「Automatic detection」をクリックします。
Greengrassコアデバイス(Raspberry Pi)に対してデプロイがスタートするので、状態が「In progress」に変わります。
無事デプロイできると「Successfully completed」に変わります。
無事にデプロイできると、デバイス側の/greengrass/ggc/deployment/lambda
にLambda関数がデプロイされていることが分かります。
# ls -l /greengrass/ggc/deployment/lambda total 4 drwxr-xr-x 6 ggc_user ggc_group 4096 Oct 17 18:47 arn:aws:lambda:ap-northeast-1:xxxxxxxxxxxx:function:Greengrass-HelloWorld:1
尚、先程の「Actions」で「Reset Deployments」を実行するとデバイス上からもLambda関数が削除されます。
Lambda関数がコアデバイスで実行されているか確認
最後に動作確認です。
ここまでの作業に問題がなければ、Lambda関数がGreengrassコアデバイス上で実行されていて、hello/world
トピックにメッセージが届いているはずです。
マネジメントコンソールから「Test」をクリックします。
トピックに「hello/world」と入力して「Subscribe to topic」をクリックします。
下記のようにマネジメントコンソール上で、hello/world
トピックにLambda関数でパブリッシュされたメッセージを確認することができました。
AWSのドキュメントとは異なりJSON形式ではない表示になっていますが、これはドキュメント作成時のLambda関数の内容が現状とは異なっている為と思われます。
実際、Lambda関数のソースを見るとJSON形式で出力していないので、JSONで表示したい場合はパブリッシュする箇所を下記のように修正しましょう。
client.publish(topic='hello/world', payload='{"message":"Hello world! Sent from Greengrass Core."}')
これでJSON形式で出力できます。
尚、緑色の表示を消したい場合は、表示形式を「文字列」として表示すればOKです。
これで緑色の説明表示が消えました。
尚、コアデバイス上のログは/greengrass/ggc/var/
以下に出力されます。今回のLambda関数個別のログは/greengrass/ggc/var/log/system/python_runtime.log
に出力されていて、5秒毎にパブリッシュしている様子を確認することができました。
グループの削除
デプロイ済みの状態でグループを削除しようとすると、下記のメッセージが出て削除できません。
その場合は、最初にデプロイをリセットする必要があります。リセットを実行するとデバイス上からもLambda関数等が削除されます。
この状態になればグループを削除することができるようになります。
尚、同名のグループを再度作成する場合、GreengrassコアのThingsの設定が残っていると失敗するので、予めThings側も削除するようにしましょう。
最後に
Greengrass面白いですね。
次回はGreengrassグループ内での接続について試してみたいと思います。
以上です。