Meta-Arguments in Terraform

Meta-Arguments in Terraform

#day63 of #90daysofdevops

Introduction:)

🚀 #Day63 of #90DaysOfDevOps 🛠️

Exploring Terraform Meta-Arguments! Today, dive into the powerful meta-arguments of Terraform—key configuration options that add flexibility and control to your infrastructure. From managing dependencies to dynamic resource creation, let's unleash the true potential of Terraform!

What are Meta-Arguments in Terraform?

In Terraform, meta-arguments are special configuration options that can be applied to resources and modules to control their behavior within a Terraform configuration.

These meta-arguments provide additional functionality and customization options beyond the basic configuration of a resource or module.

Type of Meta-Arguments in Terraform

There are 5 Meta-Arguments in Terraform, which are as follows:

  • count

  • depends_on

  • for_each

  • lifecycle

  • provider

count

In Terraform, a resource block configures only one infrastructure object by default. We can define the meta-argument if we want multiple resources with the same configurations. This will reduce the overhead of duplicating the resource block a number of times.

count require a whole number and will then create that resource that number of times. To identify each of them, we use the count.index which is the index number corresponds to each resource. The index ranges from 0 to count-1.

HandsOn

  1. Create a new Terraform configuration file, e.g., aws_instance.tf

    • If we want to create the multiple instance usining same configuration

        resource "aws_instance" "example" {
          ami           = "ami-0557a15b87f6559cf"
          instance_type = "t2.micro"
      
          count = 3 # Create 3 instances
      
          tags = {
            Name = "example-instance-${count.index + 1}"
          }
        }
      

      In this example:

      • count = 3 specifies that three instances of the aws_instance resource will be created.

      • ${count.index + 1} is used to generate a unique name for each instance by incorporating the instance index. The count.index starts from 0, so adding 1 ensures that the instances are named sequentially

  1. Run the following Terraform commands in your terminal:

     terraform init
     terraform plan
     terraform apply
    

    Before init make sure you aws required configuration blocks

    As we see after using the terraform plan, it generate the 3 instances with their names

  2. Verify

    • As we see instance has created with unique names

depend_on

Terraform has a feature of identifying resource dependency. This means that Terraform internally knows the sequence in which the dependent resources needs to be created whereas the independent resources are created parallelly.

But in some scenarios, some dependencies are there that cannot be automatically inferred by Terraform. In these scenarios, a resource relies on some other resource’s behaviour but it doesn’t access any of the resource’s data in arguments.
For those dependencies, we’ll use depends_on meta-argument to explicitly define the dependency.

In simple explanation, depend_on is used when you need one resource to be created or updated before another.

Note: depends_on  meta-argument must be a list of references to other resources in the same calling resource.

Syntax:

depends_on = [resource_type.resource_name, ...]

HandsOn

  1. Create a new Terraform configuration , and add the following content:

     resource "aws_instance" "example" {
       ami           = "ami-0c55b159cbfafe1f0"
       instance_type = "t2.micro"
    
       tags = {
         Name = "example-instance"
       }
     }
    
     resource "aws_security_group" "example_sg" {
       name        = "example-sg"
       description = "Example Security Group"
    
       ingress {
         from_port = 22
         to_port   = 22
         protocol  = "tcp"
         cidr_blocks = ["0.0.0.0/0"]
       }
    
       # Explicitly depend on the aws_instance resource
       depends_on = [aws_instance.example]
     }
    

    In this example,
    the aws_security_group resource explicitly depends on the aws_instance resource using depends_on.
    This ensures that Terraform will create or update the aws_instance resource before attempting to manage the aws_security_group resource.

  2. After planning the configuration we see that first ec2 instance will created then the security group

for_each

As specified in the count meta-argument, that the default behaviour of a resource is to create a single infrastructure object which can be overridden by using count, but there is one more flexible way of doing the same which is by using for_each meta argument.

Note: The for_each meta argument accepts a map or set of strings.

Syntax:

resource "resource_type" "resource_name" {
  for_each = <map or set>

  # Resource configuration
}

HandsOn

  1. Create a new Terraform configuration , and add the following content:

     locals {
       ami_ids = toset([
         "ami-0b0dcb5067f052a63",
         "ami-08c40ec9ead489470",
       ])
     }
    
     resource "aws_instance" "server" {
       for_each = local.ami_ids
    
       ami           = each.key
       instance_type = "t2.micro"
    
       tags = {
         Name = "Server ${each.key}"
       }
     }
    

  2. Plan the configuration

     terraform plan
    

lifecycle

The lifecycle meta-argument defines the lifecycle for the resource. As per the resource behaviour, Terraform can do the following:

  • create a resource

  • destroy a resource

  • updated resource in place

  • update resource by deleting existing and create new

Here are some key aspects and options provided by the lifecycle block:

  1. create_before_destroy Attribute: (Type: Bool)

    • Controls whether Terraform creates the replacement resource before destroying the old one during updates.

    • Example:

        lifecycle {
          create_before_destroy = true
        }
      
  1. prevent_destroy Attribute: (Type: Bool)

    • Prevents Terraform from destroying the resource. This can be useful to avoid accidental deletion of critical resources.

    • Example:

        lifecycle {
          prevent_destroy = true
        }
      
  1. ignore_changes Attribute: (Type: List(Attribute Names))

    • Instructs Terraform to ignore changes to specific attributes during updates. This can be useful for certain attributes that might change outside of Terraform's control.

    • Example:

        lifecycle {
          ignore_changes = [attribute_name]
        }
      

HandsOn

  1. Create a new Terraform configuration , and add the following content:

     resource "aws_instance" "example" {
       ami           = "ami-12345678"
       instance_type = "t2.micro"
    
       lifecycle {
         create_before_destroy = true
         prevent_destroy       = false
         ignore_changes        = [tags]
       }
     }
    

  2. Plan the configuration

provider

provider meta-argument specifies which provider to use for a resource. This is useful when you are using multiple providers which is usually used when you are creating multi-region resources.

To differentiate those providers, you use an alias field.

The resource then references the same alias field of the provider as provider.alias to tell which one to use.

HandsOn

  1. Create a new Terraform configuration , and add the following content:

     ## Default Provider
     provider "aws" {
       region = "us-east-1"
     }
    
     ## Another Provider
     provider "aws" {
       alias  = "mumbai"
       region = "ap-south-1"
     }
    
     ## Referencing the other provider
     resource "google_compute_instance" "example" {
       provider = aws.mumbai
     }
    
  2. what Happens When You Apply This Code?

    When you apply this Terraform configuration using terraform apply, the following will happen:

    • The default AWS provider with the region "us-east-1" is configured.

    • Another AWS provider with the alias "mumbai" and the region "ap-south-1" is configured.

    • The instance is created using the AWS provider configuration with the "mumbai" alias.


Choosing Between for_each and count in Terraform

  • for_each: Used for dynamic resource creation with different configurations for each instance.

  • count: Used for duplicating the block with the same configuration for each instance.


Short Explanations:-

count:

  • Purpose: Controls the number of instances of a resource to create.

  • Use Case: Useful when you need to create multiple copies of the same resource, such as multiple EC2 instances.

depends_on:

  • Purpose: Specifies explicit dependencies between resources, ensuring proper sequencing during creation and updates.

  • Use Case: Useful when you have dependencies between resources, and you need one resource to be created or updated before another.

provider:

  • Purpose: Specifies the provider alias for a particular resource, allowing the use of multiple providers of the same type within a configuration.

  • Use Case: Useful in scenarios where you have multiple environments or cloud providers.

lifecycle:

  • Purpose: Provides advanced control over the lifecycle of a resource, including options like create_before_destroy and prevent_destroy.

  • Use Case: Useful when you need fine-grained control over resource replacement and destruction behavior.

for_each:

  • Purpose: Allows dynamic creation of multiple instances of a resource based on a map or set of strings.

  • Use Case: Useful when you want to create resources dynamically based on input data or variables.


Connect with me:)

Thank you for diving into this blog with me! I trust you found the information both helpful and enlightening. To stay updated on the latest in DevOps 🚀, make sure to follow me. Remember, staying informed means staying ahead in the dynamic world of DevOps!

Feel free to connect with me on:

LinkedIn

Twitter

GitHub

For more updates and engaging discussions on DevOps, let's connect! 🚀 #DevOpsCommunity