I tried running a Docker container on AWS IoT Greengrass 2.0

This is the article on the 23rd day of AWS Containers Advent Calendar 2020.

AWS IoT Greengrass 2.0 was announced at re: Invent 2020. As with v1, v2 also supports the operation of the Docker container (https://docs.aws.amazon.com/greengrass/v2/developerguide/run-docker-container.html).

I tried it at once.

What i did

--Install AWS IoT Greengrass 2.0 on your EC2 instance --Run Docker container (here we run nginx container)

AWS IoT Greengrass 2.0 installation on EC2

I have a Raspberry Pi at hand, but since I am using it for another purpose, I created an EC2 instance this time and verified it after that. (I am using an EC2 instance of t2.micro, x86, Amazon Linux2, but the procedure for creating an EC2 instance is omitted.)

Install the required software on EC2

Creating a Core Device

Create a Core device in the AWS IoT management console (the orange button on the right side of the image) image.png

Enter the Core Device name and Things group name. Here, they are `greengrass-v2-qiita-core``` and `greengrass-v2-qiita-group```, respectively. image.png

Scroll down the page to see the installation instructions, so let's do it one by one.

image.png

Step0: Additional steps

I was addicted to it because I didn't do this and went on to the next.

sudo visudoTweak the root settings a bit as follows.

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

Step1: Install Java on the device Insert Java 8 (Corretto 8) by referring to here.

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

Step2: Configure AWS credentials on the device AWS credentials are required to install Greengrass (such as registering with AWS IoT after installation). The documentation describes the required Policy and how to set it using environment variables.

However, since this verification uses an EC2 instance, it is completed by attaching the IAM Role to the EC2 instance. Steps omitted Since it is a verification, the attached IAM Role is associated with Administrator privileges (it should never be done in production)

Step3: Run the installer

Copy and paste the displayed command, SSH into the launched EC2 instance, execute the command, and install 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

Look at the AWS IoT management console to make sure it's installed successfully

If it was installed successfully, you should see the Core Device name as shown. image.png

Run a Docker container

Do various things to meet the prerequisites

Docker installation and permission settings

Install Docker and add permission to run docker to gGC_user. (Because the docker command executed via greengrass is executed by this 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   #This command isn't required, but I'm running it because it's annoying to add sudo each time.

Re-enter your EC2 instance for usermod to take effect.

Local operation check

Here, deploy in the local environment and confirm that it works.

Preparation of 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   #Delete the local image when deploying so that it is not used

Preparation of 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

Deploy locally

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

Confirm local deployment

Check the log (you can see that docker run seems to be done somehow)

[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}

You can also see that the container is 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

You can see that nginx is also working!

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>

Now that we have confirmed that it works locally, let's actually deploy from the management console.

Deployment implementation (preparation)

Delete the local deployment

This should make the running docker container disappear

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

Upload the tar Docker image to S3

Please specify the location of S3 as you like In this case, save to s3: //xxxxxx/greengrassv2/docker/nginx.tar

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

Deployment implementation (deployment)

There seem to be various deployment methods such as AWS CLI and SDK, but here I deployed from the management console.

Creating a Component

Click create component image.png

Enter Yaml (similar to locally deployed yaml, but with the addition of an item called 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

After saving the yaml, click Deploy.

image.png

Specifies the deployment created for the initial installation image.png

Create the created Components image.png

Select Deploy without setting any options image.png

It should be deployed with this, so let's check the operation.

Operation check

Check it with the docker command or try accessing it with 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>

The docker container is also working, and I was able to confirm the operation of nginx!

Summary

Using the announced Greengrass 2.0, I deployed a docker container on my device (this time an EC2 instance). This time, it's an EC2 instance, so I don't really appreciate it, but if this is an IoT device and there are a lot of it, I think it can be used quite conveniently. At the moment, the only source of data (artifacts) is S3, so it's a bit disappointing to tar the docker image and upload it to S3, but it's just released, so I'm looking forward to future updates.

Recommended Posts

I tried running a Docker container on AWS IoT Greengrass 2.0
I tried running Ansible on a Docker container
I tried running Docker on Windows Server 2019
I tried deploying a Docker container on Lambda with Serverless Framework
I tried running Java on a Mac terminal
I built a Java EE environment on AWS and tried running a web application
Install AWS IoT Greengrass on Ubuntu
How to get inside a container running on AWS Fargate
Run React on a Docker container
Run PureScript on a Docker container
I tried running WordPress with docker preview on M1 Mac.
Microservices 101-I tried putting Docker on Ubuntu-
Starting with installing Docker on EC2 and running Yellowfin in a container
I tried running the route search engine (OSRM) easily with a container
How to deploy a container on AWS Lambda
I tried installing docker on an EC2 instance
I tried to create a portfolio with AWS, Docker, CircleCI, Laravel [with reference link]
I tried running Autoware
AWS Lambda supports container images so I tried Puppeteer
I tried using Docker Desktop for Windows on Windows 10 Home
I tried running a DB access application on IKS + Db2 on IBM Cloud (6. Preparation of DB access application (java))
left4dead2 I made a Docker image for the server and tried running it on GCE # 3 (I had a hard time building the server)
Creating a docker host on AWS using Docker Machine (personal memorandum)
I tried adding a separator line to TabLayout on Android
I tried the Docker tutorial!
I tried to create React.js × TypeScript × Material-UI on docker environment
Install docker on AWS EC2
Try Hello World using plain Java on a Docker container
I tried BIND with Docker
I tried to create a padrino development environment with Docker
I created a Docker image of a container for learning OpenAI Gym
I tried running a letter of credit transaction application with Corda 1
I tried to create a Spring MVC development environment on Mac
I tried to build a laravel operating environment while remembering Docker
Run (provisionally) a Docker image with ShellCommandActivity on AWS Data Pipeline
Install Docker on AWS Ubunt 20.04 LTS
Deploy a Docker application with Greengrass
I tried a little digdag docker.run_options
To beginners launching Docker on AWS
Build a Minecraft server on AWS
Run GUI application on Docker container
I tried installing CentOS 8 on ESXi 6.7
I tried using Pari gp container
AWS SAM CLI now supports local emulation of HttpApi, so I tried using it on WSL2 Docker
I tried running the Angular sample in Auth0 Quick Start with Docker
Access MySQL on a Docker container from a local (host OS) Java program
I tried to build a Firebase application development environment with Docker in 2020
Created a Docker container image for an OpenLDAP server based on Fedora
I tried migrating the portfolio created on Vagrant to the Docker development environment
I tried a calendar problem in Ruby
Launch docker container on EC2 (personal memorandum)
Run NordVPN on Docker (Windows) Ubuntu container
Try running Word2vec model on AWS Lambda
I tried using Scalar DL with Docker
I installed Docker on my Raspberry Pi 3
Build a Maven repository on AWS S3
I tried playing with BottomNavigationView a little ①
I made a calculator app on Android
I tried to build AdoptOpenjdk 11 on CentOS 7
What is Docker? I tried to summarize
Build an environment with Docker on AWS