Automating Infrastructure Deployment with Docker and Terraform: Deploying a containerized E-commerce website.
Tags: devops, aws, learning, cloud
Published: 2023-12-06 23:52:25

**Introduction:**
In today's fast-paced world of DevOps and cloud computing, automating the deployment and management of infrastructure is crucial. Terraform, a popular Infrastructure as Code (IaC) tool, allows you to define and provision infrastructure in a declarative manner. In this article, we will explore how to use Terraform to deploy an EC2 instance on AWS, install Docker, build a Docker image using a specified Dockerfile, and push that image to Docker Hub. Finally, we’ll deploy a containerized e-commerce website using the deployed image.
Prerequisites:
Before we begin, make sure you have the following prerequisites:
1. An AWS account with appropriate access.
2. Terraform installed on your local machine.
3. An understanding of Docker and a Docker Hub account.

**Step 1: Create a repository on Docker Hub**
• Login to your docker hub account and create a new repository for the Project.


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zbhborlzya9hfkz9nvg0.png)


• An empty repository is created.


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/nsthcpjxlf3i53rbpen5.png)

**Step 2: Set up project environment.** 
• Create a project folder on your local machine.
• Open your code editor and open the project folder from the code editor (will be using VScode)


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/datlpd0abtfyqymnhva6.png)

• Create the following files within the project folder.
 **Deployment Script: (deployment.sh)**-This shell script contains the required commands based on the deployment requirements. Copy below codes into the file. 

```
#!/bin/bash

# install and configure docker on the ec2 instance
sudo yum update -y
sudo amazon-linux-extras install docker -y
sudo service docker start
sudo systemctl enable docker

# create a dockerfile

# build the docker image
#sudo docker build -t <image-tag> 
sudo docker build -t e-commerce .

# login to your docker hub account
#cat ~/my_password.txt | sudo docker login --username <your-docker-id> --password-stdin
cat ~/docker_password.txt | sudo docker login --username ojosamuel --password-stdin

# use the docker tag command to give the image a new name
#sudo docker tag <image-tag> <repository-name>
sudo docker tag e-commerce ojosamuel/e-commerce_terraform

# push the image to your docker hub repository
#sudo docker push <repository-name>
sudo docker push ojosamuel/e-commerce_terraform

# start the container to test the image
#sudo docker run -dp 80:80 <repository-name> 
sudo docker run -dp 80:80 ojosamuel/e-commerce_terraform


```
Note: The line of command below enables you to connect to your docker hub account. 

```
# login to your docker hub account
#cat ~/my_password.txt | sudo docker login --username <your-docker-id> --password-stdin
```
But you have to provide the password for authentication. so you will create a txt file on your local machine and type in your docker hub password. Please take note of the location of this file because your will make reference to it.

** Dockerfile:** This is a simple text file that contains all the command that is required to build a Docker image. Copy below codes into the file. The comment above each command explains the action to be performed by the command.

```
FROM amazonlinux:latest

# Install dependencies
RUN yum update -y && \
    yum install -y httpd && \
    yum search wget && \
    yum install wget -y && \
    yum install unzip -y

# change directory
RUN cd /var/www/html

# download webfiles
RUN wget https://github.com/7hundredtech/E-Commerce/raw/main/E-Commerce.zip

# unzip folder
RUN unzip E-Commerce.zip

# copy files into html directory
RUN cp -r furni-1.0.0/* /var/www/html/

# remove unwanted folder
RUN rm -rf furni-1.0.0 E-Commerce.zip

# exposes port 80 on the container
EXPOSE 80

# set the default application that will start when the container start
ENTRYPOINT ["/usr/sbin/httpd", "-D", "FOREGROUND"]
```

** Terraform File: (ec2.tf)** - This file provides declarative configurations statements for provisioning EC2 instance on AWS. This will also automate the installation of docker on the Ec2 instance by executing the deployment script, build a docker image and push the image to the specified docker repository and finally deploy a containerized e-commerce website using the built image. Copy below codes into the file. The comment above each command explains the action to be performed by the command.

```
# configured aws provider with proper credentials
provider "aws" {
  region  = "us-east-2"
  profile = "terraform_user"
}


# create default vpc if one does not exit
resource "aws_default_vpc" "default_vpc" {

  tags = {
    Name = "default vpc"
  }
}


# use data source to get all avalablility zones in region
data "aws_availability_zones" "available_zones" {}


# create default subnet if one does not exit
resource "aws_default_subnet" "default_az1" {
  availability_zone = data.aws_availability_zones.available_zones.names[0]

  tags = {
    Name = "default subnet"
  }
}


# create security group for the ec2 instance
resource "aws_security_group" "ec2_security_group" {
  name        = "ec2 security group"
  description = "allow access on ports 80 and 22"
  vpc_id      = aws_default_vpc.default_vpc.id

  ingress {
    description = "http access"
    from_port   = 80
    to_port     = 80
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }

  ingress {
    description = "ssh access"
    from_port   = 22
    to_port     = 22
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }

  egress {
    from_port   = 0
    to_port     = 0
    protocol    = -1
    cidr_blocks = ["0.0.0.0/0"]
  }

  tags = {
    Name = "docker server sg"
  }
}


# use data source to get a registered amazon linux 2 ami
data "aws_ami" "amazon_linux_2" {
  most_recent = true
  owners      = ["amazon"]

  filter {
    name   = "owner-alias"
    values = ["amazon"]
  }

  filter {
    name   = "name"
    values = ["amzn2-ami-hvm*"]
  }
}


# launch the ec2 instance
resource "aws_instance" "ec2_instance" {
  ami                    = data.aws_ami.amazon_linux_2.id
  instance_type          = "t2.micro"
  subnet_id              = aws_default_subnet.default_az1.id
  vpc_security_group_ids = [aws_security_group.ec2_security_group.id]
  key_name               = "ec2_key"

  tags = {
    Name = "docker server"
  }
}
# an empty resource block
resource "null_resource" "name" {

  # ssh into the ec2 instance 
  connection {
    type        = "ssh"
    user        = "ec2-user"
    private_key = file("~/Downloads/ec2_key.pem")
    host        = aws_instance.ec2_instance.public_ip
  }

  # copy the password file for your docker hub account
  # from your computer to the ec2 instance 
  provisioner "file" {
   source      = "~/Downloads/docker_password.txt"
   destination = "/home/ec2-user/docker_password.txt"
  
   }
  # copy the dockerfile from your computer to the ec2 instance 
  provisioner "file" {
    source      = "Dockerfile"
    destination = "/home/ec2-user/Dockerfile"
  }

  # copy the deployment.sh from your computer to the ec2 instance 
  provisioner "file" {
    source      = "deployment.sh"
    destination = "/home/ec2-user/deployment.sh"
  }

  # set permissions and run the build_docker_image.sh file
  provisioner "remote-exec" {
    inline = [
      "sudo chmod +x /home/ec2-user/deployment.sh",
      "sh /home/ec2-user/deployment.sh",
      
    ]
  }

  # wait for ec2 to be created
  depends_on = [aws_instance.ec2_instance]

}
# print the url of the container
output "container_url" {
  value = join("", ["http://", aws_instance.ec2_instance.public_dns])
}
```

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/aa8l7lu7cflvupg3t4hz.png)

**Step 3: Run Terraform Commands**
Run the following Terraform commands to initialize, plan, and apply the configuration.

Open the Terminal in your project folder to run terraform commands

```
terraform init

```


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qb3f6xldgj5l3jyuh1dd.png)

```
terraform plan
```


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/yxbad3jw46l4sieffolr.png)


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/poyae8bc1zj00x8mxdkw.png)


```
terraform apply
```

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rqecv3a5xo27nf2w0vqh.png)


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/t1z9vy4tslca2wbbz92b.png)

Type **yes** to give approval to Terraform to deploy an EC2 instance on AWS, install Docker, build a Docker image using a specified Dockerfile, push that image to Docker Hub and deploy a containerized e-commerce website using the image.


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4abydbkgbkbnznt4zob0.png)

Copy and paste the container url on your web browser to access our website. if everything is done properly, your e-commerce website should appear as shown below 


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/l8dhnswyk305cyri93ut.png)


Also check from docker hub to confirm that the image was pushed to the specified repository


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/kfblwzxrw7bz2thp7j00.png)


Conclusion:
 
By combining Docker for containerization and Terraform for infrastructure automation, you can streamline the deployment of your e-commerce website. This approach provides a lightweight, scalable, and consistent environment for your application.

Clean Up

Run `terraform destroy` command to clean up all infrastructure deployed.

Thank you for Reading