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.
--Install AWS IoT Greengrass 2.0 on your EC2 instance --Run Docker container (here we run nginx container)
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.)
Create a Core device in the AWS IoT management console (the orange button on the right side of the image)
Enter the Core Device name and Things group name.
Here, they are `greengrass-v2-qiita-core``` and
`greengrass-v2-qiita-group```, respectively.
Scroll down the page to see the installation instructions, so let's do it one by one.
I was addicted to it because I didn't do this and went on to the next.
sudo visudo
Tweak 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
If it was installed successfully, you should see the Core Device name as shown.
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.
Here, deploy in the local environment and confirm that it works.
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
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
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.
This should make the running docker container disappear
sudo /greengrass/v2/bin/greengrass-cli deployment create --remove="com.example.MyDockerComponent"
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/
There seem to be various deployment methods such as AWS CLI and SDK, but here I deployed from the management console.
Click create component
Enter Yaml (similar to locally deployed yaml, but with the addition of an item called Artifacts)
---
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.
Specifies the deployment created for the initial installation
Create the created Components
Select Deploy without setting any options
It should be deployed with this, so let's check the operation.
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!
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