Terra Week Challenge Day 3

Create a Terraform configuration file to define a resource of AWS EC2 instance, Azure storage account, Google Compute Engine, etc. (anyone)

# Define provider for AWS
provider "aws" {
  region = "us-west-2"
}

# Define resource for EC2 instance
resource "aws_instance" "example" {
  ami           = "<Your EC2 Instance AMI>"
  instance_type = "t2.micro"
  key_name      = "my-key"

  tags = {
    Name = "example-instance"
  }
}
  1. The configuration starts with defining the provider block for AWS. This block specifies the AWS region to be used for resource provisioning.

  2. The resource block is used to define the EC2 instance resource. The aws_instance resource type is used to create an EC2 instance.

  3. Inside the aws_instance block, you specify the required attributes for the instance. In this example:

    • ami specifies the ID of the Amazon Machine Image (AMI) to be used for the instance.

    • instance_type specifies the EC2 instance type.

    • key_name specifies the name of the key pair used for SSH access to the instance.

    • tags allow you to add metadata tags to the resource, in this case, a name tag.

That's a basic example of AWS EC2 instances. Similarly, you can define resources for other cloud providers like Azure and Google Cloud Platform using their respective Terraform providers and resource blocks.

Check state files before running terraform plan and apply commands and Use validate command to validate your tf file for errors and provide the Output generated by each command

  1. State File :

    It's crucial to confirm that the Terraform state files are in a proper and consistent state before executing the plan and apply commands. The resources that Terraform manages are recorded in the state files along with their present condition.

    To check the state files, you can use the terraform state command. Here are some common state-related commands:

     terraform state list: 
     #Lists all resources tracked in the Terraform state.
     terraform state show: 
     #Displays detailed information about a specific resource in the state.
    

To validate the Terraform configuration file for errors, you can use the terraform validate command. This command checks the syntax and validates the configuration file against any provider requirements or constraint

Understanding Output Generated by Command:

  1. terraform validate command:

Running terraform validate validates the syntax and configuration file for errors. If there are any syntax errors or invalid configurations, it will display an error message. If the file is valid, it will return no output

Output (valid file):

Success! The configuration is valid.

Output (invalid file):

Error: Invalid character
  on main.tf line 5, in resource "aws_instance" "example":
   5:     key_name = my-key
  1. terraform state list command:

Running terraform state list lists all the resources tracked in the Terraform state file.

Output:

aws_instance.example
  1. terraform state show command:

Running terraform state show <resource> displays detailed information about a specific resource in the Terraform state. Replace <resource> with the resource name.

Output:

# aws_instance.example:
resource "aws_instance" "example" {
    ami           = "ami-0c94855ba95c71c99"
    instance_type = "t2.micro"
    key_name      = "my-key"

    tags = {
        Name = "example-instance"
    }
}

terraform plan command: Terraform plan displays the modifications that Terraform will apply to your infrastructure in its output. Terraform intends to create an example AWS EC2 instance in this example.

terraform apply command: Your infrastructure's resources will be created, updated, or destroyed as a result.

terraform destroy command: The terraform destroy command obliterates all of the resources in your infrastructure. This is helpful for testing the disaster recovery procedure or cleaning up outdated infrastructure.

Add a provisioner to the configuration file to configure the resource after it is created and use Terraform commands to apply for changes and destroy to remove resources

Here's an example of adding a provisioner to the aws_instance resource:

resource "aws_instance" "example" {
  ami           = "ami-0c94855ba95c71c99"
  instance_type = "t2.micro"
  key_name      = "my-key"

  tags = {
    Name = "example-instance"
  }

  provisioner "local-exec" {
    command = "echo Instance created: ${self.public_ip}"
  }
}

In the above example, the provisioner block uses the local-exec provisioner type and executes the echo Instance created: ${self.public_ip} shell command. The ${self.public_ip} interpolates the public IP address of the created instance into the command.

Once you have added the provisioner block, you can use the following Terraform commands to apply changes or destroy resources:

  • terraform init: Initializes the Terraform working directory (only required once in a new project).

  • terraform plan: Shows the execution plan for the changes without actually applying them.

  • terraform apply: Applies the changes and creates/updates resources.

  • terraform destroy: Destroys the resources created by Terraform.

Remember to navigate to the directory containing your Terraform configuration file before running these commands.

Note: The local-exec provisioner is just one example. Terraform provides other provisioner types like remote-exec, chef, ansible, etc., depending on your requirements and the available provisioners for the specific resource type.

What is a provisioner block:

You can use provisioners to model specific actions on the local machine or on a remote machine to prepare servers or other infrastructure objects for service.

You can add a provisioner block inside the resource block of a compute instance.

resource "aws_instance" "web" {
  # ...

  provisioner "local-exec" {
    command = "echo The server's IP address is ${self.private_ip}"
  }
}

The local-exec provisioner requires no other configuration, but most other provisioners must connect to the remote system using SSH or WinRM

The self Object

Expressions in provisioner blocks cannot refer to their parent resource by name. Instead, they can use the special self-object.

Creation - Time Provisioners

By default, provisioners run when the resource they are defined within is created. Creation-time provisioners are only run during creation, not during updating or any other lifecycle. They are meant as a means to perform bootstrapping of a system.

Destroy-Time Provisioners

If when = destroy is specified, the provisioner will run when the resource it is defined within is destroyed.

Example :

Here's an example using the null_resource resource type. The null_resource is a resource type that doesn't create or manage any infrastructure but can be used as a placeholder for running provisioners.

resource "null_resource" "example" {
  # Provisioner to run during resource creation
  provisioner "local-exec" {
    command = "echo Resource created at: $(date)"
  }

  # Provisioner to run during resource destruction
  provisioner "local-exec" {
    when    = "destroy"
    command = "echo Resource destroyed at: $(date)"
  }
}

During resource creation, the local-exec provisioner is used to execute the command echo Resource created at: $(date), which will print the current date and time when the resource is created.

During resource destruction, the second local-exec provisioner is triggered by specifying when = "destroy". It will execute the command echo Resource destroyed at: $(date), which will print the current date and time when the resource is destroyed.

Add lifecycle management configurations to the configuration file to control the creation, modification, and deletion of the resource and use Terraform commands to apply the changes

Lifecycle Block

lifecycle is a nested block that can appear within a resource block. The lifecycle block and its contents are meta-arguments, available for all resource blocks regardless of type. The arguments available within a lifecycle block are create_before_destroy, prevent_destroy, ignore_changes, and replace_triggered_by.

resource "aws_instance" "example" {
  ami           = "<Your EC2 Instance AMI Here>"
  instance_type = "t2.micro"
  key_name      = "my-key"

  tags = {
    Name = "example-instance"
  }

  lifecycle {
    create_before_destroy = true
    ignore_changes        = ["tags"]
    prevent_destroy       = false
  }
}

In the above example, the lifecycle block is added to the aws_instance resource and includes three configuration options:

  1. create_before_destroy: When set to true, Terraform will create a new resource before destroying the existing one, ensuring continuous availability during replacement. If not specified, the default value is false.

  2. ignore_changes: This option specifies a list of resource attributes that Terraform should ignore when determining whether changes have occurred.

  3. prevent_destroy: If set to true, Terraform will prevent the resource from being destroyed. This can be useful in scenarios where you want to protect specific resources from accidental deletion. If not specified, the default value is false.

After adding the lifecycle management configurations to your Terraform configuration file, you can use the following Terraform commands to apply the changes:

  • terraform init: Initializes the Terraform working directory (only required once in a new project).

  • terraform plan: Shows the execution plan for the changes without actually applying them.

  • terraform apply: Applies the changes and creates/updates resources.

Thank You! I appreciate your time and effort invested for reading this blog. A feedback is always welcomed and appreciated!