Install the AWS CLI, see AWS CLI and [Installing the AWS Command Line Interface]
sean@vubuntu:~$ sudo apt install awscli -y
sean@vubuntu:~$ aws --version aws-cli/1.14.44 Python/3.6.6 Linux/4.15.0-36-generic botocore/1.8.48
Access keys consist of an access key ID and secret access key, which are used to sign programmatic requests that you make to AWS. The aws configure
command will prompt you for four pieces of information. AWS Access Key ID and AWS Secret Access Key are your programatic account credentials. Specify an AWS region and are the same names you see in the mgt. console. The default output can be either json, text, or table, where the default format is json.
sean@vubuntu:~$ aws configure AWS Access Key ID [None]: AWS Secret Access Key [None]: Default region name [None]: us-west-2 Default output format [None]: json
Verify operation by listing all IAM users.
sean@vubuntu:~$ aws iam list-users { "Users": [ { "Path": "/", "UserName": "sean", "UserId": "AIDAJODWTO2Q2GNNXKUMA", "Arn": "arn:aws:iam::404297683117:user/sean", "CreateDate": "2018-05-08T00:38:00Z", "PasswordLastUsed": "2018-09-25T01:22:12Z" } ] }
In order to launch a virtual server use the aws ec2 run-instances
with the following parameters:
- AMI ID
- Instance type
- Security Group
- SSH key-pair
An Amazon Machine Image (AMI) is a package that contains the OS and additional software required to start the system.
- Use the
aws ec2 describe-images
command along with filter options to only include the AMI wanted. In the filter use x84_64 bits version to match the architecture. The virtualization type will be HVM. There are two types of AMI virtualization: Para-Virtual (PV) and Hardware Virtual Machine (HVM). The main difference between them is the boot process and how they take advantage of special hardware extensions like CPU, network, and storage for better performance. The GP2 is for General Purpose SSD (gp2), which is a type of EBS (Elastic Block Store) Volume.
sean@vubuntu:~$ aws ec2 describe-images --filters "Name=description,Values=Amazon Linux AMI * x86_64 HVM GP2" --query 'Images[*].[CreationDate, Description, ImageId]' --output text | sort -k 1 | tail 2018-01-08T18:43:49.000Z Amazon Linux AMI 2017.09.1.20180108 x86_64 HVM GP2 ami-32cf7b4a 2018-01-10T18:59:11.000Z Amazon Linux AMI 2017.09.1.20180108 x86_64 HVM GP2 ami-2a853252 2018-01-15T19:13:58.000Z Amazon Linux AMI 2017.09.1.20180115 x86_64 HVM GP2 ami-f2d3638a 2018-01-18T23:11:52.000Z Amazon Linux AMI 2017.09.1.20171120 x86_64 HVM GP2 ami-e6f84a9e 2018-03-07T06:59:59.000Z Amazon Linux AMI 2017.09.1.20180307 x86_64 HVM GP2 ami-d874e0a0 2018-03-07T07:11:48.000Z Amazon Linux AMI 2017.09.1-testlongids.20180307 x86_64 HVM GP2 ami-0163da89c9a854198 2018-04-13T00:32:56.000Z Amazon Linux AMI 2018.03.0.20180412 x86_64 HVM GP2 ami-6b8cef13 2018-05-08T18:06:57.000Z Amazon Linux AMI 2018.03.0.20180508 x86_64 HVM GP2 ami-e251209a 2018-06-22T22:27:00.000Z Amazon Linux AMI 2018.03.0.20180622 x86_64 HVM GP2 ami-0ad99772 2018-08-11T02:29:45.000Z Amazon Linux AMI 2018.03.0.20180811 x86_64 HVM GP2 ami-a0cfeed8
--filter
allows you to filter the output based on the JSON data which represented in data name/value pairs.
sean@vubuntu:~$ aws ec2 describe-images --filters "Name=image-id,Values=ami-a0cfeed8" { "Images": [ { "Architecture": "x86_64", "CreationDate": "2018-08-11T02:29:45.000Z", "ImageId": "ami-a0cfeed8", "ImageLocation": "amazon/amzn-ami-hvm-2018.03.0.20180811-x86_64-gp2", "ImageType": "machine", "Public": true, "OwnerId": "137112412989", "State": "available", "BlockDeviceMappings": [ { "DeviceName": "/dev/xvda", "Ebs": { "Encrypted": false, "DeleteOnTermination": true, "SnapshotId": "snap-0b9ac5da0147e5eb2", "VolumeSize": 8, "VolumeType": "gp2" } } ], "Description": "Amazon Linux AMI 2018.03.0.20180811 x86_64 HVM GP2", "EnaSupport": true, "Hypervisor": "xen", "ImageOwnerAlias": "amazon", "Name": "amzn-ami-hvm-2018.03.0.20180811-x86_64-gp2", "RootDeviceName": "/dev/xvda", "RootDeviceType": "ebs", "SriovNetSupport": "simple", "VirtualizationType": "hvm" } ] }
tail
is a command-line utility for outputting the last part of files given to it via standard input and writes results to standard output. By default tail returns the last ten lines of each file that it is given.
sort
is a command-line utility for sorting with the-k 1
option sorts the data fields using the 1st column number (the newest being on the bottom).
--query
supplements commands to filter only information wanted and uses the JMESPath query language for JSON. TheImages[*]
uses an Index Expression, which is used to access elements in a list by indexing - in this case all Images..[CreationDate, Description, ImageId]
is part of a subexpression, which is a combination of two expressions separated by the.
char. The brackets[ ...]
is a MultiSelect List, which extracts a subset of elements separated by a,
from a JSON hash. See JMESPath for more information.
Instance type comprise varying combinations of CPU, memory, storage, and networking capacity and each instance type includes one or more instance sizes.
The t2.micro includes the following:
Model | vCPU | CPU Credits / hour | Mem (GiB) | Storage |
---|---|---|---|---|
t2.micro | 1 | 6 | 1 | EBS-Only |
Security Groups act as a virtual firewall (stateful) for your instance to control inbound and outbound traffic. The small web application will run on TCP/3000 and we want to support SSH TCP/22. Security Groups are tied to subnets within a Virtual Private Cloud (VPC).
- Run the following command to find the default VPC ID.
sean@vubuntu:~$ aws ec2 describe-vpcs { "Vpcs": [ { "CidrBlock": "172.31.0.0/16", "DhcpOptionsId": "dopt-b0dbadc9", "State": "available", "VpcId": "vpc-b3b5feca", "InstanceTenancy": "default", "CidrBlockAssociationSet": [ { "AssociationId": "vpc-cidr-assoc-a7c0ddcc", "CidrBlock": "172.31.0.0/16", "CidrBlockState": { "State": "associated" } } ], "IsDefault": true, "Tags": [ { "Key": "Name", "Value": "Default VPC" } ] } ] }
- Create a Security Group for the default VPC ID.
sean@vubuntu:~$ aws ec2 create-security-group --group-name HelloWorld --description "Hello World Demo" --vpc-id vpc-b3b5feca { "GroupId": "sg-0e2799ad580df135d" }
- By default Security Groups allow all outbound traffic from the instance but deny all inbound traffic. Open up SSH TCP/22 & TCP/3000 for inbound connectivity.
:::info You can get your public IP address with the following command:
sean@vubuntu:~$ dig +short myip.opendns.com @resolver1.opendns.com 75.166.145.22
Or install curl and try this:
sean@vubuntu:~$ sudo apt install curl -y
sean@vubuntu:~$ curl https://api.ipify.org 75.166.145.22
:::
sean@vubuntu:~$ aws ec2 authorize-security-group-ingress --group-name HelloWorld --protocol tcp --port 22 --cidr 75.166.145.22/32
sean@vubuntu:~$ aws ec2 authorize-security-group-ingress --group-name HelloWorld --protocol tcp --port 3000 --cidr 75.166.145.22/32
- Verify the Security Group.
sean@vubuntu:~$ aws ec2 describe-security-groups --group-names HelloWorld --output table ---------------------------------------------------------------------------------------------- | DescribeSecurityGroups | +--------------------------------------------------------------------------------------------+ || SecurityGroups || |+------------------+------------------------+-------------+---------------+----------------+| || Description | GroupId | GroupName | OwnerId | VpcId || |+------------------+------------------------+-------------+---------------+----------------+| || Hello World Demo| sg-0e2799ad580df135d | HelloWorld | 404297683117 | vpc-b3b5feca || |+------------------+------------------------+-------------+---------------+----------------+| ||| IpPermissions ||| ||+----------------------------+----------------------------------+------------------------+|| ||| FromPort | IpProtocol | ToPort ||| ||+----------------------------+----------------------------------+------------------------+|| ||| 22 | tcp | 22 ||| ||+----------------------------+----------------------------------+------------------------+|| |||| IpRanges |||| |||+--------------------------------------------------------------------------------------+||| |||| CidrIp |||| |||+--------------------------------------------------------------------------------------+||| |||| 75.166.145.22/32 |||| |||+--------------------------------------------------------------------------------------+||| ||| IpPermissions ||| ||+----------------------------+----------------------------------+------------------------+|| ||| FromPort | IpProtocol | ToPort ||| ||+----------------------------+----------------------------------+------------------------+|| ||| 3000 | tcp | 3000 ||| ||+----------------------------+----------------------------------+------------------------+|| |||| IpRanges |||| |||+--------------------------------------------------------------------------------------+||| |||| CidrIp |||| |||+--------------------------------------------------------------------------------------+||| |||| 75.166.145.22/32 |||| |||+--------------------------------------------------------------------------------------+||| ||| IpPermissionsEgress ||| ||+----------------------------------------------------------------------------------------+|| ||| IpProtocol ||| ||+----------------------------------------------------------------------------------------+|| ||| -1 ||| ||+----------------------------------------------------------------------------------------+|| |||| IpRanges |||| |||+--------------------------------------------------------------------------------------+||| |||| CidrIp |||| |||+--------------------------------------------------------------------------------------+||| |||| 0.0.0.0/0 |||| |||+--------------------------------------------------------------------------------------+|||
- Create an SSH key pair that will be used to access the EC2 instance.
sean@vubuntu:~$ aws ec2 create-key-pair --key-name EffectiveDevOpsAWS { "KeyFingerprint": "99:ee:44:6e:9b:3f:5c:bc:3e:ab:9d:09:d5:c3:6b:28:dc:56:0e:07", "KeyMaterial": "-----BEGIN RSA PRIVATE KEY-----\n<...snippped...>\n-----END RSA PRIVATE KEY-----", "KeyName": "EffectiveDevOpsAWS" }
- The key is located in the
"KeyMaterial":
section of the JSON output. Use theecho
command to output it to a PEM file.
sean@vubuntu:~$ echo -e "-----BEGIN RSA PRIVATE KEY-----\n<...snippped...>\n-----END RSA PRIVATE KEY-----" > ~/.ssh/EffectiveDevOpsAWS.pem
sean@vubuntu:~$ chmod 600 ~/.ssh/EffectiveDevOpsAWS.pem
Verify the fingerprint is the same as that displayed by the EC2 API. The command essentially just converts the private key from PEM (text) to DER (binary) format.
sean@vubuntu:~$ openssl pkcs8 -in ~/.ssh/EffectiveDevOpsAWS.pem -nocrypt -topk8 -outform DER | openssl sha1 -c (stdin)= 99:ee:44:6e:9b:3f:5c:bc:3e:ab:9d:09:d5:c3:6b:28:dc:56:0e:07
- Launch EC2 Instance with the following information:
- AMI ID: ami-a0cfeed8
- Instance type: t2.micro
- Security Group: sg-077a84bbc6f365e4c
- SSH key-pair: EffectiveDevOps
sean@vubuntu:~$ aws ec2 run-instances --instance-type t2.micro --key-name EffectiveDevOpsAWS --security-group-ids sg-0e2799ad580df135d --image-id ami-a0cfeed8 { "Groups": [], "Instances": [ { "AmiLaunchIndex": 0, "ImageId": "ami-a0cfeed8", "InstanceId": "i-079f9ae01c99115a7", "InstanceType": "t2.micro", "KeyName": "EffectiveDevOpsAWS", "LaunchTime": "2018-10-17T22:31:44.000Z", "Monitoring": { "State": "disabled" }, "Placement": { "AvailabilityZone": "us-west-2a", "GroupName": "", "Tenancy": "default" }, "PrivateDnsName": "ip-172-31-22-252.us-west-2.compute.internal", "PrivateIpAddress": "172.31.22.252", "ProductCodes": [], "PublicDnsName": "", "State": { "Code": 0, "Name": "pending" }, "StateTransitionReason": "", "SubnetId": "subnet-718a3a08", "VpcId": "vpc-b3b5feca", "Architecture": "x86_64", "BlockDeviceMappings": [], "ClientToken": "", "EbsOptimized": false, "Hypervisor": "xen", "NetworkInterfaces": [ { "Attachment": { "AttachTime": "2018-10-17T22:31:44.000Z", "AttachmentId": "eni-attach-063a5cc7d51ce8a90", "DeleteOnTermination": true, "DeviceIndex": 0, "Status": "attaching" }, "Description": "", "Groups": [ { "GroupName": "HelloWorld", "GroupId": "sg-0e2799ad580df135d" } ], "Ipv6Addresses": [], "MacAddress": "02:38:b1:9e:31:4a", "NetworkInterfaceId": "eni-014e58c52f13fcb97", "OwnerId": "404297683117", "PrivateDnsName": "ip-172-31-22-252.us-west-2.compute.internal", "PrivateIpAddress": "172.31.22.252", "PrivateIpAddresses": [ { "Primary": true, "PrivateDnsName": "ip-172-31-22-252.us-west-2.compute.internal", "PrivateIpAddress": "172.31.22.252" } ], "SourceDestCheck": true, "Status": "in-use", "SubnetId": "subnet-718a3a08", "VpcId": "vpc-b3b5feca" } ], "RootDeviceName": "/dev/xvda", "RootDeviceType": "ebs", "SecurityGroups": [ { "GroupName": "HelloWorld", "GroupId": "sg-0e2799ad580df135d" } ], "SourceDestCheck": true, "StateReason": { "Code": "pending", "Message": "pending" }, "VirtualizationType": "hvm" } ], "OwnerId": "404297683117", "ReservationId": "r-06b2c73070b3687b7" }
- Check the status by getting the
InstanceID
from the output of theaws ec2 run-instances
command. The instance is ready when theStatus
underSystemStatus
changes frominitializing
took
.
sean@vubuntu:~$ aws ec2 describe-instance-status --instance-ids i-079f9ae01c99115a7 { "InstanceStatuses": [ { "AvailabilityZone": "us-west-2a", "InstanceId": "i-079f9ae01c99115a7", "InstanceState": { "Code": 16, "Name": "running" }, "InstanceStatus": { "Details": [ { "Name": "reachability", "Status": "initializing" } ], "Status": "initializing" }, "SystemStatus": { "Details": [ { "Name": "reachability", "Status": "initializing" } ], "Status": "initializing" } } ] }
sean@vubuntu:~$ aws ec2 describe-instance-status --instance-ids i-079f9ae01c99115a7 --query "InstanceStatuses[*].SystemStatus.Status" [ "ok" ]
- Find the DNS name of the EC2 instance.
sean@vubuntu:~$ aws ec2 describe-instances --instance-ids i-079f9ae01c99115a7 --query "Reservations[*].Instances[*].PublicDnsName" [ [ "ec2-54-189-165-229.us-west-2.compute.amazonaws.com" ] ]
- SSH using the default user account for Amazon Linux is
ec2-user
.
sean@vubuntu:~$ ssh -i ~/.ssh/EffectiveDevOpsAWS.pem [email protected] __| __|_ ) _| ( / Amazon Linux AMI ___|\___|___| https://aws.amazon.com/amazon-linux-ami/2018.03-release-notes/ 11 package(s) needed for security, out of 20 available Run "sudo yum update" to apply all updates. [ec2-user@ip-172-31-22-252 ~]$
[ec2-user@ip-172-31-22-252 ~]$ ec2-metadata --all ami-id: ami-a0cfeed8 ami-launch-index: 0 ami-manifest-path: (unknown) ancestor-ami-ids: not available block-device-mapping: ami: /dev/xvda root: /dev/xvda instance-id: i-079f9ae01c99115a7 instance-type: t2.micro local-hostname: ip-172-31-22-252.us-west-2.compute.internal local-ipv4: 172.31.22.252 kernel-id: not available placement: us-west-2a product-codes: not available public-hostname: ec2-54-189-165-229.us-west-2.compute.amazonaws.com public-ipv4: 54.189.165.229 public-keys: keyname:EffectiveDevOpsAWS index:0 format:openssh-key key:(begins from next line) ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCamr79lrbfZBhAHFkqTEgJ7GP6OcCYG0AaojxfBbg4MwNalQ0lGE6k7euFZ/OReIfvFlvthNyIF3gqZnzFsUOkxbHeXVFFGBra3DAEtrbd9xMJGjH47vc6ytiL2+8IgAaIfUa3ec9N1IsFQwrLX/vs3tM/SI5Ld8APkkFChoQbXQPDS4k3AE8wyrSn83Q0+aOAWNXGUdkAWsagMrLhmCSt31AhGdH2hGJE6XZp+XZxNu1c9ThpnTHxvXCznODeonuAKC/acQPigO5fw7DFWITw6oLx5mZfiLNd7U5vyJVQ1J9HzxoMLfA52CcwaJyGLG7wM63BnuHymCwz02YKaK3x EffectiveDevOpsAWS ramdisk-id: not available reservation-id: r-06b2c73070b3687b7 security-groups: HelloWorld user-data: not available
- Install node.js. Amazon Linux is based on Red Hat Enterprise Linux (RHEL) and uses
yum
utility to manage and install packages. The OS comes with Extra Packages for Enterprise Linux (EPEL) pre-configured in it.
[ec2-user@ip-172-31-22-252 ~]$ sudo yum install --enablerepo=epel -y nodejs
[ec2-user@ip-172-31-22-252 ~]$ node -v v0.10.48
- Download the helloworld code from github.
[ec2-user@ip-172-31-22-252 ~]$ wget http://bit.ly/2vESNuc -O /home/ec2-user/helloworld.js
var http = require("http")
http.createServer(function (request, response) {
// Send the HTTP header
// HTTP Status: 200 : OK
// Content Type: text/plain
response.writeHead(200, {'Content-Type': 'text/plain'})
// Send the response body as "Hello World"
response.end('Hello World\n')
}).listen(3000)
// Console will print the message
console.log('Server running')
- Run the code.
[ec2-user@ip-172-31-22-252 ~]$ node helloworld.js Server running Server running
- Stop execution of helloworld with Ctrl+C in the terminal window.
^C[ec2-user@ip-172-31-22-252 ~]$
- Turn simple code into a service using upstart. Amazon Linux (unlike RHEL) comes with a system called upstart and provides additional features that System-V boot-up scripts don’t have, such as the ability to re-spawn a process that died unexpectedly. Download the helloworld.conf code from github and add the following code to
/etc/init/
on the EC2 instance.
[ec2-user@ip-172-31-22-252 ~]$ sudo wget http://bit.ly/2vVvT18 -O /etc/init/helloworld.conf
description "Hello world Deamon"
# Start when the system is ready to do networking.
start on started elastic-network-interfaces
# Stop when the system is on its way down.
stop on shutdown
respawn
script
exec su --session-command="/usr/bin/node /home/ec2-user/helloworld.js" ec2-user
end script
- Start the application.
[ec2-user@ip-172-31-22-252 ~]$ sudo start helloworld helloworld start/running, process 2856
- Service should still work at: http://ec2-54-189-165-229.us-west-2.compute.amazonaws.com:3000.
- Perform a clean shutdown of Hello World service using the
stop
command, then exit the virtual server.
[ec2-user@ip-172-31-22-252 ~]$ sudo stop helloworld helloworld stop/waiting
[ec2-user@ip-172-31-22-252 ~]$ ec2-metadata --instance-id instance-id: i-079f9ae01c99115a7
[ec2-user@ip-172-31-22-252 ~]$ exit logout Connection to ec2-54-189-165-229.us-west-2.compute.amazonaws.com closed.
- Terminate the EC2 instance.
sean@vubuntu:~$ aws ec2 terminate-instances --instance-ids i-079f9ae01c99115a7 { "TerminatingInstances": [ { "CurrentState": { "Code": 32, "Name": "shutting-down" }, "InstanceId": "i-079f9ae01c99115a7", "PreviousState": { "Code": 16, "Name": "running" } } ] }