Advanced Terraform Configuration: Day 7

Mastering Terraform Configuration

Advanced Terraform Configuration: Day 7
  • In this blog, we'll explore some advanced Terraform concepts. You probably know that Terraform uses a language called HashiCorp Configuration Language (HCL) for its configuration files. Today, we'll take a closer look at HCL and learn about providers, resources, conditional expressions, and functions. We'll also discover different methods for debugging Terraform files. Let's begin our journey to becoming Terraform pros!

HashiCorp Configuration Language (HCL)

Overview:

The files used to build infrastructure are written in Hashicorp Configuration language - HCL, which is human-readable, and can be versioned, reused, shared, and managed throughout the lifecycle.

  • HCL is a declarative language in which the user specifies the desired state to be attained rather than mentioning the steps to reach the level.

  • Using HCL, we can define resources like virtual machines, networks, databases, etc. Each resource is associated with a provider (e.g., AWS, Azure, Google Cloud). This allows us to manage a wide variety of infrastructure resources with Terraform.

  • HCL automatically manages dependencies between resources.

  • HCL keeps track of the state of the infrastructure in a state file.

Syntax rules and conventions:

HCL uses a declarative syntax to specify the desired state of the infrastructure. Here's an example:

resource "provider_type" "resource_name" {
  # Configuration options for the resource
  attribute1 = value1
  attribute2 = value2
  # ...
}
  • A resource defines which provider_type this block belongs to. For example: aws_s3, aws_instance etc.

  • attributes and value are the various attributes specific to the resource being created. The available attributes depend on the resource type and the provider being used.

Examples of HCL syntax used in Terraform configurations:

# Define variables for better reusability and flexibility
variable "ami_id" {
  default = "ami-0c55b159cbfafe1f0" # Default AMI ID for non-production environments
}

variable "is_production" {
  default = false # Set this to true for production environment, false for non-production
}

# AWS provider configuration
provider "aws" {
  region = "us-east-1a" # Specify the AWS region where resources will be created
}

# AWS EC2 instance resource
resource "aws_instance" "example" {
  ami           = var.is_production ? "ami-prod" : var.ami_id # Use different AMI ID for production or the default for non-production
  instance_type = "t2.micro" # Specify the instance type
  key_name      = "my-key-pair" # Specify the SSH key pair for authentication

  tags = {
    Name = "Example EC2 Instance" # Tags help identify and organize resources
  }
}

Providers

Providers is a plugin that enables Terraform to interact with different services or tools with the help of APIs. At the start of HCL script, its required to inform the Terraform which cloud platform or service it has to talk to.

In the example mentioned above,

  • First, we informed Terraform about the aws provider and mentioned the region in which the instance has to be created.

  • Secondly, we described what kind of resource type we have to create. In the mentioned block, we defined ami, instance_type, key_name and tag.

  • Now, Terraform init command installs the aws provider and with the help of aws provider, a Virtual machine is created on amazon.

You may refer to this Providers List for a complete view of providers supported by Terraform.

Multi-Cloud Provider

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

provider "azurerm" {
  subscription_id = "your-azure-subscription-id"
  client_id = "your-azure-client-id"
  client_secret = "your-azure-client-secret"
  tenant_id = "your-azure-tenant-id"
}

Multi-Region Provider

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

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

Resources

Resources are the elements which describe what kind of virtual machine or database or service need to be created on the mentioned provider.

  • Resource type defines the type of resource that needs to be created, such as S3, aws_instance ,or vpc.

  • Resource name defines the unique name given to be created resource.

  • The resources block contains instance type, ami, key, bucket name etc.

  • Multi-Cloud Provider

  •       resource "aws_instance" "example" {
            ami = "ami-0123456789abcdef0"
            instance_type = "t2.micro"
          }
    
          resource "azurerm_virtual_machine" "example" {
            name = "example-vm"
            location = "eastus"
            size = "Standard_A1"
          }
    
  • Multi-Region Provider

  •       resource "aws_instance" "example" {
            ami = "ami-0123456789abcdef0"
            instance_type = "t2.micro"
            provider = "aws.us-east-1"
          }
    
          resource "aws_instance" "example2" {
            ami = "ami-0123456789abcdef0"
            instance_type = "t2.micro"
            provider = "aws.us-west-2"
          }
    

Variables and Outputs in Terraform

Using hardcoded values in scripts can often lead to inflexibility and maintenance challenges. Variables have also been a solution we have been using in all the languages to define values for many years now. In terraform as well, we have two types of variables:

Input Variable

Input variables are values we are passing into modules or configurations from outside.

Below are examples of variable defined in a script

variable "instance_type" {
  description = "EC2 instance type"
  type        = string
  default     = "t2.micro"
}
variable "ami_id" {
  description = "EC2 AMI ID"
  type        = string
}

And above variables can be used in the configuration under the resource as below:

resource "aws_instance" "example_instance" {
  ami           = var.ami_id
  instance_type = var.instance_type
}

Output Variable

Output variables in Terraform are specified as the data that you want to extract from your infrastructure after it's been created or modified.

resource "aws_instance" "example_instance" {
  ami           = var.ami_id
  instance_type = var.instance_type
}

Output of public ip from above code can be captured as:

output "public_ip" {
  description = "Public IP address of the EC2 instance"
  value       = aws_instance.example_instance.public_ip
}

Conditional Expressions

These expressions help to add conditional logic to your code. At certain stages we need to make a decision if the environment is dev then use certain values otherwise, use another set of values.

Syntax for conditional expression

condition ? true_val : false_val

Example

variable "environment" {
  description = "Environment type"
  type        = string
  default     = "development"
}

variable "production_subnet_cidr" {
  description = "CIDR block for production subnet"
  type        = string
  default     = "10.0.1.0/24"
}

variable "development_subnet_cidr" {
  description = "CIDR block for development subnet"
  type        = string
  default     = "10.0.2.0/24"
}

resource "aws_security_group" "example" {
  name        = "example-sg"
  description = "Example security group"

  ingress {
    from_port   = 22
    to_port     = 22
    protocol    = "tcp"
    cidr_blocks = var.environment == "production" ? [var.production_subnet_cidr] : [var.development_subnet_cidr]
  }
}

Built-in Functions

HCL has commonly used built-in functions in Terraform which are widely used. These functions are really helpful while writing configuration files.

Example

concat(list1, list2, ...) # Combines multiple lists into a single list.
length(list): Returns the number of elements in a list
map(key, value): Creates a map from a list of keys and a list of values.
lookup(map, key): Retrieves the value associated with a specific key in a map.
join(separator, list): Joins the elements of a list into a single string using the specified separator.
element(list, index): Returns the element at the specified index in a list.

Reference Links: https://www.educative.io/answers/what-is-hashicorp-configuration-languagehcl

Conclusion

In this blog, we've discussed the fundamentals of HCL syntax, a quick walk through of how we can craft Terraform configurations with ease. We discussed variables, Providers, Resources, and Conditional Expression in HCL, along with techniques for testing and debugging Terraform setups. By adhering to these principles, you'll be equipped to create streamlined and powerful Terraform configurations, streamlining your infrastructure management efforts.