AWS Greengrass + Raspberry Pi Zeroの環境構築

Raspberry Pi Zero WでAWS Greengrassを導入しようとした時のメモです。

## 参考

https://mstevetodd.com/raspberrypi-zero-w

raspberrypi zero wモデルだったので、Java 8 までしか動かないことに注意！
Java 11などを入れようとすると失敗します。

## スペック

```
$ lsb_release -a
No LSB modules are available.
Distributor ID:	Raspbian
Description:	Raspbian GNU/Linux 11 (bullseye)
Release:	11
Codename:	bullseye

uname -a
Linux rpi 5.15.32+ #1538 Thu Mar 31 19:37:58 BST 2022 armv6l GNU/Linux
```

## OS、Javaのダウンロード

`Raspberry Pi OS 32 bit`をRaspberry Pi Imagerでダウンロードした。

Raspberry pi zeroにsshする。

いつもの儀式：

```
$ sudo apt-get update
$ sudo apt-get upgrade
```

以下のコマンドでjavaがないと言われる。

```
$ java -version
-bash: java: command not found
```

javaをインストールする。このときJava 8までしかzero wモデルでは動かないことに注意する。

```
$ sudo apt install openjdk-8-jre
```

```
$ java -version
openjdk version "1.8.0_312"
OpenJDK Runtime Environment (build 1.8.0_312-8u312-b07-1+rpi1-b07)
OpenJDK Client VM (build 25.312-b07, mixed mode)
```

javaは無事インストールされた。

## Greengrassのダウンロード

```
curl -s https://d2s8p88vqu9w66.cloudfront.net/releases/greengrass-nucleus-latest.zip > greengrass-nucleus-latest.zip && unzip greengrass-nucleus-latest.zip -d GreengrassCore
```

Java 8で走るのだろうかとヒヤヒヤしながらやってみる。

```
$ sudo -E java -Droot="/greengrass/v2" -Dlog.store=FILE -jar ./GreengrassCore/lib/Greengrass.jar --aws-region us-east-1 --thing-name GreengrassQuickStartCore-181d296eb13 --thing-group-name GreengrassSetupGroup --component-default-user ggc_user:ggc_group --provision true --setup-system-service true --deploy-dev-tools true
Provisioning AWS IoT resources for the device with IoT Thing Name: [GreengrassQuickStartCore-181d296eb13]...
Found IoT policy "GreengrassV2IoTThingPolicy", reusing it
Creating keys and certificate...
Attaching policy to certificate...
Creating IoT Thing "GreengrassQuickStartCore-181d296eb13"...
Attaching certificate to IoT thing...
Successfully provisioned AWS IoT resources for the device with IoT Thing Name: [GreengrassQuickStartCore-181d296eb13]!
Adding IoT Thing [GreengrassQuickStartCore-181d296eb13] into Thing Group: [GreengrassSetupGroup]...
Successfully added Thing into Thing Group: [GreengrassSetupGroup]
Setting up resources for aws.greengrass.TokenExchangeService ...
TES role alias "GreengrassV2TokenExchangeRoleAlias" does not exist, creating new alias...
IoT role policy "GreengrassTESCertificatePolicyGreengrassV2TokenExchangeRoleAlias" for TES Role alias not exist, creating policy...
Attaching TES role policy to IoT thing...
No managed IAM policy found, looking for user defined policy...
IAM policy named "GreengrassV2TokenExchangeRoleAccess" already exists. Please attach it to the IAM role if not already
Configuring Nucleus with provisioned resource details...
Downloading Root CA from "https://www.amazontrust.com/repository/AmazonRootCA1.pem"
Created device configuration
Successfully configured Nucleus with provisioned resource details!
Creating a deployment for Greengrass first party components to the thing group
Configured Nucleus to deploy aws.greengrass.Cli component
Creating user ggc_user
ggc_user created
Creating group ggc_group
ggc_group created
Added ggc_user to ggc_group
Successfully set up Nucleus as a system service
```

うまくいきました。

一応ステータスを確認してみます。

```
$ sudo systemctl status greengrass.service
● greengrass.service - Greengrass Core
     Loaded: loaded (/etc/systemd/system/greengrass.service; enabled; vendor preset: enabled)
     Active: active (running) since Thu 2022-07-07 02:28:15 BST; 5min ago
   Main PID: 17167 (sh)
      Tasks: 35 (limit: 415)
        CPU: 2min 44.860s
     CGroup: /system.slice/greengrass.service
             ├─17167 /bin/sh /greengrass/v2/alts/current/distro/bin/loader
             └─17174 java -Dlog.store=FILE -Dlog.store=FILE -Droot=/greengrass/v2 -jar /green>

Jul 07 02:28:15 rpi systemd[1]: Started Greengrass Core.
Jul 07 02:28:15 rpi sh[17167]: Greengrass root: /greengrass/v2
Jul 07 02:28:15 rpi sh[17167]: JVM options: -Dlog.store=FILE -Droot=/greengrass/v2
Jul 07 02:28:15 rpi sh[17167]: Nucleus options: --setup-system-service false
Jul 07 02:28:39 rpi sh[17174]: Launching Nucleus...
Jul 07 02:28:52 rpi sh[17174]: Launched Nucleus successfully.
```

## 証明書などの確認

```
$ openssl x509 -noout -fingerprint -sha256 -in /greengrass/v2/thingCert.crt
SHA256 Fingerprint=XXXXX...:6C:01:C3:4B:AD:7D:97
```

この証明書がAWS上のものと一致することが確認できる。

![aws-cert.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/396623/812a9426-34fd-1e48-bf67-d0ac015fcc05.png)


## コンポーネントのデプロイを試す

ここからは以下のドキュメントを見ながら試していきます。

https://docs.aws.amazon.com/greengrass/v2/developerguide/getting-started.html#create-first-component

```
mkdir -p ~/greengrassv2/{recipes,artifacts}
cd ~/greengrassv2
```

設定用のymlファイルを作成します。

```recipes/com.example.HelloWorld-1.0.0.yaml
---
RecipeFormatVersion: '2020-01-25'
ComponentName: com.example.HelloWorld
ComponentVersion: '1.0.0'
ComponentDescription: My first AWS IoT Greengrass component.
ComponentPublisher: Amazon
ComponentConfiguration:
  DefaultConfiguration:
    Message: world
Manifests:
  - Platform:
      os: linux
    Lifecycle:
      Run: |
        python3 -u {artifacts:path}/hello_world.py "{configuration:/Message}"
  - Platform:
      os: windows
    Lifecycle:
      Run: |
        py -3 -u {artifacts:path}/hello_world.py "{configuration:/Message}"
```

artifactsのほうにもフォルダを作成します。

```
mkdir -p artifacts/com.example.HelloWorld/1.0.0
```

ここまでのファイル構成は以下のような感じです。

```
$ tree
.
|-- artifacts
|   `-- com.example.HelloWorld
|       `-- 1.0.0
`-- recipes
    `-- com.example.HelloWorld-1.0.0.yaml

4 directories, 1 file
```

pythonスクリプトを作成します。

```
$ echo 'import sys

message = "Hello, %s!" % sys.argv[1]

# Print the message to stdout, which Greengrass saves in a log file.
print(message)
' > artifacts/com.example.HelloWorld/1.0.0/hello_world.py
```

スクリプト自体はパラメータを引き取ってprintするだけです。

## 実際にデプロイ

```
$ sudo /greengrass/v2/bin/greengrass-cli deployment create \
  --recipeDir ~/greengrassv2/recipes \
  --artifactDir ~/greengrassv2/artifacts \
  --merge "com.example.HelloWorld=1.0.0"
Jul 07, 2022 3:03:48 AM software.amazon.awssdk.eventstreamrpc.EventStreamRPCConnection$1 onConnectionSetup
INFO: Socket connection /greengrass/v2/ipc.socket:8033 to server result [AWS_ERROR_SUCCESS]
Jul 07, 2022 3:03:49 AM software.amazon.awssdk.eventstreamrpc.EventStreamRPCConnection$1 onProtocolMessage
INFO: Connection established with event stream RPC server
Local deployment submitted! Deployment Id: 0e4041ab-b9c3-48ad-9e40-46bd63dd371e
```

ログを確認すると`Hello World`が出ていることがわかる。

```
$ sudo tail -f /greengrass/v2/logs/com.example.HelloWorld.log
2022-07-07T02:04:17.121Z [INFO] (pool-2-thread-22) com.example.HelloWorld: shell-runner-start. {scriptName=services.com.example.HelloWorld.lifecycle.Run, serviceName=com.example.HelloWorld, currentState=STARTING, command=["python3 -u /greengrass/v2/packages/artifacts/com.example.HelloWorld/1.0.0/hell..."]}
2022-07-07T02:04:17.803Z [INFO] (Copier) com.example.HelloWorld: stdout. Hello, world!. {scriptName=services.com.example.HelloWorld.lifecycle.Run, serviceName=com.example.HelloWorld, currentState=RUNNING}
2022-07-07T02:04:17.914Z [INFO] (Copier) com.example.HelloWorld: Run script exited. {exitCode=0, serviceName=com.example.HelloWorld, currentState=RUNNING}
```

## 今後やってみたこと

実際にランプや温度センサーなどをつけてmqttで通信などをしてみたい。