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.

Fix Provider Configuration Not Present Error in Terraform: A Deep Guide

Introduction

Terraform is an open-source infrastructure-as-code software tool that enables users to define and provision data center infrastructure using a high-level configuration language. However, despite its power and flexibility, users sometimes encounter issues that can disrupt their workflows. One common issue is the Provider Configuration Not Present Error, which can be frustrating and confusing, especially for those new to Terraform.

This comprehensive guide will delve into the causes and solutions for this error, providing a deep dive into the mechanics of Terraform provider configuration. We’ll cover both basic and advanced troubleshooting techniques, offering a path to resolution regardless of your familiarity with Terraform.

Understanding Terraform Provider Configuration

What Is a Terraform Provider?

Before diving into the error, it’s essential to understand what a Terraform provider is. A provider in Terraform is a plugin that allows Terraform to manage and interact with resources on a particular platform or service. Each provider is responsible for understanding API interactions and exposing resources for Terraform to manage. For example, the AWS provider allows Terraform to create and manage AWS resources like EC2 instances, S3 buckets, and more.

How Does Terraform Handle Provider Configuration?

Terraform requires users to specify provider configurations in their configuration files. This configuration tells Terraform which provider to use and how to authenticate and connect to it. The provider configuration typically includes credentials, regions, and other parameters required to interact with the provider’s API.

provider "aws" {
  region  = "us-west-2"
  version = "~> 3.0"
}

Why Is Provider Configuration Important?

Without a proper provider configuration, Terraform cannot interact with the desired resources, leading to errors during the plan or apply stages. The “Provider Configuration Not Present” error occurs when Terraform cannot find the necessary configuration to proceed.

The Root Causes of the Provider Configuration Not Present Error

Missing Provider Block

The most straightforward cause of this error is the absence of a provider block in your Terraform configuration file. Without this block, Terraform has no way of knowing how to connect to the provider.

Incorrect Provider Version

Terraform providers are versioned, and using an incompatible or outdated version can cause configuration issues. Specifying the correct version ensures that Terraform uses the appropriate provider features and API endpoints.

Module Dependency Issues

When using modules, Terraform may have difficulty locating the provider configuration if it’s not explicitly passed down. Modules are isolated and do not inherit provider configurations automatically, leading to potential errors.

Incorrect or Corrupted State File

Terraform maintains a state file that keeps track of the resources it manages. If this state file becomes corrupted or misaligned with your configuration, Terraform may not be able to find the necessary provider configuration.

Misconfigured Workspaces

Terraform workspaces allow users to manage multiple environments with the same configuration. However, if the provider configuration is not correctly set for each workspace, it can lead to the Provider Configuration Not Present error.

Step-by-Step Guide to Fixing the Error

Step 1: Verify the Provider Block

The first and most crucial step is to ensure that your Terraform configuration includes a valid provider block. For instance, if you’re working with AWS, your provider block should look like this:

provider "aws" {
  region  = "us-west-2"
  version = "~> 3.0"
}

Make sure this block is present in your configuration file and that it specifies the correct region and version.

Step 2: Initialize Terraform

If the provider block is correctly configured, the next step is to initialize Terraform. The initialization process downloads the necessary provider plugins and prepares the environment for further operations.

terraform init

Step 3: Upgrade the Provider

If the error persists, you may need to upgrade the provider to the latest version. This ensures that you are using a version of the provider that is compatible with your Terraform configuration.

terraform init -upgrade

Step 4: Validate the Configuration

Validation is a critical step to ensure that your Terraform configuration is syntactically correct and that all required providers are properly configured. The terraform validate the command checks your configuration for errors:

terraform validate

Step 5: Explicitly Define Provider Source in Modules

If you are using modules, you might need to pass the provider configuration explicitly to the module. This ensures that the module uses the correct provider settings.

module "vpc" {
  source  = "terraform-aws-modules/vpc/aws"
  version = "2.77.0"

  providers = {
    aws = aws.primary
  }
}

provider "aws" {
  alias  = "primary"
  region = "us-east-1"
}

Step 6: Review and Rebuild the State File

The state file is a critical component of Terraform’s operation. If the state file is corrupted or outdated, you may need to refresh or rebuild it:

terraform refresh

This command refreshes the state file with the actual state of your infrastructure, aligning it with your configuration.

Step 7: Use Terraform Workspaces Correctly

If you are managing multiple environments using workspaces, ensure that each workspace has the correct provider configuration. Switch between workspaces using the following commands:

terraform workspace new dev
terraform workspace select dev

Step 8: Inspect Dependency Graphs

Terraform provides a way to inspect the dependency graph of your configuration. This can help you identify issues related to provider configuration:

terraform graph

By analyzing the graph, you can see how providers and modules are connected, which may help identify where the configuration is missing or incorrect.

Step 9: Upgrade Terraform

If you have tried all the above steps and the error persists, consider upgrading Terraform to the latest version:

terraform version
terraform upgrade

Ensure that the Terraform version you are using is compatible with your provider versions and other plugins.

Advanced Techniques for Troubleshooting

Using Terraform Debug Logs

Terraform provides a way to enable debug logs, which can give you more insight into what’s happening during the plan or apply processes. To enable debugging, set the following environment variable:

export TF_LOG=DEBUG

Run your Terraform commands again, and you’ll see detailed logs that may help identify the source of the error.

Managing Multiple Providers

If your configuration involves multiple providers, you may need to manage them more explicitly to avoid conflicts. For example, using provider aliases can help Terraform distinguish between different providers:

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

provider "aws" {
  alias  = "secondary"
  region = "us-east-1"
}

module "my_module" {
  source   = "./module"
  providers = {
    aws = aws.primary
  }
}

Automating Provider Configuration Management

In larger infrastructure deployments, managing provider configurations manually can become cumbersome. Consider using automation tools like Terraform Cloud or Terraform Enterprise to manage provider configurations at scale. These tools provide centralized management of provider settings, reducing the likelihood of errors.

Custom Terraform Modules with Provider Configurations

If you are developing custom Terraform modules, ensure that your module explicitly defines which providers it depends on and passes these configurations from the root module. This can prevent the Provider Configuration Not Present error when others use your module.

FAQs

What does the Provider Configuration Not Present error mean?

This error indicates that Terraform cannot find the necessary provider configuration to execute the plan or apply command. It usually occurs when the provider block is missing, the provider version is incorrect, or there are issues with the state file or module dependencies.

How can I prevent the Provider Configuration Not Present error in the future?

To prevent this error, always ensure that your provider blocks are correctly configured and validated. Use Terraform workspaces and modules appropriately, and regularly upgrade your Terraform and provider versions.

What should I do if upgrading Terraform does not fix the error?

If upgrading Terraform doesn’t resolve the error, consider inspecting the state file, using debug logs, or explicitly managing multiple providers. You may also need to consult Terraform’s documentation or community forums for specific cases.

Can this error occur with any Terraform provider?

Yes, the “Provider Configuration Not Present” error can occur with any provider if the configuration is not properly set up. Whether you’re using AWS, Azure, GCP, or any other provider, the steps to resolve the error are generally similar.

Conclusion

The Provider Configuration Not Present error in Terraform can be a challenging issue to resolve, especially in complex infrastructure environments. However, by following the steps outlined in this guide, you can troubleshoot and fix the error, ensuring that your Terraform configurations run smoothly.

From verifying provider blocks to advanced techniques like using debug logs and managing multiple providers, this guide provides a comprehensive approach to resolving the error. Remember to validate your configurations, upgrade your tools, and keep your Terraform setup aligned with best practices to avoid encountering this error in the future. Thank you for reading the DevopsRoles page!

By mastering these techniques, you’ll be well-equipped to handle not only the Provider Configuration Not Present error but any other challenges that come your way in Terraform infrastructure management.

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!