【AWS IoT Greengrass V2】パブリックイメージの Docker コンテナをカスタムコンポーネントとして AWS からデプロイしてみる

今回は、AWS IoT Greengrass V2 で Docker コンテナを AWS 側からデプロイしてみました。
2021.10.09

前回は Docker コンテナをデバイス上でローカルからデプロイしてみました。

今回は同じコンテナを AWS 側からデプロイしてみたいと思います。前回同様、具体的な手順は下記のドキュメントを参考にしています。

注意点としては、上記ドキュメントのまま実施するとデプロイがエラーになる点です。

ドキュメントでは「ローカルデプロイ」→「AWSからデプロイ」という手順を想定しているようですが、ローカルでデプロイする前にアーティファクトやレシピを保存するディレクトリを作成する手順が抜けているので、そのまま実行するとエラーになります。
もしエラーになるようでしたら、前回の記事 を参考にしてみていただければと思います。

本記事で検証するデプロイパターン

デプロイパターンとして本記事で検証するのは下記の「2. パブリックイメージから Raspberry Pi に Docker コンテナを AWS からデプロイ」になります。その他のパターンについてはリンクから参照してください。

  1. Docker Hub のパブリックイメージから Raspberry Pi に Docker コンテナをローカルデプロイ
  2. Docker Hub のパブリックイメージから Raspberry Pi に Docker コンテナを AWS からデプロイ(本記事)
  3. Amazon ECR のプライベートイメージから Raspberry Pi に Docker コンテナをローカルデプロイ(予定)
  4. Amazon ECR のプライベートイメージから Raspberry Pi に Docker コンテナをAWSからデプロイ(予定)

検証内容の構成イメージ

前回とほとんど同じで、Docker Hub にあるPostgreSQL のパブリックイメージから Docker コンテナをデプロイします。
違うのはデプロイ指示を出す場所です。前回はコマンドを使ってローカルでデプロイしましたが、今回はデバイスにログインせずに AWS 側からデプロイを行います。

00-public-image-aws-deploy

前提

前回の記事と同じになりますが、再掲します。

既存イメージの削除

何もない状態から試したいので、前回の記事で動作確認に使ったコンテナやイメージがあれば消して起きましょう。

コンテナを削除する場合は、docker rmで消します。

$ docker rm [CONTAINER ID]

イメージの削除はdocker rmiで消します。

$ docker rmi [IMAGE ID]

Docker 実行ユーザーの設定変更

Greengrass 経由での Docker 実行ユーザは、デフォルトで ggc_userになるので、dockerグループにggc_userを追加しておきます。

$ sudo usermod -aG docker ggc_user

レシピとアーティファクト用のディレクトリ削除

削除する必要はありませんが、ローカルデプロイ用のレシピなどがデバイス上にも存在すると、ややこしいので一旦消しておきます。
(存在していても参照されないだけですが…)

下記の通り何もない状態にしました。
(私の環境では他に動かしているコンポーネントがあるので、実際には他のコンポーネントのアーティファクトなどが存在します。)

.
├── artifacts
└── recipes

IAM の権限追加

今回新たに追加となる前提条件です。
AWS 側からデプロイする場合、アーティファクトであるdocker-compose.yamlを S3 からダウンロードする必要があるので、Greengrass の IAM Role に権限が追加で必要となります。

まず下記のような IAM ポリシーを作成します。今回は AWS CLI で実行したので下記ポリシーで component-artifact-policy.jsonというファイルを PC 上に作成します。

{
  "Version": "2012-10-17",
  "Statement": [
  {
    "Effect": "Allow",
    "Action": [
      "s3:GetObject"
    ],
    "Resource": [
      "arn:aws:s3:::[Your-S3-Bucket]/*"
    ]
   }
  ]
}

次にこのポリシーをMyGreengrassV2ComponentArtifactPolicyという名前で作成します。(好きな名前にしてください)

$ aws iam create-policy \
  --policy-name MyGreengrassV2ComponentArtifactPolicy \
  --policy-document file://component-artifact-policy.json

IAM ポリシーが作成できたら、Greengrass の IAM Role である GreengrassV2TokenExchangeRole にアタッチします。

$ aws iam attach-role-policy \
  --role-name GreengrassV2TokenExchangeRole \
  --policy-arn arn:aws:iam::xxxxxxxxxxxx:policy/MyGreengrassV2ComponentArtifactPolicy

docker-compose.yaml の作成と S3 へ保存

前回と同じ内容でdocker-compose.yamlを作成します。( PC 上の適当なところに一旦保存します)

version: '3'

services:
  db:
    image: postgres:latest
    environment:
        POSTGRES_USER: postgres
        POSTGRES_PASSWORD: password
    ports:
      - 5432:5432

今回は、アーティファクトをS3からダウンロードするので、作成したdocker-compose.yamlを適当な S3 バケットに保存します。
今回は 下記の通りs3://[Your-S3-Bucket]/docker-component/docker-compose.yamlというパスで保存しました。

04-s3-object-path

注意点としては、アーティファクトであるdocker-compose.yamlを S3 に保存するパスの構成です。

python などで作ったカスタムコンポーネントを AWS からデプロイするときは、S3 上のアーティファクトの URI の指定としてローカルデプロイする場合と同様に、下記のような階層構成にする必要があります。

Artifacts:
  - Uri: s3://[YOUR-S3-BUCKET]/artifacts/com.example.MyComponent/1.0.0/sample.py

しかしDockerコンテナの場合、実体として動くアーティファクトはコンテナレジストリからダウンロードされるので、docker-compose.yaml の保存場所としては上記の構成である必要はなく、今回設定したような下記のようなフォルダ構成でも問題ありません。

Artifacts:
  - Uri: s3://[YOUR-S3-Bucket]/docker-component/docker-compose.yaml

ただ、他のコンポーネントと同じフォルダ構成にした方が管理しやすい場面もあるかと思いますので、利用する際は一度検討していただくのがいいかと思います。

コンポーネントの作成

次に、AWS コンソールからコンポーネントを新規に作成します。

01-make-docker-component

次の画面でレシピを YAML として入力します。

02-make-docker-component-recipe

レシピの内容は下記になります。前回と同様に「Docker application manager」というパブリックコンポーネントが依存関係で必要なので、ComponentDependenciesとして記載しています。

RecipeFormatVersion: '2020-01-25'
ComponentName: com.example.MyDockerComposeComponent
ComponentVersion: '1.0.0'
ComponentDescription: 'A component that uses Docker Compose to run images from Docker Hub.'
ComponentPublisher: Amazon
ComponentDependencies:
  aws.greengrass.DockerApplicationManager:
    VersionRequirement: ~2.0.0
Manifests:
  - Platform:
      os: all
    Lifecycle:
      Run: docker-compose -f {artifacts:path}/docker-compose.yaml up
    Artifacts:
      - Uri: docker:postgres:latest
      - Uri: s3://[YOUR-S3-BUCKET]/docker-component/docker-compose.yaml

また、上記レシピのアーティファクトに先程 S3 に保存したdocker-compose.yamlを指定しています。

コンポーネントのデプロイ

コンポーネントが作成できればデプロイします。

03-deploy-docker-component

この後は、特に特別な手順はないので割愛します。

動作確認

デプロイが正常に終了したらデバイス上で動作確認します。PostgreSQL のコンテナが起動しています。

$ sudo docker ps
CONTAINER ID   IMAGE             COMMAND                  CREATED         STATUS         PORTS                                       NAMES
42329d89927b   postgres:latest   "docker-entrypoint.s…"   7 minutes ago   Up 7 minutes   0.0.0.0:5432->5432/tcp, :::5432->5432/tcp   100_db_1


Raspberry Pi 上でデータベースに接続もできました。


$ psql -h localhost -U postgres

Password for user postgres: 
psql (11.12 (Raspbian 11.12-0+deb10u1), server 13.4 (Debian 13.4-1.pgdg100+1))
WARNING: psql major version 11, server major version 13.
         Some psql features might not work.
Type "help" for help.

postgres=#

ローカルでデプロイした場合と同様に、AWS 側からコンポーネントを削除するとコンテナも停止しました。

$ sudo docker ps -a
CONTAINER ID   IMAGE             COMMAND                  CREATED          STATUS                      PORTS     NAMES
42329d89927b   postgres:latest   "docker-entrypoint.s…"   15 minutes ago   Exited (0) 15 seconds ago             100_db_1

最後に

今回は、AWS 側からコンテナのコンポーネントをデプロイしてみました。
主な違いは下記のような点でしょうか。

  • デバイスのローカル上にアーティファクトやレシピを準備する必要がない
  • レシピにアーティファクトの URI を追加
  • IAM 権限の追加

次回は Amazon ECR を使ってプライベートイメージの運用を想定した検証を行ってみたいと思います。