Docker で Greengrass コンポーネント開発
この投稿では、 AWS IoT Greengrass の Docker イメージを使用して、ローカル環境で Greengrass コンポーネントを開発する方法について説明します。 詳細については、公式ドキュメントをご参照ください。
概要
この投稿では、毎秒 AWS IoT Core に対して MQTT 経由でメッセージを送信する Greengrass コンポーネントを開発します。 このコンポーネントは、 Greengrass CLI を使用してローカルの Docker コンテナにデプロイされます。
最終的に、プロジェクトのディレクトリ構成は以下のようになります。
/
|-- components/
| `-- mqtt_publisher/
| |-- .gitignore
| |-- gdk-config.json
| |-- main.py
| |-- recipe.yaml
| `-- requirements.txt
`-- docker/
|-- greengrass-v2-credentials/
| `-- credentials
|-- .env
`-- docker-compose.yml
Greengrass カスタムコンポーネント開発
AWS IoT Core を介して MQTT でメッセージをパブリッシュする Greengrass コンポーネントを開発します。
Greengrass Development Kit (GDK) インストール
Greengrass Development Kit (GDK) をインストールしてください。
pip install gdk
を実行すると、 Greengrass Development Kit とは無関係のライブラリがインストールされます。 $ pip install -U git+https://github.com/aws-greengrass/[email protected]
開発
gdk component init
を実行して開発を開始してください。
$ mkdir ./components
$ gdk component init \
--language python \
--template HelloWorld \
--name components/mqtt_publisher
このコマンドは以下のファイルを生成します。
この投稿では src
および tests
ディレクトリは使用しません。
./
|-- components/
| | |-- mqtt_publisher/
| | | |-- src/
| | | | |-- greeter.py
| | | |-- tests/
| | | | |-- test_greeter.py
| | | |-- .gitignore
| | | |-- gdk-config.json
| | | |-- main.py
| | | |-- README.md
| | | |-- recipe.yaml
gdk-config.json
でコンポーネントのメタデータを以下のように設定してください。
gdk component publish
を使用してコンポーネントをパブリッシュしない場合は、 publish.bucket
に S3 バケットを設定する必要はありません。
設定ファイルに関する詳細は、公式ドキュメントをご参照ください。
version
の値に NEXT_PATCH
は使用できません。 greengrass-cli deployment create
を実行する際にエラーが発生します。 {
"component": {
"com.example.MqttPublisher": {
"author": "wasabee.dev",
"version": "0.0.1",
"build": {
"build_system": "zip"
},
"publish": {
"bucket": "<PLACEHOLDER_BUCKET>",
"region": "ap-northeast-1"
}
}
},
"gdk_version": "1.0.0"
}
Python スクリプト
以下のコードで main.py
を作成してください。
このスクリプトは毎秒 MQTT メッセージをトピック /mqtt-publisher
にパブリッシュします。
import json
import random
from datetime import datetime
from time import sleep
import boto3
client = boto3.client('iot-data')
def main():
payload = {
"value": random.randint(1, 10000),
"datetime": datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
}
while True:
client.publish(
topic='/mqtt-publisher',
payload=json.dumps(payload).encode(),
qos=1,
contentType='application/json',
)
print(f'Message was sent successfully: {payload}')
sleep(1)
if __name__ == "__main__":
main()
以下の内容で requirements.txt
を作成してください。
依存関係は、後述の recipe.yaml
で指定されているコンポーネントのインストール時にインストールされます。
boto3==1.26.65
コンポーネントレシピ
以下の内容で recipe.yaml
を作成してください。
レシピの仕様については、公式ドキュメントをご参照ください。
---
RecipeFormatVersion: "2020-01-25"
ComponentName: "{COMPONENT_NAME}"
ComponentVersion: "{COMPONENT_VERSION}"
ComponentDescription: "This is an mqtt publisher written in Python."
ComponentPublisher: "{COMPONENT_AUTHOR}"
ComponentDependencies:
aws.greengrass.TokenExchangeService:
VersionRequirement: '^2.0.0'
Manifests:
- Platform:
os: all
Artifacts:
- URI: "s3://BUCKET_NAME/COMPONENT_NAME/COMPONENT_VERSION/mqtt_publisher.zip"
Unarchive: ZIP
Lifecycle:
Install: "pip3 install --user -r {artifacts:decompressedPath}/mqtt_publisher/requirements.txt"
Run: "python3 -u {artifacts:decompressedPath}/mqtt_publisher/main.py"
コンポーネント依存関係
ComponentDependencies
で aws.greengrass.TokenExchangeService
を指定してください。
これは、 Python スクリプトが boto3 を使用しているため、インストールが必要です。
AWS IoT Greengrass provides a public component, the token exchange service component, that you can define as a dependency in your custom component to interact with AWS services. The token exchange service provides your component with an environment variable, AWS_CONTAINER_CREDENTIALS_FULL_URI, that defines the URI to a local server that provides AWS credentials.
ライフサイクル
requirements.txt
に記載された Python ライブラリをインストールするために、ライフサイクルフックを使用できます。
プレースホルダー
次のプレースホルダは、 gdk component build
で gdk-config.json
で設定された値に置き換えられます。
{COMPONENT_NAME}
{COMPONENT_VERSION}
{COMPONENT_AUTHOR}
Artifacts.URI
BUCKET_NAME
COMPONENT_NAME
COMPONENT_VERSION
コンポーネントビルド
gdk component build
を使用して、コンポーネントをビルドしてください。
$ cd components/mqtt_publisher
$ gdk component build
コンポーネントをビルドした後、ビルドされたアーティファクトは greengrass-build
ディレクトリに生成されます。
コンポーネントはローカルの Docker コンテナにデプロイされるため、 gdk component publish
を実行する必要はありません。
gdk-config.json
の version
に NEXT_PATCH
を指定した場合、後で実行される bin/greengrass-cli deployment create
が失敗します。 Greengrass Core in Docker
<PROJECT_ROOT>/docker
ディレクトリで作業してください。
セキュリティクレデンシャル
Docker コンテナ内で Greengrass Core を自動プロビジョニングモードでセットアップする際、 Greengrass Core インストーラーは必要な AWS リソースをプロビジョニングするために AWS セキュリティクレデンシャルを使用する必要があります。
AWS の永続クレデンシャルを使用できますが、 sts get-session-token
を使用して一時クレデンシャルの利用を強くお勧めします。
次の AWS リソースが自動で作成されます。
- AWS IoT
- Greengrass Core Device
- IoT Thing
- IoT Thing Group
- Certificate
- Policies (x2)
- Token Exchange Role Alias
- AWS IAM
- Token Exchange Role
- Token Exchange Role Policy
次のコマンドで一時クレデンシャルを取得してください。
$ aws sts get-session-token
Greengrass Core インストーラーが使用するクレデンシャルファイルを作成してください。
$ mkdir ./greengrass-v2-credentials
$ nano ./greengrass-v2-credentials/credentials
以下は例です。
[default]
aws_access_key_id = AKIAIOSFODNN7EXAMPLE
aws_secret_access_key = wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
aws_session_token = AQoEXAMPLEH4aoAH0gNCAPy...truncated...zrkuWJOgQs8IZZaIv2BXIa2R4Olgk
環境変数ファイル
Greengrass Core インストーラーで使用される環境変数を設定するために、 .env
を作成してください。
詳細については、公式ドキュメントをご参照ください。
GGC_ROOT_PATH=/greengrass/v2
AWS_REGION=ap-northeast-1
PROVISION=true
THING_NAME=MyGreengrassCore
THING_GROUP_NAME=MyGreengrassCoreGroup
TES_ROLE_NAME=GreengrassV2TokenExchangeRole
TES_ROLE_ALIAS_NAME=GreengrassCoreTokenExchangeRoleAlias
COMPONENT_DEFAULT_USER=ggc_user:ggc_group
Docker で Greengrass Core 起動
以下の内容で docker-compose.yml
を作成してください。
詳細については、公式ドキュメントをご参照ください。
version: '3.7'
services:
greengrass:
init: true
container_name: aws-iot-greengrass
image: amazon/aws-iot-greengrass:latest
volumes:
- ./greengrass-v2-credentials:/root/.aws/:ro
- ../components:/root/components
env_file: .env
ports:
- '8883:8883'
次のコマンドでコンテナを起動してください。
$ docker-compose up -d
$ docker-compose logs -f greengrass
...
aws-iot-greengrass | Launching Nucleus...
aws-iot-greengrass | Launched Nucleus successfully.
AWS 提供コンポーネントデプロイ
AWS 提供コンポーネントを Docker コンテナにデプロイしてください。
Greengrass CLI
コンポーネントをローカルにデプロイするには、 Greengrass CLI コンポーネント (aws.greengrass.Cli
) をインストールしてください。
We recommend that you use this component in only development environments, not production environments. This component provides access to information and operations that you typically won’t need in a production environment. Follow the principle of least privilege by deploying this component to only core devices where you need it.
インストール後、 /greengrass/v2/bin
に配置されます。
$ docker-compose exec greengrass bash
$ cd /greengrass/v2
$ ls bin
greengrass-cli greengrass-cli.cmd
Token Exchange Service
Greengrass カスタムコンポーネントは、 Token Exchange Service コンポーネント (aws.greengrass.TokenExchangeService
) を使用して AWS と通信します。
これは、 AWS IoT 認証プロバイダーに接続するローカルサーバーとして ECS コンテナインスタンスを実行し、 Token Exchange Role Alias を使用して AWS IoT に接続します。
カスタムコンポーネントが AWS SDK クライアントを作成するとき、クライアントは一時クレデンシャルを取得するためにローカルサーバーを使用します。
Greengrass core devices use X.509 certificates to connect to AWS IoT Core using TLS mutual authentication protocols. These certificates let devices interact with AWS IoT without AWS credentials, which typically comprise an access key ID and a secret access key.
AWS IoT Greengrass コンソールからデプロイ
AWS IoT Greengrass コンソールから AWS 提供コンポーネントをデプロイできます。
aws.greengrass.Nucleus
) も明示的にデプロイしてください。 デプロイ後、 /greengrass/v2/logs/greengrass.log
に次のレコードが記録されているはずです。
[INFO] (Thread-4) com.aws.greengrass.deployment.IotJobsHelper: Job status update was accepted. {Status=SUCCEEDED, ThingName=MyGreengrassCore, JobId=}
[INFO] (pool-2-thread-11) com.aws.greengrass.status.FleetStatusService: fss-status-update-published. Status update published to FSS. {trigger=THING_GROUP_DEPLOYMENT, serviceName=FleetStatusService,
[INFO] (pool-2-thread-11) com.aws.greengrass.deployment.DeploymentDirectoryManager: Persist link to last deployment. {link=/greengrass/v2/deployments/previous-success}
[INFO] (Thread-4) com.aws.greengrass.deployment.IotJobsHelper: Received empty jobs in notification . {ThingName=MyGreengrassCore}
Token Exchange Role
Python スクリプトが AWS IoT Core にメッセージをパブリッシュするため、 GreengrassV2TokenExchangeRole
に以下の IAM ポリシーをアタッチしてください。
保存する前に <AWS_ACCOUNT_ID>
をご自身の AWS アカウント ID で置き換えてください。
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "iot:Connect",
"Resource": "*"
},
{
"Effect": "Allow",
"Action": "iot:Publish",
"Resource": "arn:aws:iot:*:<AWS_ACCOUNT_ID>:topic//mqtt-publisher*"
}
]
}
次のコマンドでポリシーをアタッチしてください。
$ aws iam put-role-policy \
--role-name GreengrassV2TokenExchangeRole \
--policy-name IoTPolicy \
--policy-document file://policy.json
ローカルでコンポーネントデプロイ
カスタムコンポーネントをローカルでデプロイするには、 Docker コンテナ内で greengrass-cli deployment create
を実行してください。
$ cd /greengrass/v2
$ bin/greengrass-cli deployment create \
--recipeDir /root/components/mqtt_publisher/greengrass-build/recipes \
--artifactDir /root/components/mqtt_publisher/greengrass-build/artifacts \
--merge "com.example.MqttPublisher=0.0.1"
...
Local deployment submitted! Deployment Id: <DEPLOYMENT_ID>
greengrass-cli deployment status
を実行してデプロイメントのステータスを確認してください。
$ bin/greengrass-cli deployment status -i <DEPLOYMENT_ID>
...
INFO: Connection established with event stream RPC server
<DEPLOYMENT_ID>: SUCCEEDED
/greengrass/v2/logs/com.example.MqttPublisher.log
に次のレコードが記録されているはずです。
$ cd /greengrass/v2/logs
$ tail -f com.example.MqttPublisher.log
...
[INFO] (Copier) com.example.MqttPublisher: stdout. Message was sent successfully: {'value': 31, 'datetime': '2023-02-27 12:31:35'}. {scriptName=services.com.example.MqttPublisher.lifecycle.Run, serviceName=com.example.MqttPublisher, currentState=RUNNING}
AWS IoT テストクライアントでテスト
MQTT テストクライアントを使用して、 Topic filter
フィールドに /#
または /mqtt-publisher
を入力し、 Subscribe
ボタンをクリックしてください。
カスタムコンポーネントから AWS IoT Core に送信されたメッセージが表示されるはずです。
まとめ
AWS IoT Greengrass の Docker イメージを利用することで、Greengrass コンポーネントを手軽に開発できるようになります。
この投稿が、お役に立てば幸いです。