Docker 環境で Greengrass コンポーネントをビルド・デプロイする
Greengrass Core Docker イメージを使い、AWS IoT Greengrass コンポーネントをローカルで開発します。
Greengrass Core Docker イメージ を使うと、物理的なエッジデバイスを用意せずに、ローカル環境で AWS IoT Greengrass コンポーネントを開発できます。詳細は公式ドキュメントを参照してください。
この記事では、AWS IoT Core へ 1 秒ごとに MQTT メッセージをパブリッシュする Greengrass コンポーネントを構築し、Greengrass CLI でローカルの Docker コンテナへデプロイします。

この例の最後には、プロジェクトディレクトリは以下のような構成になります。
components/├── mqtt_publisher/│ ├── .gitignore│ ├── gdk-config.json│ ├── main.py│ ├── recipe.yaml│ ├── requirements.txtdocker/├── greengrass-v2-credentials/│ ├── credentials├── .env├── docker-compose.ymlカスタム Greengrass コンポーネントの開発
Greengrass Development Kit(GDK)のインストール
Greengrass Development Kit(GDK) をインストールします。
pip install gdk を実行すると、Greengrass Development Kit とは無関係のライブラリがインストールされます。
開発の開始
gdk component init を実行して、Greengrass コンポーネントを初期化します。
mkdir ./componentsgdk 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 フィールド(10 行目)の設定は不要です。
更新後の gdk-config.json の例です。
{ "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"}詳細は、GDK CLI 設定ファイルの公式ドキュメントを参照してください。
version の値に NEXT_PATCH を指定すると、greengrass-cli deployment create でコンポーネントをデプロイするときにエラーが発生します。
Python スクリプトの作成
コンポーネント用の main.py を作成します。このスクリプトは、/mqtt-publisher トピックへ 1 秒ごとに MQTT メッセージをパブリッシュします。
import jsonimport randomfrom datetime import datetimefrom 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"コンポーネントの依存関係
このスクリプトは boto3 を使って AWS IoT Core と通信します。そのため、ComponentDependencies に aws.greengrass.TokenExchangeService コンポーネントを追加します。Token Exchange Service はローカルエンドポイントを公開し、カスタムコンポーネントへ AWS の認証情報を提供します。
詳細については公式ドキュメントを参照してください。
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}- Artifacts URI(
BUCKET_NAME、COMPONENT_NAME、COMPONENT_VERSION)
コンポーネントのビルド
Greengrass Development Kit でコンポーネントをビルドするには、gdk component build を実行します。
cd components/mqtt_publishergdk 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 をセットアップし、認証情報を設定してコンポーネントをデプロイします。以降の作業は <PROJECT_ROOT>/docker ディレクトリで行います。
セキュリティ認証情報
Greengrass Core がリソースを自動的にプロビジョニングするには、AWS の認証情報が必要です。長期的な認証情報ではなく、sts get-session-token で取得した一時的な認証情報を使用します。
以下の AWS リソースがプロビジョニングされます。
- AWS IoT
- Greengrass Core デバイス
- IoT Thing
- IoT Thing グループ
- 証明書
- ポリシー(2つ)
- Token Exchange Role エイリアス
- AWS IAM
- Token Exchange ロール
- Token Exchange ロールポリシー
一時的な認証情報を生成します。
aws sts get-session-token認証情報をファイルに保存します。
mkdir ./greengrass-v2-credentialsnano ./greengrass-v2-credentials/credentialscredentials の内容の例です。
[default]aws_access_key_id = AKIAIOSFODNN7EXAMPLEaws_secret_access_key = wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEYaws_session_token = AQoEXAMPLEH4aoAH0gNCAPy...truncated...zrkuWJOgQs8IZZaIv2BXIa2R4Olgk環境変数ファイル
Greengrass Core インストーラーの環境変数を設定するため、.env ファイルを作成します。詳細は公式ドキュメントを参照してください。
.env ファイルの例です。
GGC_ROOT_PATH=/greengrass/v2AWS_REGION=ap-northeast-1PROVISION=trueTHING_NAME=MyGreengrassCoreTHING_GROUP_NAME=MyGreengrassCoreGroupTES_ROLE_NAME=GreengrassV2TokenExchangeRoleTES_ROLE_ALIAS_NAME=GreengrassCoreTokenExchangeRoleAliasCOMPONENT_DEFAULT_USER=ggc_user:ggc_groupGreengrass 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 -ddocker-compose logs -f greengrassNucleus が正常に起動したことを示すログを確認します。
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 bashcd /greengrass/v2ls binGreengrass 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.
Token Exchange Service
カスタムコンポーネントから AWS サービスを呼び出せるよう、aws.greengrass.TokenExchangeService コンポーネントをデプロイします。このサービスは、ローカルエンドポイントを介して認証情報を提供します。
https://docs.aws.amazon.com/greengrass/v2/developerguide/interact-with-aws-services.html
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}Token Exchange ロールの更新
MQTT パブリッシュを許可するため、GreengrassV2TokenExchangeRole の IAM ポリシーを更新します。
{ "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/v2bin/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/logstail -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 Test Client でのテスト
AWS IoT コンソールの MQTT テストクライアントで、/mqtt-publisher トピックにパブリッシュされたメッセージを確認します。
- MQTT test client を開きます。
Topic filterに/#または/mqtt-publisherを入力します。Subscribeをクリックします。
カスタムコンポーネントからパブリッシュされたメッセージが表示されるはずです。

まとめ
GDK と Greengrass Core Docker イメージを使うと、物理的なエッジデバイスを用意せずに MQTT パブリッシュ用コンポーネントを構築し、AWS IoT Core でメッセージを確認できます。
GDK によるビルド、ローカルでの greengrass-cli deployment create、コンポーネントログの確認を短いサイクルで繰り返せます。同じレシピとアーティファクトの構成を、後から物理コアデバイスでも利用できます。
Greengrass CLI コンポーネントは本番デバイスへデプロイしないでください。ローカルデプロイやデバッグなど、開発環境向けの操作を公開するコンポーネントです。
Related posts
SiteWise Edge Gateway で OPC UA データを Kinesis にストリーミングする
SiteWise Edge Gateway とカスタムの Greengrass コンポーネントを使い、OPC UA テレメトリを Kinesis Data Streams へ橋渡しします。
AWS IoT Core における Kinesis Firehose のレコード区切り設定
IoT Core のトピックルールにある Firehose アクションで区切り文字を設定し、S3 にレコードを改行区切りで格納する方法を解説します。
AWS IoT のペイロード値で Kinesis レコードをパーティショニングする
IoT トピックのペイロードに含まれる顧客 ID を Kinesis のパーティションキーとして使い、顧客ごとのレコード順序を維持する方法を解説します。
Cognito User Pools と OIDC で Slack サインインを実装する
Cognito user pool を OIDC 経由で Slack と連携させ、"Sign in with Slack" を Amplify で Next.js アプリケーションに組み込みます。
Lambda Web Adapter で FastAPI を AWS Lambda にデプロイする
FastAPI で書いた API バックエンドをコンテナ化し、Lambda Web Adapter と AWS CDK を使って単一の Lambda 関数へデプロイします。
