Deploy, update, and destroy AWS EC2 Instance automatically

This tutorial explains the deployment automation of a simple AWS EC2 instance with the GruCloud AWS provider.

Instead of manually creating, updating, and destroying EC2 instances, the infrastructure will be described as Javascript code. The GruCloud C…


This content originally appeared on DEV Community and was authored by Frederic

This tutorial explains the deployment automation of a simple AWS EC2 instance with the GruCloud AWS provider.

Instead of manually creating, updating, and destroying EC2 instances, the infrastructure will be described as Javascript code. The GruCloud CLI then reads this code, retrieves the lives resources through the AWS API, and decides what needs to be created, updated, or destroyed.

graph-diagram-ec2.svg

Requirements

AWS Account

Ensure access to the Amazon Console and create an account if necessary.

AWS CLI

Ensure the AWS CLI is installed and configured:

aws --version

If not, visit https://docs.aws.amazon.com/cli/latest/userguide/install-cliv2.html

Access and Secret Key

Visit the security credentials

  • Click on Access key (access key ID and secret access key).
  • Click on the button Create New Access Key.

Write down the AWSAccessKeyId and AWSSecretKey

In a further episode, the access and secret key will be obtained from a dedicated IAM user with the correct role and policy.

Configure AWS CLI

Configure the account with the previously obtained AWSAccessKeyId and AWSSecretKey, as well as the region, for instance us-east-1

aws configure

Getting the GruCloud CLI

GruCloud is written in Javascript running on Node.js. Check if node is present on your system:

node --version

The version must be greater than 14

Install the GrucCloud command-line utility gc with npm

npm i -g @grucloud/core

Check the current version of gc:

gc --version

Code Architecture

In this section, we'll create the files needed to describe an infrastructure with GruCloud:

  • package.json: specifies the npm dependencies and other information.
  • config.js: the config function.
  • iac.js: exports createStack with provider and resources associated
  • hooks.js: optionally provides hook functions called after deployment or destruction.

The source code for this example in on GitHub.

Create a new project

Create a new directory, for instance ec2-example:

mkdir ec2-example
cd ec2-example

package.json

Let's create a new package.json with the npm init command:

npm init

Let's install the GruCloud AWS provider called @grucloud/provider-aws, as well as the GruCloud core library @grucloud/core.

npm install @grucloud/core @grucloud/provider-aws

config.js

The configuration is a Javascript function located in config.js

// config.js
const pkg = require("./package.json");
module.exports = ({ stage }) => ({
  projectName: pkg.name,
  ec2Instance: {
    name: "web-server",
    properties: {
      InstanceType: "t2.micro",
      ImageId: "ami-00f6a0c18edb19300", // Ubuntu 18.04
    },
  },
});

You will have to find out the ImageId for your specific region. One way to retrieve to list of images is with the aws cli:

aws ec2 describe-images --filters "Name=description,Values=Ubuntu Server 20.04 LTS" "Name=architecture,Values=x86_64"

This step will be automated in a future episode with the help of the Amazon Managed Image resource.

iac.js

Create a file called iac.js which stands for infrastructure as code.
We'll first import AwsProvider from @grucloud/provider-aws

iac.js must export the createStack function which returns the provider and the resources.

Then, instantiate AwsProvider by providing the config function.

In the case, an EC2 Instance is defined with provider.makeEC2.

// iac.js
const { AwsProvider } = require("@grucloud/provider-aws");

exports.createStack = async ({ stage }) => {
  const provider = AwsProvider({ config: require("./config"), stage });
  const { config } = provider;
  const ec2Instance = await provider.makeEC2({
    name: config.ec2Instance.name,
    properties: () => config.ec2Instance.properties,
  });

  return {
    provider,
    resources: { ec2Instance },
  };
};

GruCloud CLI

Info

As a way to verify that gc can connect to the AWS API, one can use the info command:

gc info
  - provider:
      name: aws
      type: aws
    stage: dev
    accountId: 840541460064
    zone: eu-west-2a
    config:
      projectName: ec2-simple
      ec2Instance:
        name: web-server
        properties:
          InstanceType: t2.micro
          ImageId: ami-00f6a0c18edb19300
      stage: dev
      zone: [object Function]
      accountId: [object Function]
      region: eu-west-2

Command "gc info" executed in 1s

Deploy

We are ready to deploy with apply command:

gc apply
Querying resources on 1 provider: aws
✓ aws
  ✓ Initialising
  ✓ Listing 6/6
  ✓ Querying
    ✓ EC2 1/1
┌──────────────────────────────────────────────────────────────────────────┐
│ 1 EC2 from aws                                                           │
├────────────┬──────────┬──────────────────────────────────────────────────┤
│ Name       │ Action   │ Data                                             │
├────────────┼──────────┼──────────────────────────────────────────────────┤
│ web-server │ CREATE   │ InstanceType: t2.micro                           │
│            │          │ ImageId: ami-00f6a0c18edb19300                   │
│            │          │ MaxCount: 1                                      │
│            │          │ MinCount: 1                                      │
│            │          │ TagSpecifications:                               │
│            │          │   - ResourceType: instance                       │
│            │          │     Tags:                                        │
│            │          │       - Key: Name                                │
│            │          │         Value: web-server                        │
│            │          │       - Key: ManagedBy                           │
│            │          │         Value: GruCloud                          │
│            │          │       - Key: CreatedByProvider                   │
│            │          │         Value: aws                               │
│            │          │       - Key: stage                               │
│            │          │         Value: dev                               │
│            │          │       - Key: projectName                         │
│            │          │         Value: ec2-simple                        │
│            │          │                                                  │
└────────────┴──────────┴──────────────────────────────────────────────────┘


┌─────────────────────────────────────────────────────────────────────────┐
│ Plan summary for provider aws                                           │
├─────────────────────────────────────────────────────────────────────────┤
│ DEPLOY RESOURCES                                                        │
├────────────────────┬────────────────────────────────────────────────────┤
│ EC2                │ web-server                                         │
└────────────────────┴────────────────────────────────────────────────────┘
? Are you sure to deploy 1 resource, 1 type on 1 provider? › (y/N)

At this point, you are given the opportunity to look at what is going to be deployed.
Type y to accept:

Deploying resources on 1 provider: aws
✓ aws
  ✓ Initialising
  ✓ Deploying
    ✓ EC2 1/1
1 resource deployed of 1 type and 1 provider
Running OnDeployedGlobal resources on 1 provider: aws
Command "gc a" executed in 1m 29s

When gc apply is executed a second time, resources should not be created or destroyed.

gc a
Querying resources on 1 provider: aws
✓ aws
  ✓ Initialising
  ✓ Listing 13/13
  ✓ Querying
    ✓ EC2 1/1
┌─────────────────────────────────────────────────────────────────────────────────────────┐
│ Plan summary for provider aws                                                           │
└─────────────────────────────────────────────────────────────────────────────────────────┘
Nothing to deploy
Running OnDeployedGlobal resources on 1 provider: aws
Command "gc a" executed in 9s

As expected, nothing to deploy, the target resources defined in the code match the live resources.

List

To list all the resources, and generate a diagram:

gc list --graph --all

This will include the default AWS resources such as VPC, subnet, internet gateway, and security group.

graph-live

To list only the resources created by GruCloud:

gc list --our
Listing resources on 1 provider: aws
✓ aws
  ✓ Initialising
  ✓ Listing 13/13
┌─────────────────────────────────────────────────────────────────────────────────────────────────────────┐
│ 1 EC2 from aws                                                                                          │
├────────────┬─────────────────────────────────────────────────────────────────────────────────────┬──────┤
│ Name       │ Data                                                                                │ Our  │
├────────────┼─────────────────────────────────────────────────────────────────────────────────────┼──────┤
│ web-server │ AmiLaunchIndex: 0                                                                   │ Yes  │
│            │ ImageId: ami-00f6a0c18edb19300                                                      │      │
│            │ InstanceId: i-016628a1b6a6a2f91                                                     │      │
│            │ InstanceType: t3.micro                                                              │      │
│            │ LaunchTime: 2021-04-29T23:10:44.000Z                                                │      │
│            │ Monitoring:                                                                         │      │
│            │   State: disabled                                                                   │      │
│            │ Placement:                                                                          │      │
│            │   AvailabilityZone: eu-west-2a                                                      │      │
│            │   GroupName:                                                                        │      │
│            │   Tenancy: default                                                                  │      │
│            │ PrivateDnsName: ip-172-31-2-146.eu-west-2.compute.internal                          │      │
│            │ PrivateIpAddress: 172.31.2.146                                                      │      │
│            │ ProductCodes: []                                                                    │      │
│            │ PublicDnsName: ec2-18-132-98-216.eu-west-2.compute.amazonaws.com                    │      │
│            │ PublicIpAddress: 18.132.98.216                                                      │      │
│            │ State:                                                                              │      │
│            │   Code: 16                                                                          │      │
│            │   Name: running                                                                     │      │
│            │ StateTransitionReason:                                                              │      │
│            │ SubnetId: subnet-0f6f085fc384bf8ce                                                  │      │
│            │ VpcId: vpc-bbbafcd3                                                                 │      │
│            │ Architecture: x86_64                                                                │      │
│            │ BlockDeviceMappings:                                                                │      │
│            │   - DeviceName: /dev/sda1                                                           │      │
│            │     Ebs:                                                                            │      │
│            │       AttachTime: 2021-04-29T23:10:45.000Z                                          │      │
│            │       DeleteOnTermination: true                                                     │      │
│            │       Status: attached                                                              │      │
│            │       VolumeId: vol-0a88a34248fe18740                                               │      │
│            │ ClientToken: 7ef5fd60-e962-400f-a2b9-37719d8329ed                                   │      │
│            │ EbsOptimized: false                                                                 │      │
│            │ EnaSupport: true                                                                    │      │
│            │ Hypervisor: xen                                                                     │      │
│            │ ElasticGpuAssociations: []                                                          │      │
│            │ ElasticInferenceAcceleratorAssociations: []                                         │      │
│            │ NetworkInterfaces:                                                                  │      │
│            │   - Association:                                                                    │      │
│            │       IpOwnerId: amazon                                                             │      │
│            │       PublicDnsName: ec2-18-132-98-216.eu-west-2.compute.amazonaws.com              │      │
│            │       PublicIp: 18.132.98.216                                                       │      │
│            │     Attachment:                                                                     │      │
│            │       AttachTime: 2021-04-29T23:10:44.000Z                                          │      │
│            │       AttachmentId: eni-attach-02744addcff43ecbb                                    │      │
│            │       DeleteOnTermination: true                                                     │      │
│            │       DeviceIndex: 0                                                                │      │
│            │       Status: attached                                                              │      │
│            │       NetworkCardIndex: 0                                                           │      │
│            │     Description:                                                                    │      │
│            │     Groups:                                                                         │      │
│            │       - GroupName: default                                                          │      │
│            │         GroupId: sg-f4139a96                                                        │      │
│            │     Ipv6Addresses: []                                                               │      │
│            │     MacAddress: 06:ee:ef:d7:1c:48                                                   │      │
│            │     NetworkInterfaceId: eni-06e9d87ff776cf40f                                       │      │
│            │     OwnerId: 840541460064                                                           │      │
│            │     PrivateDnsName: ip-172-31-2-146.eu-west-2.compute.internal                      │      │
│            │     PrivateIpAddress: 172.31.2.146                                                  │      │
│            │     PrivateIpAddresses:                                                             │      │
│            │       - Association:                                                                │      │
│            │           IpOwnerId: amazon                                                         │      │
│            │           PublicDnsName: ec2-18-132-98-216.eu-west-2.compute.amazonaws.com          │      │
│            │           PublicIp: 18.132.98.216                                                   │      │
│            │         Primary: true                                                               │      │
│            │         PrivateDnsName: ip-172-31-2-146.eu-west-2.compute.internal                  │      │
│            │         PrivateIpAddress: 172.31.2.146                                              │      │
│            │     SourceDestCheck: true                                                           │      │
│            │     Status: in-use                                                                  │      │
│            │     SubnetId: subnet-0f6f085fc384bf8ce                                              │      │
│            │     VpcId: vpc-bbbafcd3                                                             │      │
│            │     InterfaceType: interface                                                        │      │
│            │ RootDeviceName: /dev/sda1                                                           │      │
│            │ RootDeviceType: ebs                                                                 │      │
│            │ SecurityGroups:                                                                     │      │
│            │   - GroupName: default                                                              │      │
│            │     GroupId: sg-f4139a96                                                            │      │
│            │ SourceDestCheck: true                                                               │      │
│            │ Tags:                                                                               │      │
│            │   - Key: Name                                                                       │      │
│            │     Value: web-server                                                               │      │
│            │   - Key: stage                                                                      │      │
│            │     Value: dev                                                                      │      │
│            │   - Key: CreatedByProvider                                                          │      │
│            │     Value: aws                                                                      │      │
│            │   - Key: ManagedBy                                                                  │      │
│            │     Value: GruCloud                                                                 │      │
│            │   - Key: projectName                                                                │      │
│            │     Value: ec2-simple                                                               │      │
│            │ VirtualizationType: hvm                                                             │      │
│            │ CpuOptions:                                                                         │      │
│            │   CoreCount: 1                                                                      │      │
│            │   ThreadsPerCore: 2                                                                 │      │
│            │ CapacityReservationSpecification:                                                   │      │
│            │   CapacityReservationPreference: open                                               │      │
│            │ HibernationOptions:                                                                 │      │
│            │   Configured: false                                                                 │      │
│            │ Licenses: []                                                                        │      │
│            │ MetadataOptions:                                                                    │      │
│            │   State: applied                                                                    │      │
│            │   HttpTokens: optional                                                              │      │
│            │   HttpPutResponseHopLimit: 1                                                        │      │
│            │   HttpEndpoint: enabled                                                             │      │
│            │ EnclaveOptions:                                                                     │      │
│            │   Enabled: false                                                                    │      │
│            │                                                                                     │      │
└────────────┴─────────────────────────────────────────────────────────────────────────────────────┴──────┘


List Summary:
Provider: aws
┌────────────────────────────────────────────────────────────────────────────────────────────────────────┐
│ aws                                                                                                    │
├────────────────────┬───────────────────────────────────────────────────────────────────────────────────┤
│ EC2                │ web-server                                                                        │
└────────────────────┴───────────────────────────────────────────────────────────────────────────────────┘
1 resource, 7 types, 1 provider
Command "gc l -o" executed in 7s

Note that tags have been added to the EC2 Instance, it gives GruCloud a way to identify the resources under its control. Unlike other infrastructure as code tools such as Terraform and Pulumi, GruCloud does not need a state file. Hence removing a lot of complexity and issues.

Update

The ec2 instance configuration might change, for instance, let's modify the machine type to t3.micro located in config.js

The plan command is a read-only command which fetches the live resources and compares them with the target resources defined in the code.

gc plan
Querying resources on 1 provider: aws
✓ aws
  ✓ Initialising
  ✓ Listing 13/13
  ✓ Querying
    ✓ EC2 1/1
┌──────────────────────────────────────────────────────────────────────────────────────────┐
│ 1 EC2 from aws                                                                           │
├────────────┬──────────┬──────────────────────────────────────────────────────────────────┤
│ Name       │ Action   │ Data                                                             │
├────────────┼──────────┼──────────────────────────────────────────────────────────────────┤
│ web-server │ UPDATE   │ added:                                                           │
│            │          │ updated:                                                         │
│            │          │   InstanceType: t3.micro                                         │
│            │          │                                                                  │
└────────────┴──────────┴──────────────────────────────────────────────────────────────────┘

┌─────────────────────────────────────────────────────────────────────────────────────────┐
│ Plan summary for provider aws                                                           │
├─────────────────────────────────────────────────────────────────────────────────────────┤
│ DEPLOY RESOURCES                                                                        │
├────────────────────┬────────────────────────────────────────────────────────────────────┤
│ EC2                │ web-server                                                         │
└────────────────────┴────────────────────────────────────────────────────────────────────┘
1 resource to deploy on 1 provider
Command "gc plan" executed in 5s

Let's apply the change:

gc apply

Bear in mind that the machine requires to be stopped and restarted.

Trust but verify, hence, list the EC2 instances and check the InstanceType has been changed.

gc l -t EC2

Output

Another useful command is gc output, which extract information for a specific field of a given resource

gc output -t EC2 --name web-server -f InstanceType
t3.micro

Nested field can be accessed too, for example, let's retrieve the public IP address attached to the EC2 instance:

gc output -t EC2 --name web-server -f 'NetworkInterfaces[0].Association.PublicIp'
18.130.34.212

The temptation to ping is high:

ping `gc output -t EC2 --name web-server -f 'NetworkInterfaces[0].Association.PublicIp'`
PING 18.130.34.212 (18.130.34.212): 56 data bytes
64 bytes from 18.130.34.212: icmp_seq=0 ttl=38 time=153.799 ms
64 bytes from 18.130.34.212: icmp_seq=1 ttl=38 time=153.583 ms
64 bytes from 18.130.34.212: icmp_seq=2 ttl=38 time=140.622 ms

Destroy

Time to destroy the resources allocated and therefore save a lot of £$€.

gc destroy
Find Deletable resources on 1 provider: aws
✓ aws
  ✓ Initialising
  ✓ Listing 6/6
? Are you sure to destroy 1 resource, 1 type on 1 provider? › (y/N)

Once again, you are given the opportunity to look at what is going to be destroyed.
Type 'y' to confirm the destruction:

Destroying resources on 1 provider: aws
✓ aws
  ✓ Initialising
  ✓ Destroying
    ✓ EC2 1/1
1 resource destroyed, 1 type on 1 provider
Running OnDestroyedGlobal resources on 1 provider: aws
Command "gc destroy" executed in 1m 29s

Let's run the gc list command with the E2 filter to verify the EC2 is gone:

gc l -t EC2
Listing resources on 1 provider: aws
✓ aws
  ✓ Initialising
  ✓ Listing 6/6
List Summary:
Provider: aws
┌─────────────────────────────────────────────────────────────────────────┐
│ aws                                                                     │
└─────────────────────────────────────────────────────────────────────────┘
0 resources, 0 types, 1 provider
Command "gc list -t EC2" executed in 3s

This example demonstrates how to code a very basic infrastructure with one EC2 instance, and how can we use the gc apply, gc list, gc destroy and gc graph to manage the infrastructure.

It paves the way for more AWS examples

Graph

A picture is worth a thousand words, GruCloud generates an SVG file describing the resources and their relationship.

gc graph

Here is the graph of a typical web application managed by Kubernetes running on AWS where the master node is managed by EKS.

kubernetes eks

Links


This content originally appeared on DEV Community and was authored by Frederic


Print Share Comment Cite Upload Translate Updates
APA

Frederic | Sciencx (2021-04-30T02:29:19+00:00) Deploy, update, and destroy AWS EC2 Instance automatically. Retrieved from https://www.scien.cx/2021/04/30/deploy-update-and-destroy-aws-ec2-instance-automatically/

MLA
" » Deploy, update, and destroy AWS EC2 Instance automatically." Frederic | Sciencx - Friday April 30, 2021, https://www.scien.cx/2021/04/30/deploy-update-and-destroy-aws-ec2-instance-automatically/
HARVARD
Frederic | Sciencx Friday April 30, 2021 » Deploy, update, and destroy AWS EC2 Instance automatically., viewed ,<https://www.scien.cx/2021/04/30/deploy-update-and-destroy-aws-ec2-instance-automatically/>
VANCOUVER
Frederic | Sciencx - » Deploy, update, and destroy AWS EC2 Instance automatically. [Internet]. [Accessed ]. Available from: https://www.scien.cx/2021/04/30/deploy-update-and-destroy-aws-ec2-instance-automatically/
CHICAGO
" » Deploy, update, and destroy AWS EC2 Instance automatically." Frederic | Sciencx - Accessed . https://www.scien.cx/2021/04/30/deploy-update-and-destroy-aws-ec2-instance-automatically/
IEEE
" » Deploy, update, and destroy AWS EC2 Instance automatically." Frederic | Sciencx [Online]. Available: https://www.scien.cx/2021/04/30/deploy-update-and-destroy-aws-ec2-instance-automatically/. [Accessed: ]
rf:citation
» Deploy, update, and destroy AWS EC2 Instance automatically | Frederic | Sciencx | https://www.scien.cx/2021/04/30/deploy-update-and-destroy-aws-ec2-instance-automatically/ |

Please log in to upload a file.




There are no updates yet.
Click the Upload button above to add an update.

You must be logged in to translate posts. Please log in or register.