Destroy

Short lab to tear down the environment.

Overview

In this lab you will

  • selectively destroy a resource with commenting
  • destroy the whole environment with terraform destroy
  • check the state file

Starting point

Your files should look similar to this:

  • provider.tf

    terraform {
      required_providers {
        azurerm = {
          source  = "hashicorp/azurerm"
          version = "~>3.1"
        }
      }
    }
    
    provider "azurerm" {
      features {}
    
      storage_use_azuread = true
    }
    
  • variables.tf

    variable "resource_group_name" {
      description = "Name for the resource group"
      type        = string
      default     = "terraform-basics"
    }
    
    variable "location" {
      description = "Azure region"
      type        = string
      default     = "West Europe"
    }
    
    variable "container_group_name" {
      description = "Name of the container group"
      type        = string
      default     = "terraform-basics"
    }
    
  • main.tf

    locals {
      uniq = substr(sha1(azurerm_resource_group.basics.id), 0, 8)
    }
    
    resource "azurerm_resource_group" "basics" {
      name     = var.resource_group_name
      location = var.location
    
      lifecycle {
        ignore_changes = [
          tags,
        ]
      }
    }
    
    resource "azurerm_container_group" "basics" {
      name                = var.container_group_name
      location            = azurerm_resource_group.basics.location
      resource_group_name = azurerm_resource_group.basics.name
      ip_address_type     = "Public"
      dns_name_label      = "${var.container_group_name}-${local.uniq}"
      os_type             = "Linux"
    
      container {
        name   = "inspectorgadget"
        image  = "jelledruyts/inspectorgadget:latest"
        cpu    = "0.5"
        memory = "1.0"
    
        ports {
          port     = 80
          protocol = "TCP"
        }
      }
    }
    
    resource "azurerm_storage_account" "import_example" {
      name                     = "richeney27182818"
      resource_group_name      = azurerm_resource_group.basics.name
      location                 = azurerm_resource_group.basics.location
      account_tier             = "Standard"
      account_replication_type = "LRS"
    
      allow_nested_items_to_be_public = false
      is_hns_enabled                  = true
      nfsv3_enabled                   = true
    }
    

    ⚠️ Your storage account name will be different.

  • outputs.tf

    output "ip_address" {
      value = azurerm_container_group.basics.ip_address
    }
    
    output "fqdn" {
      value = "http://${azurerm_container_group.basics.fqdn}"
    }
    
  • terraform.tfvars

    location = "UK South"
    

    You may have set a different value for location.

Commenting and renaming

Before we clean up the environment, take a look at how commenting blocks and renaming files can change the behaviour of the CLI commands.

  1. Comment out the container instance

    You can comment individual lines by prepending with either # or //.

    You can comment multiple lines by surrounding the block with /* and */, as shown below.

    /*
    resource "azurerm_container_group" "basics" {
      name                = var.container_group_name
      location            = azurerm_resource_group.basics.location
      resource_group_name = azurerm_resource_group.basics.name
      ip_address_type     = "public"
      dns_name_label      = "${var.container_group_name}-${local.uniq}"
      os_type             = "Linux"
    
      container {
        name   = "inspectorgadget"
        image  = "jelledruyts/inspectorgadget:latest"
        cpu    = "0.5"
        memory = "1.0"
    
        ports {
          port     = 80
          protocol = "TCP"
        }
      }
    }
    */
    

    Users of vscode can also highlight multiple lines and use the CTRL+K,CTRL+C chord to comment, and CTRL+K,CTRL+U to uncomment.

  2. terraform plan

    terraform plan
    

    You should see errors based on the outputs.

  3. Rename the outputs.tf file

    When Terraform runs its commands it is looking at all files in the current directory that match *.tf. You can rename file suffixes and it will ignore those files.

    Rename the outputs files so that it is completely ignored in the diff.

    mv outputs.tf outputs.tf.ignore
    
  4. terraform plan

    terraform plan
    
    azurerm_resource_group.basics: Refreshing state... [id=/subscriptions/2ca40be1-7e80-4f2b-92f7-06b2123a68cc/resourceGroups/terraform-basics]
    azurerm_container_group.basics: Refreshing state... [id=/subscriptions/2ca40be1-7e80-4f2b-92f7-06b2123a68cc/resourceGroups/terraform-basics/providers/Microsoft.ContainerInstance/containerGroups/terraform-basics]
    azurerm_storage_account.import_example: Refreshing state... [id=/subscriptions/2ca40be1-7e80-4f2b-92f7-06b2123a68cc/resourceGroups/terraform-basics/providers/Microsoft.Storage/storageAccounts/richeney27182818]
    
    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_container_group.basics will be destroyed
      # (because azurerm_container_group.basics is not in configuration)
      - resource "azurerm_container_group" "basics" {
          - dns_name_label      = "terraform-basics-c3818179" -> null
          - exposed_port        = [
              - {
                  - port     = 80
                  - protocol = "TCP"
                },
            ] -> null
          - fqdn                = "terraform-basics-c3818179.uksouth.azurecontainer.io" -> null
          - id                  = "/subscriptions/2ca40be1-7e80-4f2b-92f7-06b2123a68cc/resourceGroups/terraform-basics/providers/Microsoft.ContainerInstance/containerGroups/terraform-basics" -> null
          - ip_address          = "20.108.193.216" -> null
          - ip_address_type     = "Public" -> null
          - location            = "uksouth" -> null
          - name                = "terraform-basics" -> null
          - os_type             = "Linux" -> null
          - resource_group_name = "terraform-basics" -> null
          - restart_policy      = "Always" -> null
          - tags                = {} -> null
    
          - container {
              - commands                     = [] -> null
              - cpu                          = 0.5 -> null
              - environment_variables        = {} -> null
              - image                        = "jelledruyts/inspectorgadget:latest" -> null
              - memory                       = 1 -> null
              - name                         = "inspectorgadget" -> null
              - secure_environment_variables = (sensitive value)
    
              - ports {
                  - port     = 80 -> null
                  - protocol = "TCP" -> null
                }
            }
        }
    
    Plan: 0 to add, 0 to change, 1 to destroy.
    
    Changes to Outputs:
      - fqdn       = "http://terraform-basics-c3818179.uksouth.azurecontainer.io" -> null
      - ip_address = "20.108.193.216" -> null
    
    ─────────────────────────────────────────────────────────────────────────────
    
    Note: You didn't use the -out option to save this plan, so Terraform can't
    guarantee to take exactly these actions if you run "terraform apply" now.
    

    The resource is no longer in the config and so Terraform plans to remove it.

    Some of you will be familiar with ARM templates or Bicep and the standard incremental mode, which only ever contributes resources idempotently. If you were to remove resources from the resources array in an ARM template then those resources would remain in the resource group and would have to be manually deleted.

    The Terraform behaviour here is closer to the less commonly used complete mode in ARM / Bicep.

  5. Apply the change

    terraform apply
    

    Approve the change. The container group will be deleted.

terraform destroy

We’ll finish with a command that you will use rarely in production. The terraform destroy command will update state, show the current resources and remove any defined in your files.

  1. Destroy the environment

    terraform destroy
    

    Example output:

    azurerm_resource_group.basics: Refreshing state... [id=/subscriptions/2ca40be1-7e80-4f2b-92f7-06b2123a68cc/resourceGroups/terraform-basics]
    azurerm_storage_account.import_example: Refreshing state... [id=/subscriptions/2ca40be1-7e80-4f2b-92f7-06b2123a68cc/resourceGroups/terraform-basics/providers/Microsoft.Storage/storageAccounts/richeney27182818]
    
    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_resource_group.basics will be destroyed
      - resource "azurerm_resource_group" "basics" {
          - id       = "/subscriptions/2ca40be1-7e80-4f2b-92f7-06b2123a68cc/resourceGroups/terraform-basics" -> null
          - location = "uksouth" -> null
          - name     = "terraform-basics" -> null
          - tags     = {
              - "source" = "terraform"
            } -> null
        }
    
      # azurerm_storage_account.import_example will be destroyed
      - resource "azurerm_storage_account" "import_example" {
          - access_tier                       = "Hot" -> null
          - account_kind                      = "StorageV2" -> null
          - account_replication_type          = "LRS" -> null
          - account_tier                      = "Standard" -> null
          - allow_nested_items_to_be_public   = true -> null
          - enable_https_traffic_only         = true -> null
          - id                                = "/subscriptions/2ca40be1-7e80-4f2b-92f7-06b2123a68cc/resourceGroups/terraform-basics/providers/Microsoft.Storage/storageAccounts/richeney27182818" -> null
          - infrastructure_encryption_enabled = false -> null
          - is_hns_enabled                    = true -> null
          - location                          = "uksouth" -> null
          - min_tls_version                   = "TLS1_2" -> null
          - name                              = "richeney27182818" -> null
          - nfsv3_enabled                     = true -> null
          - primary_access_key                = (sensitive value)
          - primary_blob_connection_string    = (sensitive value)
          - primary_blob_endpoint             = "https://richeney27182818.blob.core.windows.net/" -> null
          - primary_blob_host                 = "richeney27182818.blob.core.windows.net" -> null
          - primary_connection_string         = (sensitive value)
          - primary_dfs_endpoint              = "https://richeney27182818.dfs.core.windows.net/" -> null
          - primary_dfs_host                  = "richeney27182818.dfs.core.windows.net" -> null
          - primary_file_endpoint             = "https://richeney27182818.file.core.windows.net/" -> null
          - primary_file_host                 = "richeney27182818.file.core.windows.net" -> null
          - primary_location                  = "uksouth" -> null
          - primary_queue_endpoint            = "https://richeney27182818.queue.core.windows.net/" -> null
          - primary_queue_host                = "richeney27182818.queue.core.windows.net" -> null
          - primary_table_endpoint            = "https://richeney27182818.table.core.windows.net/" -> null
          - primary_table_host                = "richeney27182818.table.core.windows.net" -> null
          - primary_web_endpoint              = "https://richeney27182818.z33.web.core.windows.net/" -> null
          - primary_web_host                  = "richeney27182818.z33.web.core.windows.net" -> null
          - queue_encryption_key_type         = "Service" -> null
          - resource_group_name               = "terraform-basics" -> null
          - secondary_access_key              = (sensitive value)
          - secondary_connection_string       = (sensitive value)
          - shared_access_key_enabled         = true -> null
          - table_encryption_key_type         = "Service" -> null
          - tags                              = {} -> null
    
          - blob_properties {
              - change_feed_enabled      = false -> null
              - last_access_time_enabled = false -> null
              - versioning_enabled       = false -> null
    
              - delete_retention_policy {
                  - days = 7 -> null
                }
            }
    
          - network_rules {
              - bypass                     = [
                  - "AzureServices",
                ] -> null
              - default_action             = "Deny" -> null
              - ip_rules                   = [] -> null
              - virtual_network_subnet_ids = [] -> null
            }
    
          - queue_properties {
    
              - hour_metrics {
                  - enabled               = true -> null
                  - include_apis          = true -> null
                  - retention_policy_days = 7 -> null
                  - version               = "1.0" -> null
                }
    
              - logging {
                  - delete                = false -> null
                  - read                  = false -> null
                  - retention_policy_days = 0 -> null
                  - version               = "1.0" -> null
                  - write                 = false -> null
                }
    
              - minute_metrics {
                  - enabled               = false -> null
                  - include_apis          = false -> null
                  - retention_policy_days = 0 -> null
                  - version               = "1.0" -> null
                }
            }
    
          - share_properties {
    
              - retention_policy {
                  - days = 7 -> null
                }
            }
    
          - timeouts {}
        }
    
    Plan: 0 to add, 0 to change, 2 to destroy.
    
    Do you really want to destroy all resources?
      Terraform will destroy all your managed infrastructure, as shown above.
      There is no undo. Only 'yes' will be accepted to confirm.
    
      Enter a value: yes
    
    
    azurerm_storage_account.import_example: Destroying... [id=/subscriptions/2ca40be1-7e80-4f2b-92f7-06b2123a68cc/resourceGroups/terraform-basics/providers/Microsoft.Storage/storageAccounts/richeney27182818]
    azurerm_storage_account.import_example: Destruction complete after 2s
    azurerm_resource_group.basics: Destroying... [id=/subscriptions/2ca40be1-7e80-4f2b-92f7-06b2123a68cc/resourceGroups/terraform-basics]
    azurerm_resource_group.basics: Still destroying... [id=/subscriptions/2ca40be1-7e80-4f2b-92f7-...3a68cc/resourceGroups/terraform-basics, 10s elapsed]
    azurerm_resource_group.basics: Destruction complete after 15s
    
    
    Destroy complete! Resources: 2 destroyed.
    
    

Summary

Done! 😊

You have learnt how to initialise Terraform, install providers, format and validate HCL files, how to add resources and plan and apply your configs. You have also worked with simple expressions, locals and outputs, manipulated the state file - including an import - and then managed the destroy phase.


Help us improve

Azure Citadel is a community site built on GitHub, please contribute and send a pull request

 Make a change