search
LoginSignup
3
Help us understand the problem. What are the problem?

More than 1 year has passed since last update.

AWS Containers Advent Calendar 2020 Day 23

posted at

updated at

AWS IoT Greengrass 2.0 で Docker コンテナを動かしてみた

こちらは AWS Containers Advent Calendar 2020 の23日目の記事です。

re:Invent 2020 で AWS IoT Greengrass 2.0 が発表されました。
v1 がそうであったように、v2 でも Docker コンテナ の動作がサポートされています。

さっそくやってみました。

やったこと

  • EC2 インスタンス上に AWS IoT Greengrass 2.0 をインストールする
  • Docker コンテナを動かす(ここでは nginx コンテナを動かしました)

AWS IoT Greengrass 2.0 のインストール on EC2

手元にラズパイはあるのですが、別の用途で使っているため、今回は EC2 インスタンスをたてて、そのうえで検証しました。
(t2.micro, x86, Amazon Linux2 の EC2 インスタンスを使っていますが、EC2インスタンスの作成手順は省略しています)

EC2 へ必要なソフトウェアのインストール

Core Device の作成

AWS IoT の管理コンソールで、Core device の作成を行います(画像右側のオレンジボタンです)
image.png

Core Device名 と Things group名を入力します。
ここでは、それぞれ greengrass-v2-qiita-coregreengrass-v2-qiita-group としています。
image.png

ページをスクロールするとインストール手順が表示されるため、1つ1つやって行きましょう。

image.png

Step0: 追加手順

私はこれはやらずに次に進んだため、ハマってしまいました。

sudo visudo で以下のように root の設定を少しいじります。

root ALL=(ALL) ALL
↓
root ALL=(ALL:ALL) ALL

Step1: Install Java on the device

こちらを参考に Java 8(Corretto 8) を入れます。

sudo amazon-linux-extras enable corretto8
sudo yum install -y java-1.8.0-amazon-corretto

Step2: Configure AWS credentials on the device

Greengrass のインストール(インストール後の AWS IoT への登録など)には、AWSの認証情報が必要になります。
必要な Policy だったり、環境変数を使った設定方法がドキュメントに記載されています。
- https://docs.aws.amazon.com/greengrass/v2/developerguide/install-greengrass-core-v2.html?icmpid=docs_gg_console
- https://docs.aws.amazon.com/greengrass/v2/developerguide/install-greengrass-core-v2.html#provision-minimal-iam-policy

ただ、この検証では、EC2 インスタンスを使っていますので、IAM Role を EC2 インスタンスにアタッチすることで、完了しています。手順は省略
検証なので、アタッチした IAM Role には Administratorの権限が紐付いています(本番だと絶対にやってはいけないですね)

Step3: Run the installer

表示されたコマンドをコピペして、立ち上げた EC2 インスタンスにSSHで入って、コマンドを実行して、Greengrass をインストールします。

curl -s https://d2s8p88vqu9w66.cloudfront.net/releases/greengrass-nucleus-latest.zip > greengrass-nucleus-latest.zip && unzip greengrass-nucleus-latest.zip -d GreengrassCore

Archive:  greengrass-nucleus-latest.zip
  inflating: GreengrassCore/bin/greengrass.service.template  
  inflating: GreengrassCore/bin/loader  
  inflating: GreengrassCore/conf/nucleus-build.properties  
  inflating: GreengrassCore/lib/Greengrass.jar  
sudo -E java -Droot="/greengrass/v2" -Dlog.store=FILE -jar ./GreengrassCore/lib/Greengrass.jar --aws-region us-east-1 --thing-name greengrass-v2-qiita-core --thing-group-name greengrass-v2-qiita-group --component-default-user ggc_user:ggc_group --provision true --setup-system-service true --deploy-dev-tools true

Creating user ggc_user 
ggc_user created 
Creating group ggc_group 
ggc_group created 
Added ggc_user to ggc_group 
Provisioning AWS IoT resources for the device with IoT Thing Name: [greengrass-v2-qiita-core]...
Creating new IoT policy "GreengrassV2IoTThingPolicy"
Creating keys and certificate...
Attaching policy to certificate...
Creating IoT Thing "greengrass-v2-qiita-core"...
Attaching certificate to IoT thing...
Successfully provisioned AWS IoT resources for the device with IoT Thing Name: [greengrass-v2-qiita-core]!
Adding IoT Thing [greengrass-v2-qiita-core] into Thing Group: [greengrass-v2-qiita-group]...
Successfully added Thing into Thing Group: [greengrass-v2-qiita-group]
Setting up resources for aws.greengrass.TokenExchangeService ... 
TES role alias "GreengrassV2TokenExchangeRoleAlias" does not exist, creating new alias...
IoT role policy "GreengrassTESCertificatePolicyGreengrassV2TokenExchangeRoleAlias" for TES Role alias not exist, creating policy...
Attaching TES role policy to IoT thing...
IAM policy named "GreengrassV2TokenExchangeRoleAccess" already exists. Please attach it to the IAM role if not already
Configuring Nucleus with provisioned resource details...
Downloading Root CA from "https://www.amazontrust.com/repository/AmazonRootCA1.pem"
Created device configuration
Successfully configured Nucleus with provisioned resource details!
Creating a deployment for Greengrass first party components to the thing group
Configured Nucleus to deploy aws.greengrass.Cli component
Successfully set up Nucleus as a system service

AWS IoTの管理コンソールを見て、正常にインストールされていることを確認します

正常にインストールされていれば、図のように Core Device名 が表示されているはずです。
image.png

Docker コンテナを動かす

前提条件を満たすためにいろいろする

Docker のインストールと権限設定

Docker をインストールして、ggc_user に docker を実行できる権限を付加します。
(greengrass 経由で実行されるdocker コマンドはこの ggc_user で実行されるためです)

sudo yum install -y docker
sudo systemctl start docker
sudo systemctl enable docker
sudo usermod -a -G docker ggc_user
sudo usermod -a -G docker ec2-user   #このコマンドは必須ではないですが、いちいち sudo をつけるのがめんどくさいので実行しています

usermod が有効になるように、一度 EC2インスタンスに入り直します。

ローカルでの動作確認

ここでは local 環境でデプロイを行って、動作することを確認します

docker image の用意

mkdir -p ~/GreengrassCore/artifacts/com.example.MyDockerComponent/1.0.0

docker pull public.ecr.aws/nginx/nginx
docker save public.ecr.aws/nginx/nginx > ~/GreengrassCore/artifacts/com.example.MyDockerComponent/1.0.0/nginx.tar
docker image rm public.ecr.aws/nginx/nginx   #デプロイ時にローカルの image を使わないように削除しておく

recipe の用意

mkdir -p ~/GreengrassCore/recipes
touch ~/GreengrassCore/recipes/com.example.MyDockerComponent-1.0.0.yaml
com.example.MyDockerComponent-1.0.0.yaml
---
RecipeFormatVersion: '2020-01-25'
ComponentName: com.example.MyDockerComponent
ComponentVersion: '1.0.0'
ComponentDescription: A component that runs a Docker container.
ComponentPublisher: Amazon
Manifests:
  - Platform:
       os: linux
    Lifecycle:
       Install:
         Script: docker load -i {artifacts:path}/nginx.tar
       Run:
         Script: docker run --rm -p 8080:80 public.ecr.aws/nginx/nginx

ローカルでのデプロイ

sudo /greengrass/v2/bin/greengrass-cli deployment create \
  --recipeDir ~/GreengrassCore/recipes \
  --artifactDir ~/GreengrassCore/artifacts \
  --merge "com.example.MyDockerComponent=1.0.0"

# output
Dec 23, 2020 4:22:52 AM software.amazon.awssdk.eventstreamrpc.EventStreamRPCConnection$1 onConnectionSetup
INFO: Socket connection /greengrass/v2/ipc.socket:8033 to server result [AWS_ERROR_SUCCESS]
Dec 23, 2020 4:22:52 AM software.amazon.awssdk.eventstreamrpc.EventStreamRPCConnection$1 onProtocolMessage
INFO: Connection established with event stream RPC server
Local deployment submitted! Deployment Id: f86c969b-ce30-4f62-9cf4-fddb85987bc1

ローカルデプロイの確認

ログを確認します(なんとかく docker run されていそうなのが分かります)

[ec2-user@ip-10-0-12-139 recipes]$ sudo tail -f  /greengrass/v2/logs/com.example.MyDockerComponent.log 
...
2020-12-23T05:43:26.313Z [INFO] (pool-2-thread-33) com.example.MyDockerComponent: shell-runner-start. {scriptName=services.com.example.MyDockerComponent.lifecycle.Install.Script, serviceName=com.example.MyDockerComponent, currentState=NEW, command=["docker load -i /greengrass/v2/packages/artifacts/com.example.MyDockerComponent..."]}
2020-12-23T05:43:32.796Z [INFO] (Copier) com.example.MyDockerComponent: stdout. Loaded image: public.ecr.aws/nginx/nginx:latest. {scriptName=services.com.example.MyDockerComponent.lifecycle.Install.Script, serviceName=com.example.MyDockerComponent, currentState=NEW}
2020-12-23T05:43:32.849Z [INFO] (pool-2-thread-33) com.example.MyDockerComponent: shell-runner-start. {scriptName=services.com.example.MyDockerComponent.lifecycle.Run.Script, serviceName=com.example.MyDockerComponent, currentState=STARTING, command=["docker run --rm -p 8080:80 public.ecr.aws/nginx/nginx"]}
2020-12-23T05:43:34.532Z [INFO] (Copier) com.example.MyDockerComponent: stdout. /docker-entrypoint.sh: /docker-entrypoint.d/ is not empty, will attempt to perform configuration. {scriptName=services.com.example.MyDockerComponent.lifecycle.Run.Script, serviceName=com.example.MyDockerComponent, currentState=RUNNING}
2020-12-23T05:43:34.532Z [INFO] (Copier) com.example.MyDockerComponent: stdout. /docker-entrypoint.sh: Looking for shell scripts in /docker-entrypoint.d/. {scriptName=services.com.example.MyDockerComponent.lifecycle.Run.Script, serviceName=com.example.MyDockerComponent, currentState=RUNNING}
2020-12-23T05:43:34.544Z [INFO] (Copier) com.example.MyDockerComponent: stdout. /docker-entrypoint.sh: Launching /docker-entrypoint.d/10-listen-on-ipv6-by-default.sh. {scriptName=services.com.example.MyDockerComponent.lifecycle.Run.Script, serviceName=com.example.MyDockerComponent, currentState=RUNNING}
2020-12-23T05:43:34.569Z [INFO] (Copier) com.example.MyDockerComponent: stdout. 10-listen-on-ipv6-by-default.sh: info: Getting the checksum of /etc/nginx/conf.d/default.conf. {scriptName=services.com.example.MyDockerComponent.lifecycle.Run.Script, serviceName=com.example.MyDockerComponent, currentState=RUNNING}
2020-12-23T05:43:34.605Z [INFO] (Copier) com.example.MyDockerComponent: stdout. 10-listen-on-ipv6-by-default.sh: info: Enabled listen on IPv6 in /etc/nginx/conf.d/default.conf. {scriptName=services.com.example.MyDockerComponent.lifecycle.Run.Script, serviceName=com.example.MyDockerComponent, currentState=RUNNING}
2020-12-23T05:43:34.605Z [INFO] (Copier) com.example.MyDockerComponent: stdout. /docker-entrypoint.sh: Launching /docker-entrypoint.d/20-envsubst-on-templates.sh. {scriptName=services.com.example.MyDockerComponent.lifecycle.Run.Script, serviceName=com.example.MyDockerComponent, currentState=RUNNING}
2020-12-23T05:43:34.615Z [INFO] (Copier) com.example.MyDockerComponent: stdout. /docker-entrypoint.sh: Configuration complete; ready for start up. {scriptName=services.com.example.MyDockerComponent.lifecycle.Run.Script, serviceName=com.example.MyDockerComponent, currentState=RUNNING}

コンテナが動いていることも確認できますね!

docker ps

CONTAINER ID        IMAGE                        COMMAND                  CREATED             STATUS              PORTS                  NAMES
5f5281942e5b        public.ecr.aws/nginx/nginx   "/docker-entrypoint.…"   3 minutes ago       Up 3 minutes        0.0.0.0:8080->80/tcp   heuristic_sanderson

nginx も動いていることが確認できますね!

curl localhost:8080

<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
    body {
        width: 35em;
        margin: 0 auto;
        font-family: Tahoma, Verdana, Arial, sans-serif;
    }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>

<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>

<p><em>Thank you for using nginx.</em></p>
</body>
</html>

さて、これでローカルで動くことが確認できたので、実際にマネジメントコンソールからデプロイを行いましょう

デプロイ実施(準備編)

ローカルのデプロイメントを削除します

これで起動している docker コンテナが消えるはずです

sudo /greengrass/v2/bin/greengrass-cli deployment create --remove="com.example.MyDockerComponent"

tar の Docker イメージ を S3 にアップロードします

S3の場所は各自でお好きな場所を指定してください
この場合は、s3://xxxxxx/greengrassv2/docker/nginx.tar に保存

aws s3 cp ~/GreengrassCore/artifacts/com.example.MyDockerComponent/1.0.0/nginx.tar s3://xxxxxx/greengrassv2/docker/

デプロイ実施(デプロイ編)

デプロイの方法は、AWS CLI, SDK などいろいろあるようですが、ここでは マネジメントコンソールからデプロイを行いました。

Component の作成

create component をクリック
image.png

Yamlを入力(ローカルデプロイのyamlと似ていますが、Artifacts という項目を追加しています)
image.png

---
RecipeFormatVersion: '2020-01-25'
ComponentName: com.example.MyDockerComponent
ComponentVersion: '1.0.0'
ComponentDescription: A component that runs a Docker container.
ComponentPublisher: Amazon
Manifests:
  - Platform:
       os: linux
    Lifecycle:
       Install:
         Script: docker load -i {artifacts:path}/nginx.tar
       Run:
         Script: docker run --rm -p 8080:80 public.ecr.aws/nginx/nginx
    Artifacts:
     - Uri: s3://xxxxx/greengrassv2/docker/nginx.tar

yaml を保存したら、Deploy をクリックします。

image.png

初回インストールに作成されたデプロイメントを指定します
image.png

作成した Components を作成します
image.png

特にオプションは設定せずに、Deploy を選択します
image.png

これでデプロイされるはずので、動作確認をしてみましょう。

動作確認

docker コマンドで確認したり、localhostでアクセスしたりしてみます。

docker ps
CONTAINER ID        IMAGE                        COMMAND                  CREATED              STATUS              PORTS                  NAMES
4c3181250b11        public.ecr.aws/nginx/nginx   "/docker-entrypoint.…"   About a minute ago   Up About a minute   0.0.0.0:8080->80/tcp   recursing_montalcini
curl localhost:8080

<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
    body {
        width: 35em;
        margin: 0 auto;
        font-family: Tahoma, Verdana, Arial, sans-serif;
    }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>

<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>

<p><em>Thank you for using nginx.</em></p>
</body>
</html>

docker コンテナも動いてて、nginx の動作も確認できました!

まとめ

発表された Greengrass 2.0 を使って、デバイス(今回はEC2インスタンス)に docker コンテナをデプロイしました。
今回は、EC2 インスタンスなので、有り難みはあまり感じないですが、これが IoT機器で、しかも、それが大量にあるという環境だとかなり便利に使えるのではないでしょうか?
現時点では、データの取得元(artifacts)は、S3 のみのため、docker image を tar にして S3 にアップロードするというのはやや残念ではありますが、まだリリースされたばかりなので今後のアップデートに期待ですね。

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
What you can do with signing up
3
Help us understand the problem. What are the problem?