Raspberry Piを使ってAWS GreengrassにLambda関数をデプロイしてみた

2017.10.17

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

まいど、大阪の市田です。
少し前の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コアを作成します。

01-create-group

「Use easy creation」をクリックします。

02-easy-creation

グループ名は任意のものを付けて下さい。

03-groupname

次にGreengrassコアの名前を付けます。デフォルトでは「グループ名_Core」という形になります。必要に応じて変更して下さい。

04-ggc-name

「easy creation」で作成される内容が表示されるので、問題無ければ「Create Group and Core」をクリックします。

05-create-group-core

グループとコアの作成が完了したら、Greengrassコアのデバイスで利用する各種証明書と、Greengrassコアの実行ファイル一式をダウンロードします。

証明書類のダウンロードリンクは3つありますが、デバイスの証明書「A certificate for this Core」と秘密鍵「A private key」の2つで構いません。
この証明書はデバイス毎に一意なものになるので、必ずダウンロードするようにしましょう。

また、Greengrassコアの実行ファイルはデバイスの種類に応じたものをダウンロードしてください。今回は「Raspberry Pi」を使うので「ARMv7l」を選択します。

06-cert-core

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」をタブで選択表示できるので、利用バージョンに合わせて読み替えて下さい。

54-select-version

Greengrassコアソフトウェアの設定

次にGreengrassコアソフトウェアの設定を行っていきます。まず最初にGreengrassコアのARNを確認しておきます。

GreengrassのマネジメントコンソールでGroupsから、該当のグループをクリックします。

08-gg-group

Coresから該当するコアをクリックします。

09-core

Detailにある「Thing ARN」の内容を控えておきます。

10-core-arn

次にAWS IoTのエンドポイントも確認しておきます。マネジメントコンソールの「Settings」から確認できます。

11-awsiot

これで必要な情報が確認できたので設定ファイルを修正します。ファイルは/greengrass/config/config.jsonです。

これを下記のように修正します。
caPathcertPathkeyPathは先程SCPでコピーした各証明書ファイルを指定します。パスは/greengrass/certs/からの相対パスで記載します。

「thingArn」「iotHost」は先程控えておいたものを指定します。
「ggHost」AWS_REGION_HEREには、東京リージョンで試しているのでap-northeast-1を指定しましょう。また、Raspberry Piはsystemdに対応しているのでuntime::cgroup::useSystemdyesにします。

{
    "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のコンソール画面から作成していきます。

12-lambda

今回は予め用意されているサンプルのブループリントを利用するので、Greengrassで検索します。

13-lambda-scratch

Python版を選びます。

14-keyword-gg

関数の名前は適当に付けて下さい。IAM Roleは今回は新規に作成しました。

15-create-iam-role

IAM Roleのポリシーはデフォルトです。

16-create-new-iam-role

IAM Roleの作成が完了すれば元の画面に戻ります。

17-create-function

問題なければ「Create function」で作成します。

18-create-function

作成できたら、新しいバージョンを発行します。Greengrassコアではこのバージョンを指定してLambda関数をデバイスにデプロイすることができます。

20-publish-new-version

バージョンの説明は適当なものを記入してください。

21-version

Lambda関数をグループ定義に追加する

先程作成したLambda関数をGreengrassグループに追加して関連付けます。
これまでと同じようにGreengrassのマネジメントコンソールから該当のグループを選択します。

22-gg-group

「Lambdas」をクリックします。

23-lambdas

「Add your first Lambda」をクリックします。

24-add-lambda

作成したLambda関数を使うので「Use existing Lambda」を選択して下さい。

25-existing-lambda

先程作成したLamnbda関数を選択します。

26-select-lambda

デプロイしたいバージョンを選択して「Finish」で完了します。(今回は1つしかありませんが)

27-v1

次に、チュートリアル用として、デプロイしたLambda関数の設定を修正します。追加したLambda関数を選択してください。

28-select-gg-lambda

次に「Make this function long-lived and keep it running indefinitely」を選択して「Update」をクリックします。

29-update-lambda-config

これにより、この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」を選択します。

30-subscriptopns

「source」に作成したLambda関数を選択します。

31-select-source

「target」には「Services」から「IoT Cloud」を選択します。

32-select-target

この状態で「Next」をクリックします。

33-source-target

オプションでトピックフィルタを設定できます。テストなのでワイルドカードトピックでもよいかと思いますが、ドキュメントにならってhello/worldというトピックフィルタを設定してみます。

34-topic-filter

最後に「Finish」をクリックします。

35-finish-subscription

グループのデプロイ

ここまでGreengrassグループとコアの定義を行ってきましたが、これらの定義情報はまだAWS上にのみ存在している状態です。その為、GreengrassコアデバイスであるRaspberry Piにこれらを展開していきます。

Greengrassグループのコンソールで「Deployments」を選択して、「Actions」から「Deploy」をクリックします。

36-deploy

次の画面では「Automatic detection」をクリックします。

37-auto-detection

Greengrassコアデバイス(Raspberry Pi)に対してデプロイがスタートするので、状態が「In progress」に変わります。

46-in-progress-deploy

無事デプロイできると「Successfully completed」に変わります。

47-success-deploy

無事にデプロイできると、デバイス側の/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」をクリックします。

48-select-test

トピックに「hello/world」と入力して「Subscribe to topic」をクリックします。

49-subscribe

下記のようにマネジメントコンソール上で、hello/worldトピックにLambda関数でパブリッシュされたメッセージを確認することができました。

50-test-ok

AWSのドキュメントとは異なりJSON形式ではない表示になっていますが、これはドキュメント作成時のLambda関数の内容が現状とは異なっている為と思われます。

実際、Lambda関数のソースを見るとJSON形式で出力していないので、JSONで表示したい場合はパブリッシュする箇所を下記のように修正しましょう。

client.publish(topic='hello/world', payload='{"message":"Hello world! Sent from Greengrass Core."}')

これでJSON形式で出力できます。

53-json

尚、緑色の表示を消したい場合は、表示形式を「文字列」として表示すればOKです。

51-display-strings

これで緑色の説明表示が消えました。

52-display-strings

尚、コアデバイス上のログは/greengrass/ggc/var/以下に出力されます。今回のLambda関数個別のログは/greengrass/ggc/var/log/system/python_runtime.logに出力されていて、5秒毎にパブリッシュしている様子を確認することができました。

グループの削除

デプロイ済みの状態でグループを削除しようとすると、下記のメッセージが出て削除できません。

55-fail-delete-group

その場合は、最初にデプロイをリセットする必要があります。リセットを実行するとデバイス上からもLambda関数等が削除されます。

56-reset-deploy

この状態になればグループを削除することができるようになります。
尚、同名のグループを再度作成する場合、GreengrassコアのThingsの設定が残っていると失敗するので、予めThings側も削除するようにしましょう。

最後に

Greengrass面白いですね。
次回はGreengrassグループ内での接続について試してみたいと思います。

以上です。