Category Archives: Terraform

Learn Terraform with DevOpsRoles.com. Access detailed guides and tutorials to master infrastructure as code and automate your DevOps workflows using Terraform.

Terraform 1.9 features: Explore Enhanced Input Validation and Advanced String Template Functionality

Introduction

Terraform, the popular open-source infrastructure as code (IaC) tool, continues to evolve with its latest release, Terraform 1.9 features. This update brings significant enhancements, particularly in input validation and the introduction of a new string template function. Whether you’re a beginner or an advanced user, understanding these new features can significantly improve your infrastructure management and automation processes.

In this article, we will explore the key features of Terraform 1.9, focusing on enhanced input validation and the new string template function. We’ll provide examples that range from basic to advanced to ensure you can implement these features effectively in your projects.

What’s New in Terraform 1.9 features?

Enhanced Input Validation

What is Input Validation in Terraform?

Input validation in Terraform ensures that the values provided to variables or resources conform to the expected format and constraints. This feature is crucial for maintaining the integrity and reliability of your infrastructure configurations.

The Importance of Enhanced Input Validation

In previous versions of Terraform, input validation was somewhat limited, often requiring external tools or scripts to enforce complex validation rules. With Terraform 1.9, input validation has been significantly improved, allowing for more sophisticated checks directly within your Terraform configuration files.

Key Improvements in Input Validation

  • Complex Conditional Logic: You can now define complex conditional logic within your validation rules, ensuring that only valid combinations of inputs are accepted.
  • Detailed Error Messages: Terraform 1.9 allows you to provide more detailed error messages, making it easier for users to understand what went wrong when a validation fails.
  • Regex Support: Enhanced regex support enables more precise validation of string inputs, which is particularly useful for enforcing naming conventions or ensuring valid formats for URLs, emails, etc.

Example of Enhanced Input Validation

Let’s look at a basic example:

variable "instance_type" {
  type    = string
  default = "t2.micro"

  validation {
    condition     = contains(["t2.micro", "t2.small", "t2.medium"], var.instance_type)
    error_message = "Instance type must be one of t2.micro, t2.small, or t2.medium."
  }
}

In this example, Terraform checks that the provided instance_type is one of the allowed values. If an invalid value is provided, Terraform will output the specified error message.

New String Template Function

Understanding String Templates in Terraform

String templates in Terraform allow you to create dynamic strings by embedding expressions within ${}. This functionality is essential for creating flexible and reusable infrastructure configurations.

What’s New in Terraform 1.9?

Terraform 1.9 features introduce a new string template function that significantly expands the capabilities of string manipulation. This function provides more control over how strings are formatted and allows for more complex string operations.

Key Features of the New String Template Function

  • Advanced String Formatting: You can now format strings with more precision, including padding, alignment, and case conversion.
  • Conditional Expressions: Embed conditional logic within your string templates to create dynamic outputs based on variable values.
  • Enhanced Looping Constructs: Loop through lists or maps within your templates to generate complex configurations dynamically.

Example of the New String Template Function

Here’s an example demonstrating the new string template function:

output "formatted_message" {
  value = format("Hello, %s! Your server count is %d.", var.username, length(var.servers))
}

In this example, the format function dynamically creates a message that includes the username and the number of servers in the servers list.

Practical Use Cases of Terraform 1.9

Implementing Enhanced Input Validation in Real Projects

Scenario 1: Validating IP Addresses

Suppose you have a variable that accepts an IP address. With Terraform 1.9, you can validate that the input is a valid IP address using regex:

variable "ip_address" {
  type = string

  validation {
    condition     = can(regex("^([0-9]{1,3}\\.){3}[0-9]{1,3}$", var.ip_address))
    error_message = "The IP address must be a valid IPv4 address."
  }
}

This validation ensures that only valid IPv4 addresses are accepted, preventing misconfigurations in your network resources.

Advanced String Template Functions for Complex Configurations

Scenario 2: Dynamic Naming Conventions

In large-scale deployments, maintaining consistent naming conventions is crucial. Terraform 1.9 features a new string template function that allows you to enforce and automate naming conventions dynamically:

variable "environment" {
  type = string
  default = "production"
}

variable "component" {
  type = string
  default = "web"
}

output "resource_name" {
  value = format("%s-%s-%s", var.environment, var.component, timestamp())
}

This configuration automatically generates resource names based on the environment, component, and current timestamp, ensuring consistency across your infrastructure.

Frequently Asked Questions

How does enhanced input validation improve Terraform configurations?

Enhanced input validation in Terraform 1.9 improves the accuracy and reliability of your configurations by ensuring that only valid inputs are accepted. This reduces the risk of deployment errors and simplifies troubleshooting by providing clear and specific error messages.

Can I use the new string template function in previous Terraform versions?

No, the new string template function introduced in Terraform 1.9 is not available in earlier versions. To take advantage of this feature, you will need to upgrade to Terraform 1.9.

How do I upgrade to Terraform 1.9?

To upgrade to Terraform 1.9, you can follow the official Terraform upgrade guide. Ensure that you test your configurations in a staging environment before deploying them to production.

What are the benefits of using string templates in Terraform?

String templates in Terraform allow you to create dynamic, reusable configurations. They enable you to embed expressions within strings, which can be used to generate resource names, tags, and other configuration elements based on variable inputs.

Conclusion

Terraform 1.9 features a significant release that enhances the flexibility and robustness of infrastructure as code. The improved input validation and new string template function provide powerful tools for ensuring that your configurations are both accurate and maintainable. Thank you for reading the DevopsRoles page!

By incorporating these features into your projects, you can streamline your deployment processes, reduce errors, and maintain consistent, high-quality infrastructure across your environments. Whether you’re just starting with Terraform or are a seasoned user, the enhancements in Terraform 1.9 are sure to improve your workflow and infrastructure management. Thank you for reading the DevopsRoles page!

Creating a Terraform variable file from an Excel

Introduction

How to Create a Terraform variable file from an Excel. In the world of infrastructure as code (IaC), Terraform stands out as a powerful tool for provisioning and managing infrastructure resources. Often, managing variables for your Terraform scripts can become challenging, especially when dealing with a large number of variables or when collaborating with others.

This blog post will guide you through the process of creating a Terraform variable file from an Excel spreadsheet using Python. By automating this process, you can streamline your infrastructure management workflow and improve collaboration.

Prerequisites

Before we begin, make sure you have the following installed:

Steps to Create a Terraform Variable File from Excel

  • Step 1: Excel Setup
  • Step 2: Python Script to create Terraform variable file from an Excel
  • Step 3: Execute the Script

Step 1: Excel Setup

Start by organizing your variables in an Excel spreadsheet. Create columns for variable names, descriptions, default values, setting value, and any other relevant information.

Setting_value and Variable_name columns will be written to the output file.

In the lab, I only created a sample Excel file for the Terraform VPC variable

Folder structure

  • env.xlsx: Excel file

Step 2: Python Script to create Terraform variable file from an Excel

Write a Python script to read the Excel spreadsheet and generate a Terraform variable file (e.g., terraform2.tfvars).

import pandas as pd
from pathlib import Path
import traceback
from lib.header import get_header

parent = Path(__file__).resolve().parent

# Specify the path to your Excel file
excel_file_path = 'env.xlsx'
var_file_name = 'terraform2.tfvars'

def main():
    try:
        env = get_header()
        sheet_name = env["SHEET_NAME"]

        # Read all sheets into a dictionary of DataFrames
        excel_data = pd.read_excel(parent.joinpath(excel_file_path),sheet_name=None, header=6, dtype=str)
        
        # Access data from a specific sheet
        extracted_data = excel_data[sheet_name]
        col_map = {
            "setting_value": env["SETTING_VALUE"],
            "variable_name": env["VARIABLE_NAME"],
            "auto_gen": env["AUTO_GEN"]
        }
        sheet_data = extracted_data[[col_map[key] for key in col_map if key in col_map]]
        sheet_name_ft = sheet_data.query('Auto_gen == "○"')

        # Display the data from the selected sheet
        print(f"\nData from [{sheet_name}] sheet:\n{sheet_name_ft}")

        # Open and clear content of file
        with open(f"{var_file_name}", "w", encoding="utf-8") as file:
            print(f"{var_file_name} create finish")

        # Write content of excel file to file
        for index, row in sheet_name_ft.iterrows():
            with open(f"{var_file_name}", "a", encoding="utf-8") as file:
                file.write(row['Variable_name'] + ' = ' + '"' + row['Setting_value'] + '"' + '\n')
        print(f"{var_file_name} write finish")
        
    except Exception:
        print(f"Error:")
        traceback.print_exc()

if __name__ == "__main__":
    main()
 

You can change the input Excel file name and output file name at these variables

excel_file_path = 'env.xlsx' 
var_file_name = 'terraform2.tfvars'

Depending on the contents of your Excel file, you can change the variables in the header.py file below

import os

def get_header():
    # Description
    os.environ["DESCRIPTION"] = os.environ.get("DESCRIPTION", "Description")
    # Description
    os.environ["DATA_TYPE"] = os.environ.get("DATA_TYPE", "Data_type")
    # setting value
    os.environ["SETTING_VALUE"] = os.environ.get("SETTING_VALUE", "Setting_value")
    # variablename
    os.environ["VARIABLE_NAME"] = os.environ.get("VARIABLE_NAME", "Variable_name")
    # genaration
    os.environ["AUTO_GEN"] = os.environ.get("AUTO_GEN", "Auto_gen")
    # variable file name location
    os.environ["FILE_NAME_LOCATION"] = os.environ.get("FILE_NAME_LOCATION", "4")

    return os.environ

Step 3: Execute the Script

python3 excel/main.py 

Output

Conclusion

By following these steps, you’ve automated the process of creating a Terraform variable file from an Excel spreadsheet. This not only saves time but also enhances collaboration by providing a standardized way to manage and document your Terraform variables.

Feel free to customize the script based on your specific needs and scale it for more complex variable structures. Thank you for reading the DevopsRoles page!

Terraform deploy cluster web servers in ASG with ELB

#Introduction

In this tutorial, How to deploy cluster web servers in Auto Scaling Group with ELB use Terraform.

What does Elastic Load Balancer mean?

Elastic Load Balancer allows balancing the load across the nodes ASG cluster.ELB also helps to manage SSL cert if your project requires HTTPS access.

Three types of ELB: Classic Load Balancer, Network Load Balancer, and Application Load Balancer.

Auto Scaling Group: allow us to scale up and scaling down the resources based on usage.

Auto Scaling Policy: the key feature of Auto Scaling Group is to scale up or scale down resources based on Auto Scaling Policy we attach.

  • AWS auto scaling Group: Min = 2, Max = 10 and desired_capacity =3
  • User user_data and create a script to install Nginx webserver on amazon linux 2.
  • Auto Scaling Group: Scaling Policy – Target Tracking policy
  • Security group ingress rule to allow access web server from my laptop ? and ELB security group.
  • Elastic load balancer
  • Elastic load balancer security group: ingress rule to allow access web server from my laptop ?

Structure folder and files

Created Cluster_WebServer_ASG_ELB folder contains files as below:

asg_config.tf
auto_scale_group.tf
output.tf
provider.tf
securitygroups.tf
variables.tf
elastic_load_balancer.tf
elb_security_group.tf

On AWS

we created key pair terraform-demo as the picture below

Deploy cluster web servers in ASG with ELB

Create a new file asg_config.tf with the content as below

resource aws_launch_configuration "my_config" {
image_id = var.ami
instance_type = var.instance_type
security_groups=["${aws_security_group.web_sg.id}"]
key_name = "terraform-demo"
 user_data = <<EOF
#!/bin/bash -xe
exec > >(tee /var/log/user-data.log|logger -t user-data -s 2>/dev/console) 2>&1
sudo yum update -y
sudo amazon-linux-extras install nginx1 -y
sudo su -c "/bin/echo 'My Site: DevopsRoles.com' >/usr/share/nginx/html/index.html"
instance_ip=`curl http://169.254.169.254/latest/meta-data/local-ipv4`
sudo su -c "echo $instance_ip >>/usr/share/nginx/html/index.html"
sudo systemctl start nginx
sudo systemctl enable  nginx
EOF
lifecycle {
create_before_destroy = true
}
}

Create a new file auto_scale_group.tf with the content as below

resource "aws_autoscaling_group" "first_asg" {
	launch_configuration = aws_launch_configuration.my_config.id
	availability_zones = "${var.azs}"
    
	min_size = 2
	max_size = 10
	desired_capacity = 3
	tag {
		key = "Name"
		value = "terraform-asg"
		propagate_at_launch = true  
	}
}

New file elastic_load_balancer.tf with the content as below

resource "aws_elb" "first_elb" {
    name = "terraform-elb"
    availability_zones = var.azs
    security_groups=[ aws_security_group.elb_sg.id ]
    listener {
        lb_port=80
        lb_protocol ="http"
        instance_port = var.server_port
        instance_protocol= "http"
    }
    health_check {
        healthy_threshold = 2
        unhealthy_threshold = 2
        timeout=3
        interval = 30
        target = "HTTP:${var.server_port}/"
    }
}

Create a new file elb_security_group.tf with the content as below

resource "aws_security_group" "elb_sg" { 

    ingress {
        from_port = var.server_port
        to_port = var.server_port
        protocol = "tcp"
        cidr_blocks = [ var.my_public_ip ]
    }

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

Create a new file output.tf with the content as below

output "elb_endpoint" {
    value = [ "${aws_elb.first_elb.arn}"]
}

provider.tf file

provider "aws" {
        region = var.region
}

securitygroups.tf file

resource "aws_security_group" "web_sg" { 

    ingress {
        from_port = var.server_port
        to_port = var.server_port
        protocol = "tcp"
        cidr_blocks = [ var.my_public_ip ]
    }

    ingress {
        from_port = var.ssh_port
        to_port = var.ssh_port
        protocol = "tcp"
        cidr_blocks = [ var.my_public_ip ]
    }

    ingress {
        from_port = var.server_port
        to_port = var.server_port
        protocol = "tcp"
        security_groups = [ aws_security_group.elb_sg.id ]
    } 
       
egress {
    from_port       = 0
    to_port         = 0
    protocol        = "-1"
    cidr_blocks     = ["0.0.0.0/0"]
  }    
}

variables.tf file

variable "region" {
	description = " Define the AWS region "
	default = "us-west-2"
}
variable "server_port" {
	description = "http service listen"
	default = "80"
}

variable "ssh_port" {
	description = "ssh to server"
	default = "22"
}
variable "instance_type" { 
	description = "AWS ec2 instance type"
	default="t2.micro"
}
variable "my_public_ip" {
	description = "My laptop public IP ..." 
        default = "116.110.26.150/32"
}
variable "ami" {
    description = "amazon machine image"
        default = "ami-0c2d06d50ce30b442"
}

variable "azs" {
    default = [ "us-west-2a", "us-west-2b", "us-west-2c" ]
}

First, we run below to initialize, download the plugins and validate the terraform syntax…

terraform init
terraform validate

Applying a template

$ terraform apply

Conclusion

You have to deploy cluster web servers in ASG with ELB use Terraform. I hope will this your helpful. Thank you for reading the DevopsRoles page!

Terraform deploy cluster web servers in Auto Scaling Group

#Introduction

In this tutorial, How to deploy cluster web servers use Terraform. Now, let’s go Terraform deploy cluster web servers in Auto Scaling Group

  • AWS auto scaling Group: Min = 2, Max = 10 and desired_capacity =3
  • User user_data and create a script to install Nginx webserver on amazon linux 2.
  • Auto Scaling Group: Scaling Policy – Target Tracking policy
  • Security group ingress rule to allow access web server from my laptop ?

Structure folder and files Terraform deploy cluster web servers in Auto Scaling Group

Created Cluster_WebServer_ASG folder contains files as below:

asg_config.tf
auto_scale_group.tf
auto_scale_policy.tf
output.tf
provider.tf
securitygroups.tf
variables.tf

On AWS

we created key pair terraform-demo as the picture below

Deploy cluster web servers in Auto Scaling Group

Create a new file asg_config.tf with the content as below

resource aws_launch_configuration "my_config" {
name = "webserver-launch"
image_id = var.ami
instance_type = var.instance_type
security_groups=["${aws_security_group.web_sg.id}"]
key_name = "terraform-demo"
 user_data = <<EOF
#!/bin/bash -xe
exec > >(tee /var/log/user-data.log|logger -t user-data -s 2>/dev/console) 2>&1
sudo yum update -y
sudo amazon-linux-extras install nginx1 -y
sudo su -c "/bin/echo 'My Site: DevopsRoles.com' >/usr/share/nginx/html/index.html"
instance_ip=`curl http://169.254.169.254/latest/meta-data/local-ipv4`
sudo su -c "echo $instance_ip >>/usr/share/nginx/html/index.html"
sudo systemctl start nginx
sudo systemctl enable  nginx
EOF
}

Create a new file auto_scale_group.tf with the content as below

resource "aws_autoscaling_group" "first_asg" {
	launch_configuration = aws_launch_configuration.my_config.id
	availability_zones = "${var.azs}"
    
	min_size = 2
	max_size = 10
	desired_capacity = 3
	tag {
		key = "Name"
		value = "terraform-asg"
		propagate_at_launch = true  
	}
}

New file auto_scale_policy.tf with the content as below

resource "aws_autoscaling_policy" "my_asg_policy" {
  name = "webservers_autoscale_policy"
  policy_type = "TargetTrackingScaling"
  autoscaling_group_name = aws_autoscaling_group.first_asg.name

  target_tracking_configuration {
  predefined_metric_specification {
    predefined_metric_type = "ASGAverageCPUUtilization"
  }
  target_value = "75"
  }

}

Create new a provider.tf the content as below

provider "aws" {
        region = var.region
}

Create a new file output.tf with the content as below

output "asg_arn" {
    value = [ "${aws_autoscaling_group.first_asg.arn}"]
}

Create new file variables.tf with the content as below

variable "region" {
	description = " Define the AWS region "
	default = "us-west-2"
}
variable "server_port" {
	description = "http service listen"
	default = "80"
}

variable "ssh_port" {
	description = "ssh to server"
	default = "22"
}
variable "instance_type" { 
	description = "AWS ec2 instance type"
	default="t2.micro"
}
variable "my_public_ip" {
	description = "My laptop public IP ..." 
        default = "116.110.26.150/32"
}
variable "ami" {
    description = "amazon machine image"
        default = "ami-0c2d06d50ce30b442"
}

variable "azs" {
    default = [ "us-west-2a", "us-west-2b", "us-west-2c" ]
}

new file securitygroups.tf with the content as below

resource "aws_security_group" "web_sg" { 

    ingress {
        from_port = var.server_port
        to_port = var.server_port
        protocol = "tcp"
        cidr_blocks = [ var.my_public_ip ]
    }

    ingress {
        from_port = var.ssh_port
        to_port = var.ssh_port
        protocol = "tcp"
        cidr_blocks = [ var.my_public_ip ]
    }
egress {
    from_port       = 0
    to_port         = 0
    protocol        = "-1"
    cidr_blocks     = ["0.0.0.0/0"]
  }    
}

First, we run below to initialize, download the plugins and validate the terraform syntax…

terraform init
terraform validate

The output terminal is as follows

Applying a template

$ terraform apply

The output terminal is as below

C:\Users\HuuPV\Desktop\Terraform\Cluster_WebServer_ASG>terraform apply

Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with
the following symbols:
  + create

Terraform will perform the following actions:

  # aws_autoscaling_group.first_asg will be created
  + resource "aws_autoscaling_group" "first_asg" {
      + arn                       = (known after apply)
      + availability_zones        = [
          + "us-west-2a",
          + "us-west-2b",
          + "us-west-2c",
        ]
      + default_cooldown          = (known after apply)
      + desired_capacity          = 3
      + force_delete              = false
      + force_delete_warm_pool    = false
      + health_check_grace_period = 300
      + health_check_type         = (known after apply)
      + id                        = (known after apply)
      + launch_configuration      = (known after apply)
      + max_size                  = 10
      + metrics_granularity       = "1Minute"
      + min_size                  = 2
      + name                      = (known after apply)
      + name_prefix               = (known after apply)
      + protect_from_scale_in     = false
      + service_linked_role_arn   = (known after apply)
      + vpc_zone_identifier       = (known after apply)
      + wait_for_capacity_timeout = "10m"

      + tag {
          + key                 = "Name"
          + propagate_at_launch = true
          + value               = "terraform-asg"
        }
    }

  # aws_autoscaling_policy.my_asg_policy will be created
  + resource "aws_autoscaling_policy" "my_asg_policy" {
      + arn                     = (known after apply)
      + autoscaling_group_name  = (known after apply)
      + id                      = (known after apply)
      + metric_aggregation_type = (known after apply)
      + name                    = "webservers_autoscale_policy"
      + policy_type             = "TargetTrackingScaling"

      + target_tracking_configuration {
          + disable_scale_in = false
          + target_value     = 60

          + predefined_metric_specification {
              + predefined_metric_type = "ASGAverageCPUUtilization"
            }
        }
    }

  # aws_launch_configuration.my_config will be created
  + resource "aws_launch_configuration" "my_config" {
      + arn                         = (known after apply)
      + associate_public_ip_address = false
      + ebs_optimized               = (known after apply)
      + enable_monitoring           = true
      + id                          = (known after apply)
      + image_id                    = "ami-0c2d06d50ce30b442"
      + instance_type               = "t2.micro"
      + key_name                    = "terraform-demo"
      + name                        = "webserver-launch"
      + name_prefix                 = (known after apply)
      + security_groups             = (known after apply)
      + user_data                   = "e210837ad2017cf0971bc0ed4af86edab9d8a10d"

      + ebs_block_device {
          + delete_on_termination = (known after apply)
          + device_name           = (known after apply)
          + encrypted             = (known after apply)
          + iops                  = (known after apply)
          + no_device             = (known after apply)
          + snapshot_id           = (known after apply)
          + throughput            = (known after apply)
          + volume_size           = (known after apply)
          + volume_type           = (known after apply)
        }

      + metadata_options {
          + http_endpoint               = (known after apply)
          + http_put_response_hop_limit = (known after apply)
          + http_tokens                 = (known after apply)
        }

      + root_block_device {
          + delete_on_termination = (known after apply)
          + encrypted             = (known after apply)
          + iops                  = (known after apply)
          + throughput            = (known after apply)
          + volume_size           = (known after apply)
          + volume_type           = (known after apply)
        }
    }

  # aws_security_group.web_sg will be created
  + resource "aws_security_group" "web_sg" {
      + arn                    = (known after apply)
      + description            = "Managed by Terraform"
      + egress                 = [
          + {
              + cidr_blocks      = [
                  + "0.0.0.0/0",
                ]
              + description      = ""
              + from_port        = 0
              + ipv6_cidr_blocks = []
              + prefix_list_ids  = []
              + protocol         = "-1"
              + security_groups  = []
              + self             = false
              + to_port          = 0
            },
        ]
      + id                     = (known after apply)
      + ingress                = [
          + {
              + cidr_blocks      = [
                  + "116.110.26.150/32",
                ]
              + description      = ""
              + from_port        = 22
              + ipv6_cidr_blocks = []
              + prefix_list_ids  = []
              + protocol         = "tcp"
              + security_groups  = []
              + self             = false
              + to_port          = 22
            },
          + {
              + cidr_blocks      = [
                  + "116.110.26.150/32",
                ]
              + description      = ""
              + from_port        = 80
              + ipv6_cidr_blocks = []
              + prefix_list_ids  = []
              + protocol         = "tcp"
              + security_groups  = []
              + self             = false
              + to_port          = 80
            },
        ]
      + name                   = (known after apply)
      + name_prefix            = (known after apply)
      + owner_id               = (known after apply)
      + revoke_rules_on_delete = false
      + tags_all               = (known after apply)
      + vpc_id                 = (known after apply)
    }

Plan: 4 to add, 0 to change, 0 to destroy.

Changes to Outputs:
  + asg_arn = [
      + (known after apply),
    ]

Do you want to perform these actions?
  Terraform will perform the actions described above.
  Only 'yes' will be accepted to approve.

  Enter a value: yes

aws_security_group.web_sg: Creating...
aws_security_group.web_sg: Creation complete after 8s [id=sg-083d582a5691c56d9]
aws_launch_configuration.my_config: Creating...
aws_launch_configuration.my_config: Creation complete after 2s [id=webserver-launch]
aws_autoscaling_group.first_asg: Creating...
aws_autoscaling_group.first_asg: Still creating... [10s elapsed]
aws_autoscaling_group.first_asg: Still creating... [21s elapsed]
aws_autoscaling_group.first_asg: Still creating... [31s elapsed]
aws_autoscaling_group.first_asg: Still creating... [41s elapsed]
aws_autoscaling_group.first_asg: Creation complete after 45s [id=terraform-20211010125900499300000002]
aws_autoscaling_policy.my_asg_policy: Creating...
aws_autoscaling_policy.my_asg_policy: Creation complete after 2s [id=webservers_autoscale_policy]

Apply complete! Resources: 4 added, 0 changed, 0 destroyed.

Outputs:

asg_arn = [
  "arn:aws:autoscaling:us-west-2:633602660500:autoScalingGroup:2b023a9d-a66c-464e-9cb0-80d9eef00e33:autoScalingGroupName/terraform-20211010125900499300000002",
]

Result on EC2 AWS

3 Instance EC2

Auto Scaling: Launch configurations

Auto Scaling groups

Conclusion

You have to deploy cluster web servers in the Auto Scaling Group. I hope will this your helpful. Thank you for reading the DevopsRoles page!

Terraform deploy cluster web servers

#Introduction

In this tutorial, How to deploy cluster web servers use Terraform. For example, I will use Terraform deploy cluster web servers.

  • Create EC2 instance
  • Terraform parameter Count: I will create three EC2 instance use Count parameter
  • User user_data and create a script to install Nginx webserver on amazon linux 2.
  • Security group ingress rule to allow access web server from my laptop ?

Structure folder and files of Terraform deploy cluster web servers

Created Cluster-WebServer folder contains files as below:

main.tf
output.tf
provider.tf
securitygroups.tf
variables.tf

Deploy cluster Web Servers with Terraform

Create new file main.tf with the content as below

resource "aws_instance" "devopsroles-lab01" {
 count = 3
 ami = var.ami
 instance_type = var.instance_type
 vpc_security_group_ids = ["${aws_security_group.webserver_security_group.id}"]
 tags = {
	 Name = "DevopsRoles-${count.index}"
 }
 key_name = "terraform-demo"
 user_data = <<EOF
#!/bin/bash -xe
exec > >(tee /var/log/user-data.log|logger -t user-data -s 2>/dev/console) 2>&1
sudo yum update -y
sudo amazon-linux-extras install nginx1 -y
sudo su -c "/bin/echo 'My Site: DevopsRoles.com' >/usr/share/nginx/html/index.html"
instance_ip=`curl http://169.254.169.254/latest/meta-data/local-ipv4`
sudo su -c "echo $instance_ip >>/usr/share/nginx/html/index.html"
sudo systemctl start nginx
sudo systemctl enable  nginx
EOF
}

On AWS, we created key pair terraform-demo as the picture below

Create a new file provider.tf with the content as below

provider "aws" {
        region = var.region
}

New file securitygroups.tf with the content as below

resource "aws_security_group" "webserver_security_group" { 

    ingress {
        from_port = var.server_port
        to_port = var.server_port
        protocol = "tcp"
        cidr_blocks = [ var.my_public_ip ]
    }

    ingress {
        from_port = var.ssh_port
        to_port = var.ssh_port
        protocol = "tcp"
        cidr_blocks = [ var.my_public_ip ]
    }
egress {
    from_port       = 0
    to_port         = 0
    protocol        = "-1"
    cidr_blocks     = ["0.0.0.0/0"]
  }    
}

Create a new file output.tf with the content as below

output "public_ip" {
    value = [ "${aws_instance.devopsroles-lab01.*.public_ip}"]
}

Create new file variables.tf with the content as below

variable "region" {
	description = " Define the AWS region "
	default = "us-west-2"
}
variable "server_port" {
	description = "http service listen"
	default = "80"
}

variable "ssh_port" {
	description = "ssh to server"
	default = "22"
}
variable "instance_type" { 
	description = "AWS ec2 instance type"
	default="t2.micro"
}
variable "my_public_ip" {
	description = "My laptop public IP ..." 
        default = "116.110.26.150/32"
}
variable "ami" {
description = "amazon machine image"
default = "ami-0c2d06d50ce30b442"
}

variable "azs" {
default = [ "us-east-2a", "us-east-2b", "us-east-2c"]
}

First, we run below to initialize, download the plugins and validate the terraform syntax…

terraform init
terraform validate

The output terminal is as follows

Applying a template

$ terraform apply

The output terminal is as below

C:\Users\HuuPV\Desktop\Terraform\Cluster_WebServer>set AWS_PROFILE=devopsroles-demo
C:\Users\HuuPV\Desktop\Terraform\Cluster_WebServer>terraform apply

Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with
the following symbols:
  + create

Terraform will perform the following actions:

  # aws_instance.devopsroles-lab01[0] will be created
  + resource "aws_instance" "devopsroles-lab01" {
      + ami                                  = "ami-0c2d06d50ce30b442"
      + arn                                  = (known after apply)
      + associate_public_ip_address          = (known after apply)
      + availability_zone                    = (known after apply)
      + cpu_core_count                       = (known after apply)
      + cpu_threads_per_core                 = (known after apply)
      + disable_api_termination              = (known after apply)
      + ebs_optimized                        = (known after apply)
      + get_password_data                    = false
      + host_id                              = (known after apply)
      + id                                   = (known after apply)
      + instance_initiated_shutdown_behavior = (known after apply)
      + instance_state                       = (known after apply)
      + instance_type                        = "t2.micro"
      + ipv6_address_count                   = (known after apply)
      + ipv6_addresses                       = (known after apply)
      + key_name                             = "terraform-demo"
      + monitoring                           = (known after apply)
      + outpost_arn                          = (known after apply)
      + password_data                        = (known after apply)
      + placement_group                      = (known after apply)
      + primary_network_interface_id         = (known after apply)
      + private_dns                          = (known after apply)
      + private_ip                           = (known after apply)
      + public_dns                           = (known after apply)
      + public_ip                            = (known after apply)
      + secondary_private_ips                = (known after apply)
      + security_groups                      = (known after apply)
      + source_dest_check                    = true
      + subnet_id                            = (known after apply)
      + tags                                 = {
          + "Name" = "DevopsRoles-0"
        }
      + tags_all                             = {
          + "Name" = "DevopsRoles-0"
        }
      + tenancy                              = (known after apply)
      + user_data                            = "e210837ad2017cf0971bc0ed4af86edab9d8a10d"
      + user_data_base64                     = (known after apply)
      + vpc_security_group_ids               = (known after apply)

      + capacity_reservation_specification {
          + capacity_reservation_preference = (known after apply)

          + capacity_reservation_target {
              + capacity_reservation_id = (known after apply)
            }
        }

      + ebs_block_device {
          + delete_on_termination = (known after apply)
          + device_name           = (known after apply)
          + encrypted             = (known after apply)
          + iops                  = (known after apply)
          + kms_key_id            = (known after apply)
          + snapshot_id           = (known after apply)
          + tags                  = (known after apply)
          + throughput            = (known after apply)
          + volume_id             = (known after apply)
          + volume_size           = (known after apply)
          + volume_type           = (known after apply)
        }

      + enclave_options {
          + enabled = (known after apply)
        }

      + ephemeral_block_device {
          + device_name  = (known after apply)
          + no_device    = (known after apply)
          + virtual_name = (known after apply)
        }

      + metadata_options {
          + http_endpoint               = (known after apply)
          + http_put_response_hop_limit = (known after apply)
          + http_tokens                 = (known after apply)
        }

      + network_interface {
          + delete_on_termination = (known after apply)
          + device_index          = (known after apply)
          + network_interface_id  = (known after apply)
        }

      + root_block_device {
          + delete_on_termination = (known after apply)
          + device_name           = (known after apply)
          + encrypted             = (known after apply)
          + iops                  = (known after apply)
          + kms_key_id            = (known after apply)
          + tags                  = (known after apply)
          + throughput            = (known after apply)
          + volume_id             = (known after apply)
          + volume_size           = (known after apply)
          + volume_type           = (known after apply)
        }
    }

  # aws_instance.devopsroles-lab01[1] will be created
  + resource "aws_instance" "devopsroles-lab01" {
      + ami                                  = "ami-0c2d06d50ce30b442"
      + arn                                  = (known after apply)
      + associate_public_ip_address          = (known after apply)
      + availability_zone                    = (known after apply)
      + cpu_core_count                       = (known after apply)
      + cpu_threads_per_core                 = (known after apply)
      + disable_api_termination              = (known after apply)
      + ebs_optimized                        = (known after apply)
      + get_password_data                    = false
      + host_id                              = (known after apply)
      + id                                   = (known after apply)
      + instance_initiated_shutdown_behavior = (known after apply)
      + instance_state                       = (known after apply)
      + instance_type                        = "t2.micro"
      + ipv6_address_count                   = (known after apply)
      + ipv6_addresses                       = (known after apply)
      + key_name                             = "terraform-demo"
      + monitoring                           = (known after apply)
      + outpost_arn                          = (known after apply)
      + password_data                        = (known after apply)
      + placement_group                      = (known after apply)
      + primary_network_interface_id         = (known after apply)
      + private_dns                          = (known after apply)
      + private_ip                           = (known after apply)
      + public_dns                           = (known after apply)
      + public_ip                            = (known after apply)
      + secondary_private_ips                = (known after apply)
      + security_groups                      = (known after apply)
      + source_dest_check                    = true
      + subnet_id                            = (known after apply)
      + tags                                 = {
          + "Name" = "DevopsRoles-1"
        }
      + tags_all                             = {
          + "Name" = "DevopsRoles-1"
        }
      + tenancy                              = (known after apply)
      + user_data                            = "e210837ad2017cf0971bc0ed4af86edab9d8a10d"
      + user_data_base64                     = (known after apply)
      + vpc_security_group_ids               = (known after apply)

      + capacity_reservation_specification {
          + capacity_reservation_preference = (known after apply)

          + capacity_reservation_target {
              + capacity_reservation_id = (known after apply)
            }
        }

      + ebs_block_device {
          + delete_on_termination = (known after apply)
          + device_name           = (known after apply)
          + encrypted             = (known after apply)
          + iops                  = (known after apply)
          + kms_key_id            = (known after apply)
          + snapshot_id           = (known after apply)
          + tags                  = (known after apply)
          + throughput            = (known after apply)
          + volume_id             = (known after apply)
          + volume_size           = (known after apply)
          + volume_type           = (known after apply)
        }

      + enclave_options {
          + enabled = (known after apply)
        }

      + ephemeral_block_device {
          + device_name  = (known after apply)
          + no_device    = (known after apply)
          + virtual_name = (known after apply)
        }

      + metadata_options {
          + http_endpoint               = (known after apply)
          + http_put_response_hop_limit = (known after apply)
          + http_tokens                 = (known after apply)
        }

      + network_interface {
          + delete_on_termination = (known after apply)
          + device_index          = (known after apply)
          + network_interface_id  = (known after apply)
        }

      + root_block_device {
          + delete_on_termination = (known after apply)
          + device_name           = (known after apply)
          + encrypted             = (known after apply)
          + iops                  = (known after apply)
          + kms_key_id            = (known after apply)
          + tags                  = (known after apply)
          + throughput            = (known after apply)
          + volume_id             = (known after apply)
          + volume_size           = (known after apply)
          + volume_type           = (known after apply)
        }
    }

  # aws_instance.devopsroles-lab01[2] will be created
  + resource "aws_instance" "devopsroles-lab01" {
      + ami                                  = "ami-0c2d06d50ce30b442"
      + arn                                  = (known after apply)
      + associate_public_ip_address          = (known after apply)
      + availability_zone                    = (known after apply)
      + cpu_core_count                       = (known after apply)
      + cpu_threads_per_core                 = (known after apply)
      + disable_api_termination              = (known after apply)
      + ebs_optimized                        = (known after apply)
      + get_password_data                    = false
      + host_id                              = (known after apply)
      + id                                   = (known after apply)
      + instance_initiated_shutdown_behavior = (known after apply)
      + instance_state                       = (known after apply)
      + instance_type                        = "t2.micro"
      + ipv6_address_count                   = (known after apply)
      + ipv6_addresses                       = (known after apply)
      + key_name                             = "terraform-demo"
      + monitoring                           = (known after apply)
      + outpost_arn                          = (known after apply)
      + password_data                        = (known after apply)
      + placement_group                      = (known after apply)
      + primary_network_interface_id         = (known after apply)
      + private_dns                          = (known after apply)
      + private_ip                           = (known after apply)
      + public_dns                           = (known after apply)
      + public_ip                            = (known after apply)
      + secondary_private_ips                = (known after apply)
      + security_groups                      = (known after apply)
      + source_dest_check                    = true
      + subnet_id                            = (known after apply)
      + tags                                 = {
          + "Name" = "DevopsRoles-2"
        }
      + tags_all                             = {
          + "Name" = "DevopsRoles-2"
        }
      + tenancy                              = (known after apply)
      + user_data                            = "e210837ad2017cf0971bc0ed4af86edab9d8a10d"
      + user_data_base64                     = (known after apply)
      + vpc_security_group_ids               = (known after apply)

      + capacity_reservation_specification {
          + capacity_reservation_preference = (known after apply)

          + capacity_reservation_target {
              + capacity_reservation_id = (known after apply)
            }
        }

      + ebs_block_device {
          + delete_on_termination = (known after apply)
          + device_name           = (known after apply)
          + encrypted             = (known after apply)
          + iops                  = (known after apply)
          + kms_key_id            = (known after apply)
          + snapshot_id           = (known after apply)
          + tags                  = (known after apply)
          + throughput            = (known after apply)
          + volume_id             = (known after apply)
          + volume_size           = (known after apply)
          + volume_type           = (known after apply)
        }

      + enclave_options {
          + enabled = (known after apply)
        }

      + ephemeral_block_device {
          + device_name  = (known after apply)
          + no_device    = (known after apply)
          + virtual_name = (known after apply)
        }

      + metadata_options {
          + http_endpoint               = (known after apply)
          + http_put_response_hop_limit = (known after apply)
          + http_tokens                 = (known after apply)
        }

      + network_interface {
          + delete_on_termination = (known after apply)
          + device_index          = (known after apply)
          + network_interface_id  = (known after apply)
        }

      + root_block_device {
          + delete_on_termination = (known after apply)
          + device_name           = (known after apply)
          + encrypted             = (known after apply)
          + iops                  = (known after apply)
          + kms_key_id            = (known after apply)
          + tags                  = (known after apply)
          + throughput            = (known after apply)
          + volume_id             = (known after apply)
          + volume_size           = (known after apply)
          + volume_type           = (known after apply)
        }
    }

  # aws_security_group.webserver_security_group will be created
  + resource "aws_security_group" "webserver_security_group" {
      + arn                    = (known after apply)
      + description            = "Managed by Terraform"
      + egress                 = [
          + {
              + cidr_blocks      = [
                  + "0.0.0.0/0",
                ]
              + description      = ""
              + from_port        = 0
              + ipv6_cidr_blocks = []
              + prefix_list_ids  = []
              + protocol         = "-1"
              + security_groups  = []
              + self             = false
              + to_port          = 0
            },
        ]
      + id                     = (known after apply)
      + ingress                = [
          + {
              + cidr_blocks      = [
                  + "116.110.26.150/32",
                ]
              + description      = ""
              + from_port        = 22
              + ipv6_cidr_blocks = []
              + prefix_list_ids  = []
              + protocol         = "tcp"
              + security_groups  = []
              + self             = false
              + to_port          = 22
            },
          + {
              + cidr_blocks      = [
                  + "116.110.26.150/32",
                ]
              + description      = ""
              + from_port        = 80
              + ipv6_cidr_blocks = []
              + prefix_list_ids  = []
              + protocol         = "tcp"
              + security_groups  = []
              + self             = false
              + to_port          = 80
            },
        ]
      + name                   = (known after apply)
      + name_prefix            = (known after apply)
      + owner_id               = (known after apply)
      + revoke_rules_on_delete = false
      + tags_all               = (known after apply)
      + vpc_id                 = (known after apply)
    }

Plan: 4 to add, 0 to change, 0 to destroy.

Changes to Outputs:
  + public_ip = [
      + [
          + (known after apply),
          + (known after apply),
          + (known after apply),
        ],
    ]

Do you want to perform these actions?
  Terraform will perform the actions described above.
  Only 'yes' will be accepted to approve.

  Enter a value: yes

aws_security_group.webserver_security_group: Creating...
aws_security_group.webserver_security_group: Creation complete after 8s [id=sg-05fe82255b21a2c8b]
aws_instance.devopsroles-lab01[1]: Creating...
aws_instance.devopsroles-lab01[0]: Creating...
aws_instance.devopsroles-lab01[2]: Creating...
aws_instance.devopsroles-lab01[0]: Still creating... [10s elapsed]
aws_instance.devopsroles-lab01[2]: Still creating... [10s elapsed]
aws_instance.devopsroles-lab01[1]: Still creating... [10s elapsed]
aws_instance.devopsroles-lab01[2]: Still creating... [20s elapsed]
aws_instance.devopsroles-lab01[0]: Still creating... [20s elapsed]
aws_instance.devopsroles-lab01[1]: Still creating... [20s elapsed]
aws_instance.devopsroles-lab01[1]: Still creating... [30s elapsed]
aws_instance.devopsroles-lab01[2]: Still creating... [30s elapsed]
aws_instance.devopsroles-lab01[0]: Still creating... [30s elapsed]
aws_instance.devopsroles-lab01[0]: Still creating... [40s elapsed]
aws_instance.devopsroles-lab01[1]: Still creating... [40s elapsed]
aws_instance.devopsroles-lab01[2]: Still creating... [40s elapsed]
aws_instance.devopsroles-lab01[0]: Creation complete after 42s [id=i-0ade24acdfd72944c]
aws_instance.devopsroles-lab01[1]: Creation complete after 42s [id=i-00daeeee26f9dcd20]
aws_instance.devopsroles-lab01[2]: Creation complete after 43s [id=i-0b77263afa926a374]

Apply complete! Resources: 4 added, 0 changed, 0 destroyed.

Outputs:

public_ip = [
  [
    "54.189.128.5",
    "52.27.217.183",
    "54.201.82.158",
  ],
]

C:\Users\HuuPV\Desktop\Terraform\Cluster_WebServer>

The result, on EC2 AWS

Open Browser, type http://IP_Public_EC2 as below

Webserver 1

Webserver 2

Webserver 3

Conclusion

You have use Terraform deploy cluster web servers. I hope will this your helpful. Thank you for reading the DevopsRoles page!

Deploy a Web Server with Terraform

#Introduction

In this tutorial, How to deploy a Web Server with Terraform.

  • Create EC2 instance
  • User user_data and create a script to install Nginx webserver on amazon linux 2.
  • Security group ingress rule to allow access web server from my laptop ?

Structure folder and files deploy a Web Server with Terraform

Created Single-WebServer folder contains files as below:

main.tf
output.tf
provider.tf
securitygroups.tf

Deploy a Web Server with Terraform

Create new file main.tf with the content as below

resource "aws_instance" "devopsroles-lab01" {
 ami = "ami-0c2d06d50ce30b442"
 instance_type = "t2.micro"
 vpc_security_group_ids = ["${aws_security_group.webserver_security_group.id}"]
 tags = {
	 Name = "DevopsRoles-Webserver"
 }
 key_name = "terraform-demo"
 user_data = <<EOF
#!/bin/bash -xe
exec > >(tee /var/log/user-data.log|logger -t user-data -s 2>/dev/console) 2>&1
sudo yum update -y
sudo amazon-linux-extras install nginx1 -y
sudo su -c "/bin/echo 'My Site: DevopsRoles.com' >/usr/share/nginx/html/index.html"
instance_ip=`curl http://169.254.169.254/latest/meta-data/local-ipv4`
sudo su -c "echo $instance_ip >>/usr/share/nginx/html/index.html"
sudo systemctl start nginx
sudo systemctl enable  nginx
EOF
}

On AWS, we created key pair terraform-demo as the picture below

Create a new file provider.tf with the content as below

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

New file securitygroups.tf with the content as below

resource "aws_security_group" "webserver_security_group" { 

    ingress {
        from_port = 22
        to_port = 22
        protocol = "tcp"
        cidr_blocks = [ "116.110.26.150/32"]
    }
    ingress {
        from_port = 80
        to_port = 80
        protocol = "tcp"
        cidr_blocks = [ "116.110.26.150/32"]
    }
    
egress {
    from_port       = 0
    to_port         = 0
    protocol        = "-1"
    cidr_blocks     = ["0.0.0.0/0"]
  }    
}

Create a new file output.tf with the content as below

output "public_ip" {
    value = "${aws_instance.devopsroles-lab01.public_ip}"
}

First, we run below to initialize, download the plugins and validate the terraform syntax…

terraform init
terraform validate

The output terminal is as follows

Applying a template

$ terraform apply

The output terminal is as below

C:\Users\HuuPV\Desktop\Terraform\Single-WebServer>terraform apply

Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with
the following symbols:
  + create

Terraform will perform the following actions:

  # aws_instance.devopsroles-lab01 will be created
  + resource "aws_instance" "devopsroles-lab01" {
      + ami                                  = "ami-0c2d06d50ce30b442"
      + arn                                  = (known after apply)
      + associate_public_ip_address          = (known after apply)
      + availability_zone                    = (known after apply)
      + cpu_core_count                       = (known after apply)
      + cpu_threads_per_core                 = (known after apply)
      + disable_api_termination              = (known after apply)
      + ebs_optimized                        = (known after apply)
      + get_password_data                    = false
      + host_id                              = (known after apply)
      + id                                   = (known after apply)
      + instance_initiated_shutdown_behavior = (known after apply)
      + instance_state                       = (known after apply)
      + instance_type                        = "t2.micro"
      + ipv6_address_count                   = (known after apply)
      + ipv6_addresses                       = (known after apply)
      + key_name                             = "terraform-demo"
      + monitoring                           = (known after apply)
      + outpost_arn                          = (known after apply)
      + password_data                        = (known after apply)
      + placement_group                      = (known after apply)
      + primary_network_interface_id         = (known after apply)
      + private_dns                          = (known after apply)
      + private_ip                           = (known after apply)
      + public_dns                           = (known after apply)
      + public_ip                            = (known after apply)
      + secondary_private_ips                = (known after apply)
      + security_groups                      = (known after apply)
      + source_dest_check                    = true
      + subnet_id                            = (known after apply)
      + tags                                 = {
          + "Name" = "DevopsRoles-Webserver"
        }
      + tags_all                             = {
          + "Name" = "DevopsRoles-Webserver"
        }
      + tenancy                              = (known after apply)
      + user_data                            = "e210837ad2017cf0971bc0ed4af86edab9d8a10d"
      + user_data_base64                     = (known after apply)
      + vpc_security_group_ids               = (known after apply)

      + capacity_reservation_specification {
          + capacity_reservation_preference = (known after apply)

          + capacity_reservation_target {
              + capacity_reservation_id = (known after apply)
            }
        }

      + ebs_block_device {
          + delete_on_termination = (known after apply)
          + device_name           = (known after apply)
          + encrypted             = (known after apply)
          + iops                  = (known after apply)
          + kms_key_id            = (known after apply)
          + snapshot_id           = (known after apply)
          + tags                  = (known after apply)
          + throughput            = (known after apply)
          + volume_id             = (known after apply)
          + volume_size           = (known after apply)
          + volume_type           = (known after apply)
        }

      + enclave_options {
          + enabled = (known after apply)
        }

      + ephemeral_block_device {
          + device_name  = (known after apply)
          + no_device    = (known after apply)
          + virtual_name = (known after apply)
        }

      + metadata_options {
          + http_endpoint               = (known after apply)
          + http_put_response_hop_limit = (known after apply)
          + http_tokens                 = (known after apply)
        }

      + network_interface {
          + delete_on_termination = (known after apply)
          + device_index          = (known after apply)
          + network_interface_id  = (known after apply)
        }

      + root_block_device {
          + delete_on_termination = (known after apply)
          + device_name           = (known after apply)
          + encrypted             = (known after apply)
          + iops                  = (known after apply)
          + kms_key_id            = (known after apply)
          + tags                  = (known after apply)
          + throughput            = (known after apply)
          + volume_id             = (known after apply)
          + volume_size           = (known after apply)
          + volume_type           = (known after apply)
        }
    }

  # aws_security_group.webserver_security_group will be created
  + resource "aws_security_group" "webserver_security_group" {
      + arn                    = (known after apply)
      + description            = "Managed by Terraform"
      + egress                 = [
          + {
              + cidr_blocks      = [
                  + "0.0.0.0/0",
                ]
              + description      = ""
              + from_port        = 0
              + ipv6_cidr_blocks = []
              + prefix_list_ids  = []
              + protocol         = "-1"
              + security_groups  = []
              + self             = false
              + to_port          = 0
            },
        ]
      + id                     = (known after apply)
      + ingress                = [
          + {
              + cidr_blocks      = [
                  + "116.110.26.150/32",
                ]
              + description      = ""
              + from_port        = 22
              + ipv6_cidr_blocks = []
              + prefix_list_ids  = []
              + protocol         = "tcp"
              + security_groups  = []
              + self             = false
              + to_port          = 22
            },
          + {
              + cidr_blocks      = [
                  + "116.110.26.150/32",
                ]
              + description      = ""
              + from_port        = 80
              + ipv6_cidr_blocks = []
              + prefix_list_ids  = []
              + protocol         = "tcp"
              + security_groups  = []
              + self             = false
              + to_port          = 80
            },
        ]
      + name                   = (known after apply)
      + name_prefix            = (known after apply)
      + owner_id               = (known after apply)
      + revoke_rules_on_delete = false
      + tags_all               = (known after apply)
      + vpc_id                 = (known after apply)
    }

Plan: 2 to add, 0 to change, 0 to destroy.

Changes to Outputs:
  + public_ip = (known after apply)

Do you want to perform these actions?
  Terraform will perform the actions described above.
  Only 'yes' will be accepted to approve.

  Enter a value: yes

aws_security_group.webserver_security_group: Creating...
aws_security_group.webserver_security_group: Still creating... [10s elapsed]
aws_security_group.webserver_security_group: Creation complete after 15s [id=sg-08ad09dbfd038f567]
aws_instance.devopsroles-lab01: Creating...
aws_instance.devopsroles-lab01: Still creating... [10s elapsed]
aws_instance.devopsroles-lab01: Still creating... [20s elapsed]
aws_instance.devopsroles-lab01: Still creating... [30s elapsed]
aws_instance.devopsroles-lab01: Still creating... [40s elapsed]
aws_instance.devopsroles-lab01: Creation complete after 48s [id=i-085b38b93b9e04090]

Apply complete! Resources: 2 added, 0 changed, 0 destroyed.

Outputs:

public_ip = "34.221.162.57"

C:\Users\HuuPV\Desktop\Terraform\Single-WebServer>

The result, on EC2 AWS

Open Browser, type http://IP_Public_EC2 as below

Conclusion

You have to Deploy a Web Server with Terraform. I hope will this your helpful. Thank you for reading the DevopsRoles page!

Terraform deploy a single server

#Introduction

In this tutorial, We will create an EC2 server. How to use Terraform deploy a single server.

Structure folder and files for Terraform deploy a single server

Created Deploy-EC2-Server folder contains files as below:

main.tf
output.tf
provider.tf
securitygroups.tf

Terraform deploy a single server

Create new file main.tf with the content as below

resource "aws_instance" "devopsroles-lab01" {

 ami = "ami-0c2d06d50ce30b442" 
 instance_type = "t2.micro"
 vpc_security_group_ids = ["${aws_security_group.webserver_security_group.id}"]
 key_name = "terraform-demo"
 tags = {
	 Name = "Devops Roles"
 }

}

On AWS, we created key pair terraform-demo as the picture below

Create a new file provider.tf with the content as below

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

New file securitygroups.tf with the content as below

resource "aws_security_group" "webserver_security_group" { 

    ingress {
        from_port = 22
        to_port = 22
        protocol = "tcp"
        cidr_blocks = [ "116.110.26.100/32"]
    }
    
    egress {
    from_port       = 0
    to_port         = 0
    protocol        = "-1"
    cidr_blocks     = ["0.0.0.0/0"]
  }
    
}

Create a new file output.tf with the content as below

output "public_ip" {
    value = "${aws_instance.devopsroles-lab01.public_ip}"
}

First, we run below to initialize, download the plugins and validate the terraform syntax…

terraform init
terraform validate

The output terminal is as follows

Applying a template

$ terraform apply

The output terminal is as below

C:\Users\HuuPV\Desktop\Terraform\EC2>set AWS_PROFILE=devopsroles-demo

C:\Users\HuuPV\Desktop\Terraform\EC2>terraform apply

Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with
the following symbols:
  + create

Terraform will perform the following actions:

  # aws_instance.devopsroles-lab01 will be created
  + resource "aws_instance" "devopsroles-lab01" {
      + ami                                  = "ami-0c2d06d50ce30b442"
      + arn                                  = (known after apply)
      + associate_public_ip_address          = (known after apply)
      + availability_zone                    = (known after apply)
      + cpu_core_count                       = (known after apply)
      + cpu_threads_per_core                 = (known after apply)
      + disable_api_termination              = (known after apply)
      + ebs_optimized                        = (known after apply)
      + get_password_data                    = false
      + host_id                              = (known after apply)
      + id                                   = (known after apply)
      + instance_initiated_shutdown_behavior = (known after apply)
      + instance_state                       = (known after apply)
      + instance_type                        = "t2.micro"
      + ipv6_address_count                   = (known after apply)
      + ipv6_addresses                       = (known after apply)
      + key_name                             = "terraform-demo"
      + monitoring                           = (known after apply)
      + outpost_arn                          = (known after apply)
      + password_data                        = (known after apply)
      + placement_group                      = (known after apply)
      + primary_network_interface_id         = (known after apply)
      + private_dns                          = (known after apply)
      + private_ip                           = (known after apply)
      + public_dns                           = (known after apply)
      + public_ip                            = (known after apply)
      + secondary_private_ips                = (known after apply)
      + security_groups                      = (known after apply)
      + source_dest_check                    = true
      + subnet_id                            = (known after apply)
      + tags                                 = {
          + "Name" = "Devops Roles"
        }
      + tags_all                             = {
          + "Name" = "Devops Roles"
        }
      + tenancy                              = (known after apply)
      + user_data                            = (known after apply)
      + user_data_base64                     = (known after apply)
      + vpc_security_group_ids               = (known after apply)

      + capacity_reservation_specification {
          + capacity_reservation_preference = (known after apply)

          + capacity_reservation_target {
              + capacity_reservation_id = (known after apply)
            }
        }

      + ebs_block_device {
          + delete_on_termination = (known after apply)
          + device_name           = (known after apply)
          + encrypted             = (known after apply)
          + iops                  = (known after apply)
          + kms_key_id            = (known after apply)
          + snapshot_id           = (known after apply)
          + tags                  = (known after apply)
          + throughput            = (known after apply)
          + volume_id             = (known after apply)
          + volume_size           = (known after apply)
          + volume_type           = (known after apply)
        }

      + enclave_options {
          + enabled = (known after apply)
        }

      + ephemeral_block_device {
          + device_name  = (known after apply)
          + no_device    = (known after apply)
          + virtual_name = (known after apply)
        }

      + metadata_options {
          + http_endpoint               = (known after apply)
          + http_put_response_hop_limit = (known after apply)
          + http_tokens                 = (known after apply)
        }

      + network_interface {
          + delete_on_termination = (known after apply)
          + device_index          = (known after apply)
          + network_interface_id  = (known after apply)
        }

      + root_block_device {
          + delete_on_termination = (known after apply)
          + device_name           = (known after apply)
          + encrypted             = (known after apply)
          + iops                  = (known after apply)
          + kms_key_id            = (known after apply)
          + tags                  = (known after apply)
          + throughput            = (known after apply)
          + volume_id             = (known after apply)
          + volume_size           = (known after apply)
          + volume_type           = (known after apply)
        }
    }

  # aws_security_group.webserver_security_group will be created
  + resource "aws_security_group" "webserver_security_group" {
      + arn                    = (known after apply)
      + description            = "Managed by Terraform"
      + egress                 = [
          + {
              + cidr_blocks      = [
                  + "0.0.0.0/0",
                ]
              + description      = ""
              + from_port        = 0
              + ipv6_cidr_blocks = []
              + prefix_list_ids  = []
              + protocol         = "-1"
              + security_groups  = []
              + self             = false
              + to_port          = 0
            },
        ]
      + id                     = (known after apply)
      + ingress                = [
          + {
              + cidr_blocks      = [
                  + "116.110.26.100/32",
                ]
              + description      = ""
              + from_port        = 22
              + ipv6_cidr_blocks = []
              + prefix_list_ids  = []
              + protocol         = "tcp"
              + security_groups  = []
              + self             = false
              + to_port          = 22
            },
        ]
      + name                   = (known after apply)
      + name_prefix            = (known after apply)
      + owner_id               = (known after apply)
      + revoke_rules_on_delete = false
      + tags_all               = (known after apply)
      + vpc_id                 = (known after apply)
    }

Plan: 2 to add, 0 to change, 0 to destroy.

Changes to Outputs:
  + public_ip = (known after apply)

Do you want to perform these actions?
  Terraform will perform the actions described above.
  Only 'yes' will be accepted to approve.

  Enter a value: yes

aws_security_group.webserver_security_group: Creating...
aws_security_group.webserver_security_group: Still creating... [10s elapsed]
aws_security_group.webserver_security_group: Creation complete after 13s [id=sg-0fc57ba0b0d8f51d8]
aws_instance.devopsroles-lab01: Creating...
aws_instance.devopsroles-lab01: Still creating... [10s elapsed]
aws_instance.devopsroles-lab01: Still creating... [20s elapsed]
aws_instance.devopsroles-lab01: Still creating... [30s elapsed]
aws_instance.devopsroles-lab01: Still creating... [40s elapsed]
aws_instance.devopsroles-lab01: Creation complete after 45s [id=i-051ce096e6d8cad8a]

Apply complete! Resources: 2 added, 0 changed, 0 destroyed.

Outputs:

public_ip = "34.212.176.200"

C:\Users\HuuPV\Desktop\Terraform\EC2>

The result, on EC2 AWS

Conclusion

You have Terraform deploy a single server. I hope will this your helpful. Thank you for reading the DevopsRoles page!

Beginner’s Terraform aws get started

Introduction

Terraform aws get started. In this tutorial, we’ll guide you through the basics of using Terraform to set up and manage your AWS resources efficiently. Terraform, a powerful Infrastructure as Code (IaC) tool, allows you to define your cloud infrastructure in configuration files, making it easier to automate and maintain.

Whether you’re new to Terraform or looking to enhance your AWS deployment strategies, this guide will provide you with essential steps and best practices to get you up and running quickly. Let’s dive into the world of Terraform on AWS and simplify your cloud infrastructure management.

Step-by-Step Guide: Terraform aws get started

  • Create a new AWS free tier.
  • Setup MFA for the root user.
  • Create new Admin user and configure MFA.
  • Install and configure AWS CLI on Mac/Linux and Windows
  • Install Terraform

Create a new AWS free tier

First, we create a new AWS free tier account. The email address would be the root user for this account.

Setup MFA for the root user.

Link IAM

Activate MFA as in the picture below:

Create Admin user and configure MFA

  • Do not use the root user for day-to-day work
  • Create new admin user and secure with MFA.

Install and configure AWS CLI on Mac/Linux and Windows

Install AWS CLI on MAC/Linux

Using bundled install on MAC/Linux

curl https://s3.amazonaws.com/aws-cli/awscli-bundle.zip -o "awscli-bundle.zip"
unzip awscli-bundle.zip
sudo ./awscli-bundle/install -I /usr/local/aws -b /usr/local/bin/aws
./awscli-bundle/install -h

Using pip on Mac/Linux

curl -O https://bootstrap.pypa.io/get-pip.py
python3 get-pip.py -user
pip3 install awscli --upgrade -user
aws --version

Install AWS cli on Windows

Refer here:

AWS configure

aws configure --profile devopsroles-demo
AWS Access Key ID [None]: XXXXZHBNJLCKKCE7EQQQ
AWS Secret Access Key [None]: fdfdfdfd43434dYlQ1il1xKNCnqwUvNHFSv41111
Default region name [None]:
Default output format [None]:

Install Terraform

Link download here: Download Terraform – Terraform by HashiCorp

After install Terraform.

C:\Users\HuuPV>terraform --version
Terraform v1.0.6
on windows_amd64

Your version of Terraform is out of date! The latest version
is 1.0.7. You can update by downloading from https://www.terraform.io/downloads.html

Conclusion

You have installed and configured Terraform AWS labs. I hope will this your helpful. Thank you for reading the DevopsRoles page! Terraform aws get started.

Terraform commands cheat sheet

#Introduction

In this tutorial, to learn about Terraform commands cheat sheet.

Terraform commands cheat sheet.

Initialize the terraform stack and download provider plugins as per provider and also verify the syntax

#terraform init

How to display the preview of the resources that are going to be created, updated, and destroyed.

#terraform plan

Build or change infrastructure.

 #terraform apply

Destroy terraform-managed infrastructure.

#terraform destroy

Run plan or apply or destroy only to the target resource

#terraform plan -target=resource
#terraform apply -target=resource
#terraform destroy -target=resource

Show human-readable output from Terraform state.

#terraform show

How to validate terraform syntax

 #terraform validate

Rewrites terraform code to a canonical format. This useful run command before git commit that codes very nicely formatted.

#terraform fmt

Manually mark a resource for re-creation

#terraform taint

Download and install modules for the configurations. When you update the module.

#terraform get

Create a visual dependency graph of resources.

#terraform graph

Configure remote state storage.

#terraform remote

Use this command for advanced state management.

#terraform state

Conclusion

You have learned about Terraform commands cheat sheet. I hope will this your helpful. Thank you for reading the DevopsRoles page!

Terraform AWS create VPC: A Comprehensive Step-by-Step Guide

Introduction

How to create AWS VPC using Terraform. In this tutorial, I’m using Terraform AWS create VPC example. Embark on a journey to mastering cloud infrastructure with our detailed tutorial on creating a Virtual Private Cloud (VPC) in AWS using Terraform.

This guide is tailored for DevOps professionals and enthusiasts eager to leverage the scalability and efficiency of AWS. By the end of this tutorial, you will have a clear understanding of how to set up a VPC that aligns perfectly with your organizational needs, ensuring a secure and robust network environment.

Terraform aws create VPC example

The structure folder and files for AWS VPC are as follows

E:\STUDY\TERRAFORM\AWS
└───EC2
│ main.tf
│ outputs.tf
│ variables.tf

Terraform init command is used to initialize a working directory containing Terraform configuration files

terraform init 

The output as the picture below

Use the terraform plan command to create an execution plan.

terraform plan

The output as the picture below

Use terraform apply is to run it.

terraform apply

The output is the picture below

The result on AWS VPC

The content files for Terraform AWS VPC

main.tf file

# dry-run
# terraform plan
# Apply it
# terraform apply
provider "aws" {
    access_key = "${var.aws_access_key}"
	secret_key = "${var.aws_secret_key}"
	region = "${var.region}"
}
# describe the VPC resource.
resource "aws_vpc" "myVPC" {
    cidr_block = "10.1.0.0/16"
    instance_tenancy = "default"
    enable_dns_support = "true"
    enable_dns_hostnames = "false"
    tags = {
      Name = "myVPC"
    }
}

variables.tf file

variable "aws_access_key" {}
variable "aws_secret_key" {}
variable "region" {
    default = "us-west-2"
}

outputs.tf file

output "test" {
    value ="${aws_vpc.myVPC.cidr_block}"
}

Conclusion

Congratulations on successfully creating your AWS VPC using Terraform! This guide aimed to simplify the complexities of cloud networking, providing you with a solid foundation to build upon. As you continue to explore Terraform and AWS, remember that the flexibility and power of these tools can significantly enhance your infrastructure’s reliability and performance.

Keep experimenting and refining your skills to stay ahead in the ever-evolving world of cloud computing. I hope will this your helpful. Thank you for reading the DevopsRoles page!