greengrassでエッジデバイスにDockerコンテナアプリケーションをデプロイする
やりたいこと
エッジデバイスにWebアプリケーションをデプロイしたい
できたこと
greengrass でDockerfile で定義したコンテナをデプロイして、デバイス上で80番ポートにHTTPアクセスして"Hello World"がレスポンスされることを確認
やったこと
概要
- 動作確認用のdockerイメージを用意する
- dockerイメージをECRに保存する
- 動作確認環境の用意(greengrass、dockerインストール)
- カスタムコンポーネントの作成、デプロイ
動作確認用のdockerイメージを用意する
今回は、FastAPIでHello World するだけのdockerイメージを用意しました。
参考:https://fastapi.tiangolo.com/ja/deployment/docker/
RaspberryPiを私用する場合は、dockerイメージを作成するdocker build
時に --platform linux/arm/v7
を指定します。
dockerイメージをECRにプッシュする
参考:https://docs.aws.amazon.com/ja_jp/AmazonECR/latest/userguide/docker-push-ecr-image.html
ECRリポジトリは事前に作成しておきます。
ECRリポジトリへのログイン、イメージにタグ付け、リポジトリにPUSHします。
aws ecr get-login-password --region ap-northeast-1 | docker login --username AWS --password-stdin {accountId}.dkr.ecr.ap-northeast-1.amazonaws.com
docker tag myimage:latest {accountId}.dkr.ecr.ap-northeast-1.amazonaws.com/greengrass-test:latest
docker push {accountId}.dkr.ecr.ap-northeast-1.amazonaws.com/greengrass-test:latest
動作確認環境を用意する
手元にRaspberryPiがなかったので、EC2のLinux(Ubuntu)で動作確認しました。
- EC2にUbuntuのインスタンスを構築(手順割愛)
- greengrass(手順割愛 ※)
- dockerのインストール(手順割愛)
- greengrassユーザがdockerを実行するための権限設定
※ 参考:https://docs.aws.amazon.com/ja_jp/greengrass/v2/developerguide/getting-started.html
- greengrassユーザがdockerを実行するための権限設定
Docker コンテナコンポーネントを実行するシステムユーザーには、ルート権限または管理者権限が必要です。権限がない場合は、ルート権限または管理者権限を持たないユーザーとして実行されるように Docker を構成する必要があります。
参考:https://docs.aws.amazon.com/ja_jp/greengrass/v2/developerguide/run-greengrass-docker.html
greengrassユーザにdocker実行権限を付与します。
sudo usermod -aG docker ggc_user
カスタムコンポーネントの作成、デプロイ
- greengrassによるデバイスへのソフトウェアデプロイには、カスタムコンポーネント(デバイスにデプロイするソフトウェアモジュール)の作成とコンポーネントをデプロイするための設定が必要です
- また、ECRからdockerイメージを取得するために、ECRへの権限設定が必要です
カスタムコンポーネントの作成
参考:https://docs.aws.amazon.com/ja_jp/greengrass/v2/developerguide/create-components.html
デプロイの作成
参考:https://docs.aws.amazon.com/ja_jp/greengrass/v2/developerguide/manage-deployments.html
ECRの権限追加
参考:https://docs.aws.amazon.com/ja_jp/greengrass/v2/developerguide/run-docker-container.html#run-docker-container-requirements、https://docs.aws.amazon.com/ja_jp/greengrass/v2/developerguide/device-service-role.html
カスタムコンポーネントを定義する
カスタムコンポーネントの定義として以下のJSONを使用します。
{
"RecipeFormatVersion": "2020-01-25",
"ComponentName": "com.example.MyPrivateDockerComponent",
"ComponentVersion": "1.0.0",
"ComponentDescription": "A component that runs a Docker container from a private Amazon ECR image.",
"ComponentPublisher": "Amazon",
"ComponentDependencies": {
"aws.greengrass.DockerApplicationManager": {
"VersionRequirement": "~2.0.0"
},
"aws.greengrass.TokenExchangeService": {
"VersionRequirement": "~2.0.0"
}
},
"Manifests": [
{
"Platform": {
"os": "all"
},
"Lifecycle": {
"Run": "docker run -p 80:80 {accountId}.dkr.ecr.ap-northeast-1.amazonaws.com/greengrass-test:latest"
},
"Artifacts": [
{
"URI": "docker:{accountId}.dkr.ecr.ap-northeast-1.amazonaws.com/greengrass-test:latest"
}
]
}
]
}
ポイントとしては以下の2点です。
- Lifecycleにdockerの起動コマンド、ArtifactsにdockerイメージのARNを指定します
- 起動コマンドに-pオプションでコンテナ上のアプリケーションにアクセスするためのポート指定します
ECRにアクセスするためのIAMロールを設定する
greengrassがECSからdockerイメージを取得するために、ECRへのアクセス権限をデバイスのロールに追加します。
IAMポリシーの作成
aws iam create-policy \
--policy-name MyGreengrassV2ComponentArtifactPolicy \
--policy-document file://component-artifact-policy.json
作成するポリシーは以下の通り
component-artifact-policy.json
{
"Version": "2012-10-17",
"Statement": [
{
"Action": [
"ecr:GetAuthorizationToken",
"ecr:BatchGetImage",
"ecr:GetDownloadUrlForLayer"
],
"Resource": [
"*"
],
"Effect": "Allow"
}
]
}
ロールの作成
aws iam attach-role-policy \
--role-name GreengrassV2TokenExchangeRole \
--policy-arn arn:aws:iam::{accountId}:policy/MyGreengrassV2ComponentArtifactPolicy
GreengrassV2TokenExchangeRole
がデバイス(IoT Core上のThing)に紐付いています
デプロイして動作確認する
コンソールからポチポチ、デプロイ実行します。
デプロイ実行後、デバイス(EC2)側でコンテナの起動確認、コンテナ上のアプリケーションが起動していることを確認できました。
コンテナの起動確認
# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
7dbd9efbe8f6 {accountId}.dkr.ecr.ap-northeast-1.amazonaws.com/greengrass-test:latest "uvicorn app.main:ap…" 5 minutes ago Up 5 minutes 80/tcp vibrant_hodgkin
→ greengrassで配布したコンテナが起動しています。
com.example.MyPrivateDockerComponent.log
2022-08-16T06:40:40.686Z [INFO] (pool-2-thread-24) com.example.MyPrivateDockerComponent: shell-runner-start. {scriptName=services.com.example.MyPrivateDockerComponent.lifecycle.Run, serviceName=com.example.MyPrivateDockerComponent, currentState=STARTING, command=["docker run {accountId}.dkr.ecr.ap-northeast-1.amazonaws.com/greengrass-test:l..."]}
2022-08-16T06:40:42.161Z [WARN] (Copier) com.example.MyPrivateDockerComponent: stderr. INFO: Started server process [1]. {scriptName=services.com.example.MyPrivateDockerComponent.lifecycle.Run, serviceName=com.example.MyPrivateDockerComponent, currentState=RUNNING}
2022-08-16T06:40:42.162Z [WARN] (Copier) com.example.MyPrivateDockerComponent: stderr. INFO: Waiting for application startup.. {scriptName=services.com.example.MyPrivateDockerComponent.lifecycle.Run, serviceName=com.example.MyPrivateDockerComponent, currentState=RUNNING}
2022-08-16T06:40:42.162Z [WARN] (Copier) com.example.MyPrivateDockerComponent: stderr. INFO: Application startup complete.. {scriptName=services.com.example.MyPrivateDockerComponent.lifecycle.Run, serviceName=com.example.MyPrivateDockerComponent, currentState=RUNNING}
2022-08-16T06:40:42.164Z [WARN] (Copier) com.example.MyPrivateDockerComponent: stderr. INFO: Uvicorn running on http://0.0.0.0:80 (Press CTRL+C to quit). {scriptName=services.com.example.MyPrivateDockerComponent.lifecycle.Run, serviceName=com.example.MyPrivateDockerComponent, currentState=RUNNING}
Uvicorn running on <http://0.0.0.0:80> (Press CTRL+C to quit).
→ 起動されていることを確認しました。
アプリケーションの動作確認
$ curl localhost
{"Hello":"World"}
→ Webアプリケーションが動作していることを確認しました。
# cd /greengrass/v2/logs
# ls -l
total 88
-rw-r--r-- 1 root root 0 Aug 15 07:23 aws.greengrass.Nucleus.log
-rw-r--r-- 1 root root 572 Aug 16 12:09 com.example.MyPrivateDockerComponent.log
-rw-r--r-- 1 root root 37103 Aug 16 07:13 greengrass.log
-rw-r--r-- 1 root root 0 Aug 15 07:23 main.log
- com.example.MyPrivateDockerComponent.log:カスタムコンポーネントのログ、コンテナのアプリケーションログが含まれます
- greengrass.log:greengrassのログ、デプロイのログ等
以上です。
Discussion