Blue Flower

1) Why Terraform?

    Read article Infrastructure As Code (IaC)

2) What is terraform state?

   Terraform state refers to a persistent data store that Terraform uses to keep track of the infrastructure resources it create and manages

3) Where and how this terraform state exists ?

    Terraform state (resource information) is stored in a physical file in JSON format and it usually referred as state file (terraform.tfstate) and its by default stored in the same directory where you run 

    Terraform

4) Is it always mandatory to store it along with Terraform directory?

     No, it can be stored remotely. Example, it can be stored in cloud storage like Azure blob storage, AWS S3 or HashiCorp workspace

5) What is the major benefit of storing the state file remotely?

     For better collaboration, security and reliability.  Example, when multiple team members are working on the same Terraform script there are more changes of concurrent modifications and in this scenario storing state file remotely will resolve this problem by locking and releasing while update by a team member

6) How to install Terraform in my local to start work on it?

     You can download it from official HashiCorp portal by following simple steps  Install Terraform

7) Can you give some important Terraform ?

      terraform init     : Initializes the working directory containing Terraform configuration files.

    terraform plan     : Compares the current state with the desired state defined in the configuration files and generates an execution plan.

      terraform apply    : Applies the changes required to reach the desired state.

      terraform refresh  : Updates the state file with the real-world state of resources.

      terraform state    : Commands for advanced state management, such as listing resources (terraform state list), showing details (terraform state show), moving resources (terraform state mv), 

                                    and removing resources (terraform state rm)

      terraform destroy  : Delete mentioned managed resources through Terraform script 

8) Please detail Terraform script file structure by creating a simple Virtual Machine (VM) in Azure ?

     Sure, I will try to provide it in a pictorial way for ease understanding

    

 9) Can you provide me the content of each file given in your above example ?

      backend.tf

terraform {
  backend "azurerm" {
    resource_group_name   = "terraformTestVM"
    storage_account_name  = "myterraformstorage"
    container_name        = "tfstate"
    key                   = "terraform.tfstate"
  }
}

variables.tf

variable "location" {
  description = "The Azure region to deploy resources"
  default     = "eastus"
}

variable "resource_group_name" {
  description = "The name of the resource group"
  default     = "TerraForm-RG"
}

variable "vm_name" {
  description = "The name of the virtual machine"
  default     = "terraformTestVM"
}

variable "vm_size" {
  description = "The size of the virtual machine"
  default     = "Standard_B1s"
}

variable "admin_username" {
  description = "The admin username for the VM"
  default     = "adminuser"
}
main.tf
 
provider "azurerm" {
  features {}
}

resource "azurerm_resource_group" "rg" {
  name     = var.resource_group_name
  location = var.location

   # Specify that the resource group already exists
  lifecycle {
    ignore_changes = [tags]  # This prevents Terraform from attempting to modify tags
  }
 
}

resource "azurerm_virtual_network" "vnet" {
  name                = "rajaVnet"
  address_space       = ["10.0.0.0/16"]
  location            = azurerm_resource_group.rg.location
  resource_group_name = azurerm_resource_group.rg.name
}

resource "azurerm_subnet" "subnet" {
  name                 = "mySubnet"
  resource_group_name  = azurerm_resource_group.rg.name
  virtual_network_name = azurerm_virtual_network.vnet.name
  address_prefixes     = ["10.0.1.0/24"]
}

resource "azurerm_network_interface" "nic" {
  name                = "myNIC"
  location            = azurerm_resource_group.rg.location
  resource_group_name = azurerm_resource_group.rg.name

  ip_configuration {
    name                          = "internal"
    subnet_id                     = azurerm_subnet.subnet.id
    private_ip_address_allocation = "Dynamic"
  }
}

resource "azurerm_network_security_group" "nsg" {
  name                = "myNSG"
  location            = azurerm_resource_group.rg.location
  resource_group_name = azurerm_resource_group.rg.name

  security_rule {
    name                       = "Allow_SSH"
    priority                   = 1001
    direction                  = "Inbound"
    access                     = "Allow"
    protocol                   = "Tcp"
    source_port_range          = "*"
    destination_port_range     = "22"
    source_address_prefix      = "*"
    destination_address_prefix = "*"
  }
}

resource "azurerm_network_interface_security_group_association" "nsg_association" {
  network_interface_id      = azurerm_network_interface.nic.id
  network_security_group_id = azurerm_network_security_group.nsg.id
}

resource "azurerm_public_ip" "public_ip" {
  name                = "myPublicIP"
  location            = azurerm_resource_group.rg.location
  resource_group_name = azurerm_resource_group.rg.name
  allocation_method   = "Dynamic"
}

resource "azurerm_virtual_machine" "vm" {
  name                  = var.vm_name
  location              = azurerm_resource_group.rg.location
  resource_group_name   = azurerm_resource_group.rg.name
  network_interface_ids = [azurerm_network_interface.nic.id]
  vm_size               = var.vm_size

  os_profile {
    computer_name  = var.vm_name
    admin_username = var.admin_username
    admin_password = "P@ssw0rd1234!"  # Note: For production, use a more secure method for password management.
  }

  os_profile_linux_config {
    disable_password_authentication = false
  }

  storage_os_disk {
    name              = "${var.vm_name}_osdisk"
    caching           = "ReadWrite"
    create_option     = "FromImage"
    managed_disk_type = "Standard_LRS"
  }

  storage_image_reference {
    publisher = "Canonical"
    offer     = "UbuntuServer"
    sku       = "18.04-LTS"
    version   = "latest"
  }

  depends_on = [azurerm_network_interface_security_group_association.nsg_association]

  tags = {
    environment = "Terraform"
  }
}

output "public_ip_address" {
  value = azurerm_public_ip.public_ip.ip_address
}
variables.tfvars
location = "eastus"
resource_group_name = "terraformTestVM"
vm_name= "rajatestVM"
vm_size = "Standard_B1s"
admin_username = "adminuser"
 
 
9) Can you provide me the steps to execute above created VM script files ?
 
     9.1) Prerequisite : 
 
     1) Install Azure CLI
 
     2) Install Terraform
 
     9.2) Steps: 
 
     Step 1: Login into Azure account thru CLI (which set available tenant & subscriptions for your account)

     Step 2: In command prompt go to terraform script folder and run following commands

             terraform apply -var-file="variables.tfvars"
 
          Above command executes main.tf by supplying variables value defined in "variables.tfvars" file and ask interim confirmation that are you OK to create by listing all creation/modification will be done.  Following are the output of above command execution 
 
Acquiring state lock. This may take a few moments...
azurerm_resource_group.rg: Refreshing state... [id=/subscriptions/91ec4999-9cd6-4d56-86d4-dxxx209d7be6/resourceGroups/terraformTestVM
]

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:

# azurerm_network_interface.nic will be created
+ resource "azurerm_network_interface" "nic" {
+ applied_dns_servers = (known after apply)
+ dns_servers = (known after apply)
+ enable_accelerated_networking = false


# azurerm_network_interface_security_group_association.nsg_association will be created
+ resource "azurerm_network_interface_security_group_association" "nsg_association" {
+ id = (known after apply)
+ network_interface_id = (known after apply)
+ network_security_group_id = (known after apply)
}

# azurerm_network_security_group.nsg will be created
+ resource "azurerm_network_security_group" "nsg" {
+ id = (known after apply)
+ location = "eastus"
+ name = "myNSG"
+ resou

# azurerm_public_ip.public_ip will be created
+ resource "azurerm_public_ip" "public_ip" {
+ allocation_method = "Dynamic"
+ ddos_protection_mode = "VirtualNetworkInherited"
+ fqdn = (known after apply)
+ id = (known after apply)
+ idle_timeou


# azurerm_virtual_machine.vm will be created
+ resource "azurerm_virtual_machine" "vm" {
+ availability_set_id = (known after apply)
+ delete_data_disks_on_termination = false
+ delete_os_disk_on_termination = false
+

Plan: 7 to add, 0 to change, 0 to destroy.

Changes to Outputs:
+ public_ip_address = (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  (I confirmed by typing 'yes' here after deliberately reviewed above listing from TF)

azurerm_virtual_network.vnet: Creating...
azurerm_public_ip.public_ip: Creating...
azurerm_network_security_group.nsg: Creating...
........
.........
.........
zurerm_virtual_machine.vm: Creation complete after 19s [id=/subscriptions//91ec4999-9cd6-4d56-86d4-dxxx209d7be6/resourceGroups/terraformTestVM/providers/Microsoft.Compute/virtualMachines/rajatestVM]
Releasing state lock. This may take a few moments...

Apply complete! Resources: 7 added, 0 changed, 0 destroyed.

Outputs:

public_ip_address = ""

 

9) How to delete all the resources created by above scripts ?
 
     From the Terraform direction run below command which delete all resources which are created through this script will be deleted. As like in creation, it asks confirmation before it delete by listing resources to be deleted for more clarity
 
      terraform destroy -var="resource_group_name=terraformTestVM"
 
     Output of above command
 
Acquiring state lock. This may take a few moments...
azurerm_resource_group.rg: Refreshing state... [id=/subscriptions/91ec4999-9cd6-4d56-86d4-dxxx209d7be6/resourceGroups/terraformTestVM]
azurerm_virtual_network.vnet: Refreshing state... [id=/subscriptions/91ec4999-9cd6-4d56-86d4-dxxx209d7be6/resourceGroups/terraformTestVM/providers/Microsoft.Network/virtualNetworks/rajaVnet]
azurerm_public_ip.public_ip: Refreshing state... [id=/subscriptions/91ec4999-9cd6-4d56-86d4-dxxx209d7be6/resourceGroups/terraformTestVM/providers/Microsoft.Network/publicIPAddresses/myPublicIP]
azurerm_network_security_group.nsg: Refreshing state... [id=/subscriptions/91ec4999-9cd6-4d56-86d4-dxxx209d7be6/resourceGroups/terraformTestVM/providers/Microsoft.Network/networkSecurityGroups/myNSG]
azurerm_subnet.subnet: Refreshing state... [id=/subscriptions/91ec4999-9cd6-4d56-86d4-dxxx209d7be6/resourceGroups/terraformTestVM/providers/Microsoft.Network/virtualNetworks/rajaVnet/subnets/mySubnet]
azurerm_network_interface.nic: Refreshing state... [id=/subscriptions/91ec4999-9cd6-4d56-86d4-dxxx209d7be6/resourceGroups/terraformTestVM/providers/Microsoft.Network/networkInterfaces/myNIC]
azurerm_network_interface_security_group_association.nsg_association: Refreshing state... [id=/subscriptions/91ec4999-9cd6-4d56-86d4-dxxx209d7be6/resourceGroups/terraformTestVM/providers/Microsoft.Network/networkInterfaces/myNIC|/subscriptions/91ec4999-9cd6-4d56-86d4-dxxx209d7be6/resourceGroups/terraformTestVM/providers/Microsoft.Network/networkSecurityGroups/myNSG]
azurerm_virtual_machine.vm: Refreshing state... [id=/subscriptions/91ec4999-9cd6-4d56-86d4-dxxx209d7be6/resourceGroups/terraformTestVM/providers/Microsoft.Compute/virtualMachines/rajatestVM]

Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with
the following symbols:
- destroy

Terraform will perform the following actions:

# azurerm_network_interface.nic will be destroyed
- resource "azurerm_network_interface" "nic" {
- applied_dns_servers = [] -> null
- dns_servers = [] -> null
- enable_accelerated_networking = false -> null
- enable_ip_forwarding = false -> null
- id = "/subscriptions/91ec4999-9cd6-4d56-86d4-dxxx209d7be6/resourceGroups/terraformTestVM/providers/Microsoft.Network/networkInterfaces/myNIC" -> null
- internal_domain_name_suffix = "unmumh1g1gyedfjdy5e10qsb2h.bx.internal.cloudapp.net" -> null
- location = "eastus" -> null
- mac_address = "00-0D-3A-1C-A9-E0" -> null
- name = "myNIC" -> null
- private_ip_address = "10.0.1.4" -> null
- private_ip_addresses = [
- "10.0.1.4",
] -> null
- resource_group_name = "terraformTestVM" -> null
- tags = {} -> null
- virtual_machine_id = "/subscriptions/91ec4999-9cd6-4d56-86d4-dxxx209d7be6/resourceGroups/terraformTestVM/providers/Microsoft.Compute/virtualMachines/rajatestVM" -> null
# (4 unchanged attributes hidden)




Error: deleting Resource Group "terraformTestVM": the Resource Group still contains Resources.

│ Terraform is configured to check for Resources within the Resource Group when deleting the Resource Group - and
│ raise an error if nested Resources still exist to avoid unintentionally deleting these Resources.

│ Terraform has detected that the following Resources still exist within the Resource Group:

│ * `/subscriptions/91ec4999-9cd6-4d56-86d4-dxxx209d7be6/resourceGroups/terraformTestVM/providers/Microsoft.Compute/disks/rajatestVM_osdisk`
│ * `/subscriptions/91ec4999-9cd6-4d56-86d4-dxxx209d7be6/resourceGroups/terraformTestVM/providers/Microsoft.Storage/storageAccounts/myterraformstorage`

│ This feature is intended to avoid the unintentional destruction of nested Resources provisioned through some
│ other means (for example, an ARM Template Deployment) - as such you must either remove these Resources, or
│ disable this behaviour using the feature flag `prevent_deletion_if_contains_resources` within the `features`
│ block when configuring the Provider, for example:

│ provider "azurerm" {
│ features {
│ resource_group {
│ prevent_deletion_if_contains_resources = false
│ }
│ }
│ }

│ When that feature flag is set, Terraform will skip checking for any Resources within the Resource Group and
│ delete this using the Azure API directly (which will clear up any nested resources).

│ More information on the `features` block can be found in the documentation:
│ https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/guides/features-block




Releasing state lock. This may take a few moments...
 
10) You said that above command will delete all mentioned resources but why it was giving error after deleting few resources ?
 
       You are right ! As I mentioned above it will delete all the resources which are defined and created through the main Terraform script ie., main.tf
 
       In above case, I created manually the Azure storage account under the resource group which is not defined in the main.tf thus it didn't delete it but it try to delete the RG by keeping the storage account thus got above error that couldn't delete resource group as it contains few resources :)
 

You have no rights to post comments