Raspberry Pi Zero WでAWS IoT Greengrassを使ってみる

AWS IoT GreengrassのVer 1.9.3でARMv6に対応したことで、Raspberry Pi Zeroでも使えるようになりました。

[AWS IoT Greengrass 1.9.3 With Support for ARMv6 and New Machine Learning Connectors Now Available](https://aws.amazon.com/jp/about-aws/whats-new/2019/09/aws-iot-greengrass-1-9-3-with-support-for-armv6-and-new-machine-learning-connectors-now-available/)

Zeroは通常のRaspberry Piよりもかなり小型のデバイスなので、これで使えるようになると色々と可能性が広がるかなと。ということで、早速インストールを試してみます。

## Raspberry Piのセットアップ

Greengrass 1.9.3は新しいRaspbian Busterで利用できるので、そのイメージをダウンロードします。
今回はデスクトップは使う予定はないので、`Raspbian Buster Lite`を使いました。
https://www.raspberrypi.org/downloads/raspbian/

## Greengrassのインストール準備

Greengrassのセットアップは通常のRaspberry Piと同じなので、公式ドキュメントに沿ってセットアップを進めます。
[Raspberry Pi のセットアップ](https://docs.aws.amazon.com/ja_jp/greengrass/latest/developerguide/setup-filter.rpi.html)

まずは、sshしてunameの情報を見てみます。

```sh
uname -a

Linux raspberrypi 4.19.57+ #1244 Thu Jul 4 18:42:50 BST 2019 armv6l GNU/Linux
```

Greengrass用のユーザー／グループを作成

```sh
sudo adduser --system ggc_user
sudo addgroup --system ggc_group
```

ハードリンクとソフトリンク (symlink) の保護を有効にします。

```sh
cd /etc/sysctl.d
ls 98-rpi.conf

sudo vi 98-rpi.conf
```

viで98-rpi.confを編集し、ファイル末尾に以下の２行を追加します。

```98-rpi.conf
fs.protected_hardlinks = 1
fs.protected_symlinks = 1
```

メモリ cgroups を有効にしてマウントします。

```sh
cd /boot/
sudo vi cmdline.txt
```

改行させないで、既存の行の末尾に以下を追加

```cmdline.txt
cgroup_enable=memory cgroup_memory=1
```

ここで一度再起動をします

```sh
sudo reboot
```

リンクの設定が反映されているかを確認

```sh
sudo sysctl -a 2> /dev/null | grep fs.protected

fs.protected_fifos = 0
fs.protected_hardlinks = 1 ← これ
fs.protected_regular = 0
fs.protected_symlinks = 1 ← これ
```

Greengrassが動く環境になっているかを確認

```sh
cd /home/pi/Downloads
mkdir greengrass-dependency-checker-GGCv1.9.x
cd greengrass-dependency-checker-GGCv1.9.x
wget https://github.com/aws-samples/aws-greengrass-samples/raw/master/greengrass-dependency-checker-GGCv1.9.x.zip
unzip greengrass-dependency-checker-GGCv1.9.x.zip
cd greengrass-dependency-checker-GGCv1.9.x
sudo modprobe configs
sudo ./check_ggc_dependencies
```
結果

```
==========================Checking script dependencies==============================
The device has all commands required for the script to run.

========================Dependency check report for GGC v1.9.x=========================
System configuration:
Kernel architecture: armv6l
Init process: /lib/systemd/systemd
Kernel version: 4.19.57
C library: Debian GLIBC 2.28-10+rpi1
C library version: 2.28
Directory /var/run: Present
/dev/stdin: Found
/dev/stdout: Found
/dev/stderr: Found
----------------------------Commands and software packages--------------------------
Python 2.7 version: 2.7.16
Python 3.7 version: 3.7.3
NodeJS 8.10: Not found
Java 8: Not found
wget: Present
realpath: Present
tar: Present
readlink: Present
basename: Present
dirname: Present
pidof: Present
df: Present
grep: Present
umount: Present
mv: Present
gzip: Present
mkdir: Present
rm: Present
ln: Present
cat: Present
cut: Present

---------------------------------Platform security----------------------------------
Hardlinks_protection: Enabled
Symlinks protection: Enabled

-----------------------------------User and group-----------------------------------
ggc_user: Present
ggc_group: Present

----------------(Optional) Greengrass container dependency check----------------

--------------------------------Kernel configuration--------------------------------
Kernel config file: /proc/config.gz

Namespace configs:
CONFIG_IPC_NS: Enabled
CONFIG_UTS_NS: Enabled
CONFIG_USER_NS: Enabled
CONFIG_PID_NS: Enabled

Cgroup configs:
CONFIG_CGROUP_DEVICE: Enabled
CONFIG_CGROUPS: Enabled
CONFIG_MEMCG: Enabled

Other required configs:
CONFIG_POSIX_MQUEUE: Enabled
CONFIG_OVERLAY_FS: Enabled
CONFIG_HAVE_ARCH_SECCOMP_FILTER: Enabled
CONFIG_SECCOMP_FILTER: Enabled
CONFIG_KEYS: Enabled
CONFIG_SECCOMP: Enabled
CONFIG_SHMEM: Enabled

------------------------------------Cgroups check-----------------------------------
Cgroups mount directory: /sys/fs/cgroup

Devices cgroup: Enabled and Mounted
Memory cgroup: Enabled and Mounted


------------------------------------Results-----------------------------------------
Note:
1. It looks like the kernel uses 'systemd' as the init process. Be sure to set the
'useSystemd' field in the file 'config.json' to 'yes' when configuring Greengrass core.

Missing optional dependencies:
1. Could not find the binary 'nodejs8.10'.

If NodeJS 8.10 or later is installed on the device, name the binary 'nodejs8.10' and
add its parent directory to the PATH environment variable. NodeJS 8.10 or later is
required to execute NodeJS lambdas on Greengrass core.

2. Could not find the binary 'java8'.

If Java 8 or later is installed on the device name the binary 'java8' and add its
parent directory to the PATH environment variable. Java 8 or later is required to
execute Java lambdas on Greengrass core.

Supported lambda isolation modes:
No Container: Supported
Greengrass Container: Supported

----------------------------------Exit status---------------------------------------
You can now proceed to installing the Greengrass core 1.9.x software on the device.
Please reach out to the AWS Greengrass support if issues arise.
```

エラーが出てなかったので、Greengrassが動きそうです。
python3.7も入ってますね。GreengrassのLambdaでNodeJSまたはJavaを利用したい場合は、別途インストールが必要です。

## Greengrassの設定

Greengrass側の設定は[以前書いた記事](https://qiita.com/sparkgene/items/2757f35bbae0186cced7#2greengrass%E3%81%AE%E6%BA%96%E5%82%99)で紹介しているので、そちらを参照してください。

前の記事との違いはダウンロードするGreengrassのソフトウエアがARMv6l用を選ぶこと。

<img width="502" alt="スクリーンショット_2019-09-21_11_13_58.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/36184/32639e09-5097-a72b-2b8d-8037fb89a6a9.png">

## Greengrassのインストール

AWS IoT側の設定が終わったので、Zeroにダウンロードしたファイルをセットアップします。
まずは、自分のPCからSCPでファイルをコピーします。IPアドレス、ユーザー名、ファイル名は実際の環境に合わせてください。

```sh
scp ~/11111111-setup.tar.gz pi@192.168.1.11:~/

scp ~/greengrass-linux-armv6l-1.9.3.tar.gz pi@192.168.1.11:~/
```

Zero上でコピーしたファイルを展開します。

```sh
sudo tar -zxvf greengrass-linux-armv6l-1.9.3.tar.gz -C /
sudo tar -zxvf 11111111-setup.tar.gz -C /greengrass
```

AWS IoTのエンドポイントの検証で利用するRoot CAの証明書もダウンロードします

```sh
sudo wget https://www.amazontrust.com/repository/AmazonRootCA1.pem -O /greengrass/certs/root.ca.pem
```

Greengrassで利用する証明書や、エンドポイントの設定は/greengrass/config/config.jsonに書かれています

```/greengrass/config/config.json
{
  "coreThing" : {
    "caPath" : "root.ca.pem",
    "certPath" : "11111111.cert.pem",
    "keyPath" : "11111111.private.key",
    "thingArn" : "arn:aws:iot:ap-northeast-1:1234567890:thing/RaspberryPiZero_Core",
    "iotHost" : "11111111-ats.iot.ap-northeast-1.amazonaws.com",
    "ggHost" : "greengrass-ats.iot.ap-northeast-1.amazonaws.com",
    "keepAlive" : 600
  },
  "runtime" : {
    "cgroup" : {
      "useSystemd" : "yes"
    }
  },
  "managedRespawn" : false,
  "crypto" : {
    "principals" : {
      "SecretsManager" : {
        "privateKeyPath" : "file:///greengrass/certs/11111111.private.key"
      },
      "IoTCertificate" : {
        "privateKeyPath" : "file:///greengrass/certs/11111111.private.key",
        "certificatePath" : "file:///greengrass/certs/11111111.cert.pem"
      }
    },
    "caPath" : "file:///greengrass/certs/root.ca.pem"
  }
}
```

これで、起動する準備ができたので、実際に起動します。

```sh
sudo /greengrass/ggc/core/greengrassd start

Setting up greengrass daemon
Validating hardlink/softlink protection
Waiting for up to 1m10s for Daemon to start

Greengrass successfully started with PID: 792
```

ログの状態を確認してみます

```
・
・
・
[2019-09-21T03:26:10.638+01:00][DEBUG]-Subscribed to topic.	{"topic": "$aws/things/RaspberryPiZero_Core-gda/shadow/get/accepted"}
[2019-09-21T03:26:10.638+01:00][DEBUG]-Publish	{"topic": "$aws/things/RaspberryPiZero_Core-gda/shadow/get", "qos": 1}
[2019-09-21T03:26:10.654+01:00][INFO]-All topics subscribed.	{"clientId": "RaspberryPiZero_Core"}
```

DEBUGレベルで吐かれているのは気になるけど、ちゃんと動いてそうです。

実際にマネージメントコンソールからデプロイをしてみましょう

<img width="998" alt="スクリーンショット_2019-09-21_11_32_28.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/36184/c0150ca8-2a7f-6cdb-d27a-297ed5891f27.png">

`自動検出`を選択
初めてデプロイするときは、Roleを作成しますみたいなダイアログが表示されるので、作成してください。

<img width="991" alt="スクリーンショット_2019-09-21_11_32_43.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/36184/e53a584a-242a-db54-6853-bbd7eb0ad393.png">

無事デプロイも出来ました

<img width="999" alt="スクリーンショット_2019-09-21_11_33_15.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/36184/6c738fdf-d822-cf4c-f675-6e5c2216df08.png">

## Lambdaをデプロイして動作確認

ここも前の[記事を参考にLambdaを作成してデプロイ](https://qiita.com/sparkgene/items/2757f35bbae0186cced7#4lambda%E3%82%92%E3%83%87%E3%83%97%E3%83%AD%E3%82%A4%E3%81%97%E3%81%A6%E3%83%A1%E3%83%83%E3%82%BB%E3%83%BC%E3%82%B8%E3%82%92%E9%80%81%E4%BF%A1%E3%81%99%E3%82%8B)します。

せっかくPython3.7が入っているのでLambda作るときのランタイムはPython3.7にしました。

## AWS IoTのテスト画面でメッセージを確認

<img width="1015" alt="スクリーンショット 2019-09-21 11.59.23.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/36184/bdedf600-ff9e-4e7b-8b6f-517aab4b6ee0.png">

メッセージも届きました。

## まとめ

Raspberry Pi ZeroでGreengrassが使えるようなったので、ちょっとしたアプリケーションを作成して、それを継続的にアップデートしたいといった場合も、Greengrassであればデプロイするだけで反映できるので、実機にSSHして〜といった作業が不要になります。遠隔地にデバイスを置く場合はこういった機能を自作する必要がありますが、Greengrassだと楽ですね。