🍏

greengrassでエッジデバイスにDockerコンテナアプリケーションをデプロイする

2022/09/02に公開約6,800字

やりたいこと

エッジデバイスに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)で動作確認しました。

  1. EC2にUbuntuのインスタンスを構築(手順割愛)
  2. greengrass(手順割愛 ※)
  3. dockerのインストール(手順割愛)
  4. greengrassユーザがdockerを実行するための権限設定

※ 参考:https://docs.aws.amazon.com/ja_jp/greengrass/v2/developerguide/getting-started.html

  1. 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-requirementshttps://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のログ、デプロイのログ等

以上です。

GitHubで編集を提案

Discussion

ログインするとコメントできます