Docker での Greengrass コンポーネント開発: ステップバイステップガイド
はじめに
この記事では、AWS IoT Greengrass Core の Docker イメージ を使用して、ローカル環境での Greengrass コンポーネント開発方法を説明します。
概要
この投稿では、MQTT を通じて毎秒メッセージを AWS IoT Core に送信する 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 カスタムコンポーネントの開発
Greengrass Development Kit (GDK) のインストール
Greengrass Development Kit (GDK) をインストールします。
pip install -U git+https://github.com/aws-greengrass/aws-greengrass-gdk-cli.git@v1.1.0
pip install gdk
を実行すると、Greengrass Development Kit とは無関係なライブラリがインストールされます。
開発の開始
gdk component init
を実行して Greengrass コンポーネントを初期化します。
まず、components
ディレクトリを作成し、コンポーネントを初期化します。
mkdir ./components
gdk component init \
--language python \
--template HelloWorld \
--name components/mqtt_publisher
このコマンドにより、次のような基本的なコンポーネント構造が生成されます。
./
|-- components/
| |-- mqtt_publisher/
| |-- src/
| | |-- greeter.py
| |-- tests/
| | |-- test_greeter.py
| |-- .gitignore
| |-- gdk-config.json
| |-- main.py
| |-- README.md
| |-- recipe.yaml
src
および tests
ディレクトリは使用しません。
コンポーネントメタデータの設定
gdk-config.json
ファイルを更新してコンポーネントのメタデータを設定します。コンポーネントを gdk component publish
を使用して S3 バケットにパブリッシュしない場合、publish.bucket
フィールドを設定する必要はありません。
以下は、更新された gdk-config.json
の例です。
{
"component": {
"com.example.MqttPublisher": {
"author": "wasabee.io",
"version": "0.0.1",
"build": {
"build_system": "zip"
},
"publish": {
"bucket": "<PLACEHOLDER_BUCKET>",
"region": "ap-northeast-1"
}
}
},
"gdk_version": "1.0.0"
}
詳しい情報は、GDK CLI 構成ファイルに関する公式ドキュメント をご参照ください。
version
の値として NEXT_PATCH
を使用しないでください。greengrass-cli deployment create
を使用してコンポーネントをデプロイする際にエラーが発生します。
この設定で、カスタム Greengrass コンポーネントの実装を開始する準備が整いました。
Python スクリプト
コンポーネントの main.py
スクリプトを作成します。このスクリプトは、/mqtt-publisher
トピックに毎秒 MQTT メッセージをパブリッシュします。
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
ファイルを作成して、コンポーネントに必要な依存関係を指定します。
boto3==1.26.65
これらの依存関係は、recipe.yaml
に定義されたコンポーネントのインストールプロセス中にインストールされます。
コンポーネントレシピ
コンポーネントのレシピを定義するために、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"
コンポーネント依存関係
このスクリプトは boto3 ライブラリに依存して AWS IoT Core とやり取りします。ComponentDependencies
セクションに aws.greengrass.TokenExchangeService
コンポーネントを依存関係として指定します。
- 目的: AWS サービスとやり取りするための資格情報を提供。
- 主な機能:
TokenExchangeService
は、AWS 資格情報を提供するローカルサーバーを実行します。
詳しくは Greengrass ドキュメント をご参照ください。
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.
ライフサイクルフック
Lifecycle
セクションでは、コンポーネントのインストールおよび実行中に実行するコマンドを指定します。
- Install:
requirements.txt
にリストされた Python ライブラリをインストールします。 - Run: コンポーネントが起動するときに
main.py
スクリプトを実行します。
レシピのプレースホルダー
レシピ内のプレースホルダー(例:{COMPONENT_NAME}
)は、ビルドプロセス中に gdk-config.json
の値に置き換えられます。これらのプレースホルダーには以下が含まれます。
{COMPONENT_NAME}
{COMPONENT_VERSION}
{COMPONENT_AUTHOR}
- アーティファクト URI コンポーネント(例:
BUCKET_NAME
、COMPONENT_NAME
、COMPONENT_VERSION
)
コンポーネントのビルド
Greengrass Development Kit を使用してコンポーネントをビルドします。
cd components/mqtt_publisher
gdk component build
ビルド後、アーティファクトは greengrass-build
ディレクトリに配置されます。ローカルの Docker コンテナへのデプロイでは gdk component publish
を実行する必要はありません。
gdk-config.json
内の version
値として NEXT_PATCH
を使用すると、bin/greengrass-cli deployment create
実行時にデプロイメントが失敗します。
これで、Docker 上で動作する Greengrass Core にコンポーネントをデプロイする準備が整いました。
Docker 上の Greengrass Core
このセクションでは、Docker コンテナ内で Greengrass Core をセットアップし、資格情報を構成し、コンポーネントをデプロイする方法を説明します。
以下の作業は、<PROJECT_ROOT>/docker
ディレクトリで実行します。
セキュリティ資格情報
Greengrass Core では、リソースの自動プロビジョニングのために AWS セキュリティ資格情報が必要です。永続的な資格情報も使用可能ですが、セキュリティ強化のため sts get-session-token
による 一時的な資格情報 の使用を推奨します。
以下の AWS リソースがプロビジョニングされます。
- AWS IoT
- Greengrass Core デバイス
- IoT Thing
- IoT Thing グループ
- 証明書
- ポリシー(2 つ)
- トークン交換ロールエイリアス
- AWS IAM
- トークン交換ロール
- トークン交換ロールポリシー
一時的な資格情報を生成します。
aws sts get-session-token
資格情報をファイルに保存します。
mkdir ./greengrass-v2-credentials
nano ./greengrass-v2-credentials/credentials
credentials
の例:
[default]
aws_access_key_id = AKIAIOSFODNN7EXAMPLE
aws_secret_access_key = wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
aws_session_token = AQoEXAMPLEH4aoAH0gNCAPy...truncated...zrkuWJOgQs8IZZaIv2BXIa2R4Olgk
環境ファイル
Greengrass Core インストーラの環境変数を構成するために .env
ファイルを作成します。詳細については、公式ドキュメント をご参照ください。
.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 で Greengrass Core を実行するために、docker-compose.yml
ファイルを作成します。詳細については、ドキュメント をご参照ください。
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
次のようなログが表示され、Nucleus が正常に起動したことを確認できます:
aws-iot-greengrass | Launching Nucleus...
aws-iot-greengrass | Launched Nucleus successfully.
AWS 提供のコンポーネントをデプロイする
Greengrass CLI
ローカルデプロイメント用に Greengrass CLI コンポーネント (aws.greengrass.Cli
) をインストールします。インストール後は /greengrass/v2/bin
に配置されます。
docker-compose exec greengrass bash
cd /greengrass/v2
ls bin
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.
トークン交換サービス
カスタムコンポーネントが AWS とやり取りできるようにするために、aws.greengrass.TokenExchangeService
コンポーネントをデプロイします。このサービスは、一時的な資格情報をローカルサーバーを通じて提供します。
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 コンソールからのデプロイ
Greengrass Nucleus を含む AWS 提供のコンポーネントを AWS IoT Greengrass コンソールを通じてデプロイします。
デプロイが完了すると、/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}
トークン交換ロールの更新
GreengrassV2TokenExchangeRole
IAM ポリシーを更新し、MQTT パブリッシングの権限を付与します:
{
"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 を使用して、カスタムコンポーネントをデプロイします: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"
デプロイメントステータスを確認するには、greengrass-cli deployment status
を使用します:
bin/greengrass-cli deployment status -i <DEPLOYMENT_ID>
以下のようなレスポンスが表示されます:
INFO: Connection established with event stream RPC server
<DEPLOYMENT_ID>: SUCCEEDED
ログを監視してコンポーネントが実行中であることを確認します:
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 テストクライアントでのテスト
AWS IoT コンソールの MQTT テストクライアントを使用して、メッセージが /mqtt-publisher
トピックにパブリッシュされていることを確認します。
- MQTT テストクライアント に移動します。
Topic filter
フィールドに/#
または/mqtt-publisher
を入力します。- Subscribe ボタンをクリックします。
カスタムコンポーネントからパブリッシュされたメッセージが表示されます。
まとめ
AWS IoT Greengrass Docker イメージを活用することで、コンポーネントのローカル開発とテストをより効率的かつ柔軟に行えます。この投稿が IoT アプリケーション開発プロセスの効率化に寄与できれば幸いです。
Happy Coding! 🚀