DEV Community

Cover image for Automating the deployment of Docker Containers on Amazon EC2 with Infrastructure as Code (IaC) tool - Terraform
Caleb Yeboah
Caleb Yeboah

Posted on

Automating the deployment of Docker Containers on Amazon EC2 with Infrastructure as Code (IaC) tool - Terraform

Introduction:

Docker has revolutionized the way applications are deployed and run, providing a lightweight and consistent environment across different platforms. Amazon EC2, a popular cloud computing service, allows users to deploy virtual servers in the cloud. In this guide, we'll walk you through the process of pulling a Docker image from Docker Hub and running a container on an EC2 instance using Infrastructure as Code (IaC).

Prerequisites:

Before you begin, ensure you have the following prerequisites in place:

  • An AWS account with the necessary permissions to create EC2 instances.
  • The AWS CLI installed on your local machine.
  • Terraform installed on your local machine.

Step 1: Create an EC2 Key Pair

To securely access your EC2 instance, you'll need an SSH key pair. If you don't have one, create a new key pair using the AWS Management Console or the AWS CLI.

aws ec2 create-key-pair --key-name YourKeyName --query 'KeyMaterial' --output text > YourKeyName.pem
chmod 400 YourKeyName.pem

Enter fullscreen mode Exit fullscreen mode

Alternatively, you can use ssh-keygen to create the key-pair on your computer.

Generate SSH key pair

ssh-keygen -t rsa -b 2048 -f YourKeyName

Enter fullscreen mode Exit fullscreen mode

Set appropriate permissions

chmod 400 YourKeyName
Enter fullscreen mode Exit fullscreen mode

Replace YourKeyName with a preferred name for your key pair.

2. Create a main.tf file

touch main.tf
Enter fullscreen mode Exit fullscreen mode

Update main.tf

Modify the aws_instance resource block in main.tf to include the key_name parameter:

terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 4.16"
    }
  }

  required_version = ">= 1.2.0"
}

provider "aws" {
  region = "us-west-2"
}


resource "aws_vpc" "main" {
  cidr_block = var.vpc_cidr_block

  tags = {
    "Name" = "Production ${var.main_vpc_name}"
  }
}

# Create a subnet
resource "aws_subnet" "web" {
  vpc_id            = aws_vpc.main.id
  cidr_block        = var.web_subnet
  availability_zone = var.subnet_zone

  tags = {
    Name = "Web Subnet"
  }
}


resource "aws_internet_gateway" "my_web_igw" {
  vpc_id = aws_vpc.main.id

  tags = {
    Name = "${var.main_vpc_name} IGW"
  }
}

resource "aws_default_route_table" "main_vpc_default_rt" {
  default_route_table_id = aws_vpc.main.default_route_table_id

  route {
    cidr_block = "0.0.0.0/0"
    gateway_id = aws_internet_gateway.my_web_igw.id
  }

  tags = {
    Name = "my-default-rt"
  }
}

resource "aws_default_security_group" "default_sec_group" {
  vpc_id = aws_vpc.main.id

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

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

  ingress {
    from_port   = 8080
    to_port     = 8080
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }

  ingress {
    from_port   = 5000
    to_port     = 5000
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }

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

  tags = {
    "Name" = "Default Security Group"
  }
}

# Create a new Key Pair
resource "aws_key_pair" "terraform_ssh_pair" {
  key_name = "terraform_rsa" 
  public_key = file(var.ssh_public_key)
}


data "aws_ami" "latest_amazon_linux2" {
  owners = [ "amazon" ]
  most_recent = true
  filter {
    name = "name"
    values = ["amzn2-ami-kernel-*-x86_64-gp2"] 
  }

  filter {
    name = "architecture"
    values = [ "x86_64" ]
  }

}

resource "aws_instance" "web-server" {
  ami                         = data.aws_ami.latest_amazon_linux2.id 
  instance_type               = "t2.micro"
  subnet_id                   = aws_subnet.web.id
  vpc_security_group_ids      = [aws_default_security_group.default_sec_group.id]
  associate_public_ip_address = true
  user_data = file("script.sh")
  key_name                    = aws_key_pair.terraform_ssh_pair.key_name
  tags = {
    "Name" : "My Public Web Server"
  }
}

Enter fullscreen mode Exit fullscreen mode

The user_data is contained in script.sh below. This installs an apache server (to confirm if everything worked correctly). It also installs docker, terraform and runs an nginx docker container as well. You can modify the script to suit your requirements.

#!/bin/bash

# update vm and install server
sudo yum -y update && sudo yum -y install httpd
sudo systemctl start httpd && sudo systemctl enable httpd
sudo echo "<h1>Deployed via Terraform</h1>" > /var/www/html/index.html

# install terraform
sudo yum install -y yum-utils
sudo yum-config-manager --add-repo https://rpm.releases.hashicorp.com/AmazonLinux/hashicorp.repo
sudo yum -y install terraform
sudo touch ~/.bashrc
sudo terraform -install-autocomplete

# install docker
sudo yum -y install docker
sudo systemctl start docker
sudo amazon-linux-extras install docker
sudo service docker start
sudo usermod -aG docker ec2-user
sudo chkconfig docker on
sudo yum install -y git
sudo curl -L https://github.com/docker/compose/releases/download/1.22.0/docker-compose-$(uname -s)-$(uname -m) -o /usr/local/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-compose
sudo systemctl enable docker
sudo docker run -d -p 8080:80 nginx
Enter fullscreen mode Exit fullscreen mode

3. Create a variables.tf file

touch variables.tf
Enter fullscreen mode Exit fullscreen mode

Update variables.tf

variable "vpc_cidr_block" {
  type        = string
  description = "cidr block for the main vpc"
  default     = "10.0.0.0/16"
}

variable "web_subnet" {
  type        = string
  description = "cidr block for the web subnet"
  default     = "10.0.10.0/24"
}

variable "subnet_zone" {
  type        = string
  description = "availability zone for subnet zone"
  # subnet_zone was set as environment variable
}

variable "ssh_public_key" {
  type = string
  description = "public key that permits ssh connection to the ec2 instance"
}

variable "main_vpc_name" {
  type        = string
  description = "name of the main vpc"
}

variable "my_public_ip" {
  description = "my public ip address"
}
Enter fullscreen mode Exit fullscreen mode

4. Create an output.tf file

touch output.tf
Enter fullscreen mode Exit fullscreen mode

Update the output.tf file with the configuration below which provides the public IP address of the instance upon creation.

output "public_ip" {
  description = "The public IP address of the EC2 instance."
  value       = aws_instance.web-server.public_ip
}
Enter fullscreen mode Exit fullscreen mode

5. Usage

  • Follow the previous steps to clone the repository, customize configurations, and run terraform apply.
  • After the Terraform apply, you will find the public IP address and the path to the local SSH private key in the outputs.
  • Use the following command to SSH into the EC2 instance:
ssh -i YourKeyName ec2-user@<public_ip>

Enter fullscreen mode Exit fullscreen mode

Replace YourKeyName with the name of your private key file and with the actual public IP address.

Now, you can securely access your EC2 instance using the generated SSH key pair.

Top comments (0)