🐟
GreengrassV2のコンポーネントとしてLambda関数をエッジデバイスにデプロイするためシェルスクリプト
エッジデバイス上のプログラムをLambda関数(Node.js)+GreengrassV2で作っています。
実機での動作確認の際、Lambda 関数をデプロイして、Greengrassのコンポーネントを設定して、デプロイを設定していますが、この一連の作業が非常に面倒なのでシェルスクリプトを作成しました。
経緯
- Lambda関数はServerlessFramework(v2)で開発
- GreengrassのコンポーネントのソースにLambda関数を使用する際の諸々の設定をコンソールから実施している
- Lambda関数のバージョンを明示したりSubscribeしたいIoTCoreのトピックを書いたり、環境変数書いたり、、、、
- CLIで設定できるので自動化したい
コンソールでの設定方法
CLIでの設定方法
Before/After
Before
- ServerlessFrameworkでデプロイ
sls deploy ...
- IoTCoreのコンソールに移動
- コンソールからGreengrassのコンポーネントを設定
- Lambda関数のバージョンを指定
- コンポーネントのバージョンを更新
- Lambda関数のEventとしてSubscribeしたいIoTCoreのトピックを指定
- 環境変数設定
- デプロイの設定
- 数回ポチポチするだけ
After
- スクリプト実行
sh ./scripts/deploy.sh
作ったもの
Lambda関数をデプロイしてバージョンを取得してコンポーネントに設定するだけのスクリプトを作りました。
以前書いた記事をLambda関数向けにアレンジしただけです。
フォルダ構成
scripts
|- template
| |- component_template.json
| |- deployment_template.json
|- deployment.sh
特定のトピックをSubscribeしてメッセージをEventとして受け取るLambda関数をコンポーネント化する例
template/component.json
{
"lambdaFunction":{
"lambdaArn": "LambdaFunctionのARN:$LAMBDA_LATEST_VERSION",
"componentName": "カスタムコンポーネント名",
"componentVersion": "$CUSTOM_COMPONENT_VERSION",
"componentDependencies": {
"aws.greengrass.LambdaLauncher": {
"versionRequirement": ">=2.0.0 <3.0.0",
"dependencyType": "HARD"
},
"aws.greengrass.TokenExchangeService": {
"versionRequirement": ">=2.0.0 <3.0.0",
"dependencyType": "HARD"
},
"aws.greengrass.LambdaRuntimes": {
"versionRequirement": ">=2.0.0 <3.0.0",
"dependencyType": "SOFT"
}
},
"componentLambdaParameters": {
"eventSources": [
{
"topic": "LambdaのEventとしてSubscribeしたいトピック、ワイルドカード(#)も使用可能",
"type": "IOT_CORE"
}
],
"maxQueueSize": 1000,
"maxInstancesCount": 100,
"maxIdleTimeInSeconds": 60,
"timeoutInSeconds": 3,
"statusTimeoutInSeconds": 60,
"pinned": true,
"inputPayloadEncodingType": "json",
"environmentVariables": {
"STAGE": "$STAGE_NAME",
"ENV1": "$ENV1",
"ENV2": "$ENV2"
},
"linuxProcessParams": {
"isolationMode": "NoContainer",
"containerParams": {}
}
}
}
}
templates/deployment.json
{
"targetArn": "arn:aws:iot:ap-northeast-1:$ACCOUNT_ID:thinggroup/デプロイ対象のターゲットグループ",
"deploymentName": "デプロイ設定名",
"components": {
"aws.greengrass.Cli": {
"componentVersion": "2.7.0"
},
"aws.greengrass.LegacySubscriptionRouter": {
"componentVersion": "2.1.6",
"configurationUpdate": {
"merge": "{\"subscriptions\":{\"設定名(Lambda関数名と同じものを設定しています)\":{\"id\":\"識別子(Lambda関数名と同じものを設定しています)\",\"source\":\"component:Lambda関数名\",\"subject\":\"#\",\"target\":\"cloud\"}}}"
},
"runWith": {}
},
"aws.greengrass.Nucleus": {
"componentVersion": "2.7.0",
"runWith": {}
},
"カスタムコンポーネント名": {
"componentVersion": "$CUSTOM_COMPONENT_VERSION",
"runWith": {}
}
},
"deploymentPolicies": {
"failureHandlingPolicy": "DO_NOTHING",
"componentUpdatePolicy": {
"timeoutInSeconds": 60,
"action": "NOTIFY_COMPONENTS"
},
"configurationValidationPolicy": {
"timeoutInSeconds": 60
}
},
"iotJobConfiguration": {}
}
deploy.sh
#!/bin/bash
echo "StageName(dev/stg) : "
read stage_name
echo "start lambda function deployment"
./node_modules/.bin/sls deploy --stage $stage_name --aws-profile AWSCLIで使用するプロファイル名
env1=`grep "ENV1=" ./scripts/.secrets | awk -F "=" '{print$2}'`
env2=`grep "ENV2=" ./scripts/.secrets | awk -F "=" '{print$2}'`
account_id=`aws sts get-caller-identity --profile AWSCLIで使用するプロファイル名 --query "Account" |sed -e 's/"//g'`
# component version: $LambdaLtestVersion.0.0
lambda_latest_version=`aws lambda list-versions-by-function --function-name 関数名 --query 'Versions[-1].Version' --profile AWSCLIで使用するプロファイル名| sed -e 's/"//g'`
custom_component_version=$lambda_latest_version.0.0
echo "create component.json"
cat ./scripts/templates/component_template.json | sed -e "s/\$ENV1/$env1/g"| sed -e "s/\$ENV2/$env2/g"| sed -e "s/\$CUSTOM_COMPONENT_VERSION/$custom_component_version/g" | sed -e "s/\$LAMBDA_LATEST_VERSION/$lambda_latest_version/g" | sed -e "s/\$STAGE_NAME/$stage_name/g" | sed -e "s/\$ACCOUNT_ID/$account_id/g" > ./scripts/component.json
echo "create deployment.json"
cat ./scripts/templates/deployment_template.json | sed -e "s/\$CUSTOM_COMPONENT_VERSION/$custom_component_version/g" | sed -e "s/\$STAGE_NAME/$stage_name/g" | sed -e "s/\$ACCOUNT_ID/$account_id/g" > ./scripts/deployment.json
echo "start create greengrass component"
aws greengrassv2 create-component-version --cli-input-json fileb://scripts/component.json --profile AWSCLIで使用するプロファイル名
echo "start create greengrass deployment"
aws greengrassv2 create-deployment --cli-input-json fileb://scripts/deployment.json --profile AWSCLIで使用するプロファイル名
- デプロイ時に設定が必要な値はスクリプト実行時に取得、置換しています。
- 値を公開したくないもの(環境変数等、↑の場合は
ENV1
、ENV2
)は.secretに書いて.gitignoreさせています。
grep "ENV2=" ./scripts/.secrets | awk -F "=" '{print$2}'
- AWSのアカウントIDはAWS CLIから取得できます。AWSCLIで使用するプロファイル名も.secretから取得しても良いかもです。
aws sts get-caller-identity --profile AWSCLIで使用するプロファイル名 --query "Account" |sed -e 's/"//g'
- Lambdaの最新バージョンもAWS CLIから取得できます。
aws lambda list-versions-by-function --function-name 関数名 --query 'Versions[-1].Version' --profile AWSCLIで使用するプロファイル名| sed -e 's/"//g'
- 一時ファイルは削除したほうが良いかもですね。一応、.gitignoreには書いています。
deployment.json
component.json
- エラーハンドリングしていません。ちゃんと書きましょう。
.secrets
ENV1=xxxxx
ENV2=yyyyy
.gitignore(抜粋)
.secrets
component.json
deployment.json
実機での確認が楽になりました。
以上です。
Discussion