EC2 instance with EFS storage

Deploy a simple webpage with EFS serving as the permanent storage backend

Saptarsiroy
7 min readDec 9, 2020

This article aims at a practical implementation of webserver deployment with unlimited storage provided by the EFS service. So let’s get started :)

Alright!
Let’s have a quick look at what all we are going to implement in-order to develop the actual concept behind EFS and why to prefer them over EBS, although both of them are Storage As A Service from AWS!

We would be creating a key-pair and a security group (allowing port 22 for SSH and port 80 for web traffic). An instance would be created including the created key and security group. Next, we would launch an EFS service and mount the EFS volume onto the httpd document root (/var/www/html). The code would be committed into GitHub and the images of the webpage will be uploaded into an s3-bucket. We would create a CloudFront for the s3 domain and update the CloudFront URL into the webpage code to ensure lowest latency towards the webpage.

Let’s jump directly into the practical steps…

  • STEP-1: GET THE PROVIDERS, SECURE VARIABLES AND CREATE KEY-PAIR
    The key-pair generated here would be later on used in secure SSH connection to the launched instance.
provider "aws" {region = "ap-south-1"profile = "Sara"}data "aws_vpc" "default_vpc" {default = true} data "aws_subnet_ids" "default_subnet" {vpc_id = data.aws_vpc.default_vpc.id}//Creating Variable for AMI_IDvariable "ami_id" {type    = stringdefault = "ami-0447a12f28fddb066"}//Creating Variable for AMI_Typevariable "ami_type" {type    = stringdefault = "t2.micro"} //Creating Keyresource "tls_private_key" "tls_key" {algorithm = "RSA"}//Generating Key-Value Pairresource "aws_key_pair" "generated_key" {key_name   = "rg-env-key"public_key = tls_private_key.tls_key.public_key_opensshdepends_on = [tls_private_key.tls_key]}//Saving Private Key PEM Fileresource "local_file" "key-file" {content  = tls_private_key.tls_key.private_key_pemfilename = "mykey.pem"depends_on = [tls_private_key.tls_key]}
  • STEP-2: CREATE SECURITY GROUP FOR INSTANCE
    The security group created here will have the rules for SSH (port-22) for secure remote connection and for web ingress/egress (port-80) that will allow us to access the deployed webpage.
//Creating Security Group for ec2 instanceresource "aws_security_group" "web-SG" {name        = "WEB-SG"description = "Web Environment Security Group"vpc_id      = data.aws_vpc.default_vpc.id//Adding Rules to Security Groupingress {description = "SSH Rule"from_port   = 22to_port     = 22protocol    = "tcp"cidr_blocks = ["0.0.0.0/0"]}ingress {description = "HTTP Rule"from_port   = 80to_port     = 80protocol    = "tcp"cidr_blocks = ["0.0.0.0/0"]}egress {from_port   = 0to_port     = 0cidr_blocks = ["0.0.0.0/0"]protocol    = "-1"}depends_on = [tls_private_key.tls_key]}
  • STEP-3: CREATE SECURITY GROUP FOR EFS
    The security groups act as a virtual firewall that controls the traffic between them. If we don’t provide a security group when creating a mount target, Amazon EFS associates the default security group of the VPC with it which might not always be feasible.
//Creating Security Group for efs storageresource "aws_security_group" "efs-sg" {name        = "EFS-SG"description = "EFS security group"vpc_id      = data.aws_vpc.default_vpc.idingress {to_port         = 0from_port       = 0protocol        = "-1"security_groups = [aws_security_group.web-SG.id]}egress {from_port   = 0to_port     = 0cidr_blocks = ["0.0.0.0/0"]protocol    = "-1"}depends_on = [tls_private_key.tls_key]}
  • STEP-4: CREATE AN EFS CLUSTER
    Amazon Elastic File System (Amazon EFS) provides a simple, scalable, fully managed elastic NFS file system for use with AWS Cloud services and on-premises resources. It is built to scale on demand to petabytes without disrupting applications, growing and shrinking automatically as you add and remove files, eliminating the need to provision and manage capacity to accommodate growth. Amazon EFS is well suited to support a broad spectrum of use cases from home directories to business-critical applications.
//Creating efs clusterresource "aws_efs_file_system" "myefs" {creation_token = "web-efs"tags = {Name = "Webstore"}depends_on = [aws_security_group.efs-sg]}resource "aws_efs_mount_target" "efs-mount" {for_each        = data.aws_subnet_ids.default_subnet.idsfile_system_id  = aws_efs_file_system.myefs.idsubnet_id       = each.valuesecurity_groups = [aws_security_group.efs-sg.id]}
  • STEP-5: CREATE S3 BUCKET TO STORE OBJECTS
    Here, we are going to create an S3 bucket. S3 is an Object Storage System, where we will be putting the images (or other objects) to be used in the webpage. The object will be given public-read access so that it is visible in the webpage.
//Creating an S3 Bucket for Terraform Integrationresource "aws_s3_bucket" "new-web-bucket" {bucket = "new-web-bucket"acl    = "public-read"}//Putting Objects in S3 Bucketresource "aws_s3_bucket_object" "web-object1" {bucket = aws_s3_bucket.new-web-bucket.bucketkey    = "img.jpg"source = "C:/Users/saran/OneDrive/Desktop/AWS task-2/img.jpg"acl    = "public-read"}
  • STEP-6: CREATE CLOUDFRONT USING THE S3 DOMAIN
    Amazon CloudFront is a fast content delivery network (CDN) service that securely delivers data, videos, applications, and APIs to customers globally with low latency, high transfer speeds, all within a developer-friendly environment. We will be using the S3 domain in order to provide low latency from the objects in the bucket.
//Creating CloutFront with S3 Bucket Originresource "aws_cloudfront_distribution" "web-distribution" {origin {domain_name = aws_s3_bucket.new-web-bucket.bucket_regional_domain_nameorigin_id   = aws_s3_bucket.new-web-bucket.id}enabled             = trueis_ipv6_enabled     = truecomment             = "CloudFront Distribution"default_cache_behavior {allowed_methods  = ["DELETE", "GET", "HEAD", "OPTIONS", "PATCH", "POST", "PUT"]cached_methods   = ["GET", "HEAD"]target_origin_id = aws_s3_bucket.sappy-murgi-bucket.idforwarded_values {query_string = falsecookies {forward = "none"}}viewer_protocol_policy = "allow-all"min_ttl                = 0default_ttl            = 3600max_ttl                = 86400}restrictions {geo_restriction {restriction_type = "whitelist"locations        = ["IN"]}}tags = {Name        = "web-distribution"Environment = "Production"}viewer_certificate {cloudfront_default_certificate = true}depends_on = [aws_s3_bucket.new-web-bucket]}
  • STEP-7: LAUNCH THE EC2 INSTANCE
    Firstly, let us launch the EC2 instance using the variables created and the security group created.
//Launching First ec2 instanceresource "aws_instance" "first_instance" {ami             = var.ami_idinstance_type   = var.ami_typekey_name        = aws_key_pair.generated_key.key_namesecurity_groups = [aws_security_group.web-SG.name]

Now, we would need to properly configure the instance. We would mount the EFS volume into the directory /var/www/html (document root for Apache HTTPD) after installing the required packages. Then, we would clone the github repo containing the codes for the webpage, as well as tweak our code to insert the object cloudfront URL.

//Labelling the Instancetags = {Name = "Web-Env"env  = "Production"}connection {agent       = "false"type        = "ssh"user        = "ec2-user"private_key = tls_private_key.tls_key.private_key_pemhost        = aws_instance.first_instance.public_ip}provisioner "remote-exec" {inline = ["sudo yum install httpd git -y","sudo systemctl start httpd","sudo yum install -y amazon-efs-utils","sudo mount -t efs -o tls ${aws_efs_file_system.myefs.id}:/ /var/www/html","sudo git clone https://github.com/SaranyaChattopadhyay/aws-efs-web.git /var/www/html","echo '<img src='https://${aws_cloudfront_distribution.web-distribution.domain_name}/img.JPG' width='400' height='400'>' | sudo tee -a /var/www/html/index.html",]}depends_on = [aws_security_group.web-SG,aws_key_pair.generated_key,aws_efs_file_system.myefs,aws_efs_mount_target.efs-mount,aws_cloudfront_distribution.web-distribution,]}
  • STEP-8: OPEN THE WEBPAGE
//Open web-pageresource "null_resource" "ChromeOpen"  {depends_on = [aws_instance.first_instance,]provisioner "local-exec" {command = "start chrome  ${aws_instance.first_instance.public_ip}/index.html"}}

Seems nice!!

Now its time to deploy the full architecture at a go!
That’s simple, just a matter of a few terraform codes :)

terraform init
terraform validate
terraform apply -auto-approve

This process will take nearly 5–7minutes as this command is the one to setup the architecture by deploying all the services one-by-one.

After deploying the services, we will find an SSH connection happening to the launched instance.

This connection will be made only to properly label the instance and configure it as the webserver.

After all the steps are successful, the “success message” would somewhat look like this —

Once the creation is complete, automatically a new tab in the default web-browser would be opened with the public IP of our EC2 instance, and if the steps run correctly, the tab would contain our deployed webpage!!

Now, let’s have a quick glance at what all services have been launched on AWS.

Key-Pair
Security groups for web and EFS
EFS Cluster
S3 Bucket
CloudFront
EC2 instance

Well, that was really interesting! :)

So that was all in this practical that we had aimed at.

Thanks all!!

--

--

No responses yet