Terraform Essentials: Lifecycles, Data Sources, and Meta Arguments Overview

This is the second part of the terraform basics.

We will understand this concept by discussing real-world use cases.

Refer to the Terraform overview series, and follow it sequentially to understand the flow.

Lifecycles

Terraform lifecycles are configuration options that allow us to control resource management behavior during the Terraform execution process. They are beneficial when we want to customize how Terraform handles resource creation, updates, or deletion. Here's an overview of Terraform lifecycles and their key attributes:

Key Lifecycle Arguments

  1. create_before_destroy

    • Ensures that a new resource is created before an existing one is destroyed.

    • Useful for resources where downtime is unacceptable or when dependency order is critical.

  2. prevent_destroy

    • Prevents accidental destruction of critical resources.

    • Terraform will throw an error instead of proceeding if a destroy operation is attempted.

  3. ignore_changes

    • Allows us to specify resource attributes that Terraform should ignore during updates.

    • Useful when an attribute is managed externally or changes dynamically outside of Terraform.

Use case of Lifecycle arguments

  1. create_before_destroy

    Use cases:

    1. Zero-Downtime Deployments
      In production environments, we cannot afford downtime. For example, when upgrading an instance type or changing an application server configuration (such as upgrading a VM or load balancer), create_before_destroy ensure the new resource is up and running before the old one is terminated. This prevents any disruption to users or services.

    2. Sensitive Data or Critical Applications
      Some infrastructure components, like databases or critical stateful services, cannot afford to be down even briefly. In such cases, we can use create_before_destroy to ensure a smooth transition when replacing or upgrading resources.

  2. prevent_destroy
    Use cases:

    1. Protecting Production Resources
      Resources such as production databases, core networking components (like VPCs or subnets), or critical applications should never be destroyed unintentionally. By applying prevent_destroy, we ensure that these resources are immune to accidental destruction during Terraform operations.

    2. Accidental Deletion Prevention in Shared Environments
      In environments where multiple teams or individuals are collaborating, having prevent_destroy shared resources (e.g., shared databases or network resources) reduces the risk of unintentional destruction. This is particularly important in environments where Terraform is being used by different users or teams.

  3. ignore_changes
    Use cases:

    1. External Configuration Changes
      When a resource is updated or changed by a process outside of Terraform (e.g., manually updating tags, security group rules, or an external automation tool), Terraform might detect these changes and attempt to revert them to their last state. ignore_changes Prevents this by telling Terraform to disregard specific attributes.

    2. Dynamic Properties Managed Outside Terraform
      Some resources, like Kubernetes deployments, might have attributes (such as dynamic IP addresses or auto-updated status information) that change frequently outside Terraform's management. In this case, we can use ignore_changes to ensure that Terraform doesn’t try to reset or undo these changes every time it runs.

There are other lifecycle arguments like replace_triggered_by, precondition and postcondition which can be used in the resources block to ensure the specific condition of validation of the resource attributes’s value of the infrastructure.

Datasource

  • A Data source allows us to retrieve information about existing resources or data from outside of Terraform's management. These resources or data can be used in your Terraform configurations to help create or manage infrastructure.

  • For example, if we are using an existing virtual machine or storage bucket that was created outside of Terraform, we can use a data source to pull in its details (like the ID or attributes) and reference it within your Terraform code.

Consideration while using Datasource

  • Read-only: Unlike resources block, the data source block doesn’t modify or create resources, they just fetch existing information.

  • Reusable: We can use the information retrieved by the data source multiple times in your configuration.

  • Own attributes: The data block has its own set of attributes for different resource types.

Use case of Datasource

  1. Fetching Information About Existing Infrastructure:
    Often, we will have infrastructure resources that were created outside of Terraform, such as pre-existing virtual machines, storage buckets, or DNS records. With data sources, we can reference those resources in your Terraform code, even if Terraform didn’t create them.

  2. Fetching Information About Infrastructure in Other Accounts:
    In multi-account environments, sometimes resources (such as a VPC, subnets, or security groups) are created in a different AWS account or even a different cloud provider. Data sources can help Terraform retrieve resources from different accounts without needing to manage them directly.

  3. Working with External APIs or Systems:
    Terraform's data sources can also integrate with external systems to fetch data for use in our infrastructure. For example, we can use the HTTP data source to fetch data from external APIs or use a terraform_remote_state data source to pull outputs from other Terraform configurations or workspaces.

Meta arguments: Counts and For_each

When working with Terraform, we may need to create multiple instances of the same resource. This is where count and for_each loops come in. These loops allow us to create multiple resources with the same configuration but with different values.

Count meta argument

  • The count argument allows us to specify how many instances of a resource we want to create.

  • It is useful when we want to create identical resources in a loop, such as creating multiple virtual machines with the same configuration, etc.

  • It expects an integer value, and the resource will be created that many times.

  • When count is used, Terraform assigns an index to each instance, starting from 0, and we can access each resource using count.index.

  • Ex: Create multiple files using the count meta argument

      resource "local_file" "example" {
        filename = "example_file_${count.index + 1}.txt"
        content  = "This is file ${count.index + 1}"
        count    = 3
      }
    
  • Explanation:

    • This will create three files: example_file_1.txt, example_file_2.txt, and example_file_3.txt, with the respective content "This is file 1", "This is file 2", and "This is file 3".

    • The count.index is used to index the resources (starting from 0).

Pros:

  • Simplicity and Ease of Use: The count meta argument is straightforward to use when we need to create a fixed number of identical resources. It’s a simple, index-based repetition mechanism.

  • Good for Creating Identical, Non-Variable Resources: If our resources are identical and don’t need unique attributes per instance (beyond index-based differences), count is ideal.

Cons:

  • No Named Access to Resources:
    When using count, the resources are addressed by their index (e.g., resource_name[count.index]). This can lead to a lack of clarity, especially if we need to reference specific resources based on dynamic conditions.

  • Reordering Resources When Modifying count:
    If we change the count value (e.g., from 3 to 5 or vice versa), Terraform will destroy the existing resources and create new ones to match the new count, it also changes the previous index. This is a destructive operation and can lead to unexpected results if resources are state-dependent or tied to production workloads.

  • Limited Support for Complex Data Structures:
    count is not suitable when we need to loop through complex data structures like maps of objects or lists with nested data, as the count only works with integers and indexes.

For_each meta argument

  • The for_each meta-argument in Terraform is used to create multiple instances of a resource based on a collection (a map, set, or list).

  • Unlike count, which uses a numerical index, for_each gives each resource a meaningful key, allowing you to reference them by their key instead of an index. This makes for_each it more flexible, especially when the resources you're creating have unique attributes.

  • Ex: Create multiple files using the for_each meta argument

      # Define a map of filenames and their content
      variable "files" {
        type = map(string)
        default = {
          "file1" = "This is the content of file1.",
          "file2" = "This is the content of file2.",
          "file3" = "This is the content of file3."
        }
      }
    
      # Use for_each to create files
      resource "local_file" "example" {
        filename = "example_${each.key}.txt"  # Filename based on the key
        content  = each.value          # Content of the file
        for_each = var.files
      }
    
  • Explanation:

    • Used Input variables to define the map-type variables.

    • The for_each meta-argument iterates over the files map and create a local_file resource for each key-value pair. For example:
      A file named example_file1.txt with content "This is the content of file1.", etc.

    • During the iteration, each.key refers to the key in the map (like "file1", "file2") and each.value refers to the value (the file content). This allows us to dynamically assign both the filename and the content based on the map values.

In the future, we will create real-world projects based on this concept, so do subscribe to the newsletter or follow to get an update.

Thank you for reading this far…