Microsoft invest deeply on Hashicorp Terraform, 15 minutes how to use Terraform with Azure

    No Comments

    5 months ago I attended a Cloud Native hands-on lab on Kubernets and Terraform @ Oracle in Rome, my interest for Terraform started last year because in my opinion this tool can lessen vendor lock-in effect.
    Thanks to his providers it can manage Infrastructure as Code of many cloud providers as Amazon AWS, Microsoft Azure, Google Cloud, IBM Bluemix, Alibaba AliCloud and so on.
    IT professionals are struggling learning script languages and configuration tools for managing and building infrastructure that are deprecated fast, with Terraform you follow a Desiderd State Configuration approach but in a neutral fashion, it has not all the feature of Cloudformation of AWS and cannot supersede configuration manager tools as Puppet, Chef, Ansible and SCCM but it should simplify and speed up IaC.
    If you are good in connecting dots you could envision where the digital transformation is directing.
    I would like to recall the Powershell + DevOps Global Summit 2018 by Microsoft Technical Fellow Jeffrey Snover, that I watched on Youtube.

    In this talk I picked some good points:
    Jeffrey talked about spend calories on Terraform, stating that IT world is in a messy state and always will be,

    powershell is a glue that let you “manage” chaos, but we need to reduce complexity more, for support digital transformation From ANY client manage ANY cloud or on-premise using ANY hypervisor Any storage and ANY networking.
    Infrastructure can be versioned and anyone can contribute on github.
    In his predictions Jeffrey talk about CrossStack IT and the need to be Expert in Learning.

     

    In the meantime Microsoft acquired Github and Corey Sanders Corporate Vice President Azure in August 2018 announced to invest DEEPLY in Terraform.
    https://azure.microsoft.com/en-us/blog/investing-deeply-in-terraform-on-azure/

    Hashicorp founder of Terraform released a Webinar demo for getting started with Terraform on Azure in less than 15 minutes by his Solutions Engineer Sean Carolan https://www.hashicorp.com/resources/hangout-terraform-azure-for-beginners.

    Provisioning your first application in 15 minutes and subscribing to Microsoft Visual Studio Dev Essential for on-going Azure free-credit.
    If you follow the video you can learn that Terraform is not difficult like learning C, you have not to be a Software Engineer to use Terraform. Microsoft Azure is a cloud computing platform that you can use to run your infrastructure and applications. On Azure you can run Windows and Linux Virtual Machines, Containers, Networks, Database, FaaS (Functions as a Service) and so on. Many company struggle running Datacenter in a traditional way.
    Terraform is a language and a tool that quickly provision Infrastructure into any cloud, it is also called executable documentation and it is self-documented code. Terraform is easy to learn is human and machine readable and it is very easy to test, re-use and automate.

    Logon in a Azure Portal you can easily sign-up for one for free, Microsoft will give you 200$ for free to use in your first 30 days, or if you like an on-going account that you can use for development anytime you can sign for Visual Studio Dev Essential Program and Microsoft will give you 25$ amount in credit that you can use.

    In order to learn in a production like enviroment and experiment online  we need free Azure credit that not expire so lets subscribe to Microsoft Visual Studio Dev Essential Program and then continue with Terraform.

    Visual Studio Dev Essentials

     

     

     

     

    Click on Join or access now and Select Azure

    Subscribe using a Credit Card or using a Debit Card with your name on it, pre-paid card are not accepted

    Here we are with $200 170€ today of free credit on Azure plus 25 $ every month.

    Using the Azure UI portal for creating Virtual Machines and other resources does not scale well, and humans commit mistakes doing the same repetable tasks over and over. Manually creating and customize different virtual machines or OS are called snowflakes by the DevOps movement. Just think resources (servers, vm, networks etc.) as they are cattle and not as pet we need easy disposable resources and to obtain that we need to strive for idempotence helping replay and resubmission of the same code having the same results on the resources created in any point of time and in any place. Thanks to this level of abastraction we can realize a part of what is called SDDC (Software-defined data center) this should free many IT professionals from depend on physical hardware and favourite remote workers and smart working, they can spend the time saved to manually build servers learning scripting, coding and tools for manage the cloudnative applications. All your past experience is useful in this new way of managing data centers, your skills will help you to size and scale correctly the applications and their subsets.

    Let’s see how we can realize this with Azure ARM and Terraform.

    Microsoft ARM (Azure Resource Manager) Templates are pre-configured settings that allow you to define your Azure infrastructure and it’s a form of Infrastructures as Code and defined in JSON. In the video Sean Carolan clearly demonstrated how JSON files are not humans friendly because are error prone, he used a JSON Validator service on  https://jsonlint.com he tried to edit some commas and curly braces in a json file that obviously breaked the code. He called it a nightmare, being in a “jungle JSON” did not help to find the missing comma.

    Here we can see the difference between JSON and Terraform in defining local variables for custom names and running a simple shell script with parameters, as you will note, JSON commands are longer and require spaces. Terraform code are more like CLI commands.

    So let’s return to Azure portal and click on the cloud shell and check the Terraform version number.

    We need to clone the github repo from scarolan github space, for the sake of clarity I will underline some azure bash/powershell commands and results as they were code.

    PS Azure:\> terraform --version
    Terraform v0.11.8
    
    Azure:/
    PS Azure:\> git --version
    git version 2.7.4
    Azure:/
    PS Azure:\> git clone https://github.com/scarolan/azure-terraform-beginners
    Cloning into 'azure-terraform-beginners'...
    remote: Counting objects: 58, done.
    remote: Compressing objects: 100% (48/48), done.
    remote: Total 58 (delta 23), reused 36 (delta 9), pack-reused 0
    Unpacking objects: 100% (58/58), done.
    Checking connectivity... done.
    PS Azure:\> ls
    azure-terraform-beginners  clouddrive  Windows Azure Powershell
    Azure:/

    Anything that ends in .tf file extensions are Terraform code and other files are needed for support Terraform code or provide documentation.

    Just copy the example files to our own variables file that we can use

    @Azure:~/azure-terraform-beginners$ ls
    docs  files  LICENSE  main.tf  outputs.tf  README.md  terraform.tfvars.example  variables.tf
    @Azure:~/azure-terraform-beginners$ cp terraform.tfvars.example terraform.tfvars

    Cloud Shell Host on Azure include built-in editors as nano, vi, emacs and code that we can launch using the command code on the shell, here I am using vi and pasting the screenshot of the terraform.tfvars code

    You can see available regions launching this azure command:

    Requesting a Cloud Shell.Succeeded.
    Connecting terminal...
    
    @Azure:~$ az account list-locations --output table
    DisplayName          Latitude    Longitude    Name
    -------------------  ----------  -----------  ------------------
    East Asia            22.267      114.188      eastasia
    Southeast Asia       1.283       103.833      southeastasia
    Central US           41.5908     -93.6208     centralus
    East US              37.3719     -79.8164     eastus
    East US 2            36.6681     -78.3889     eastus2
    West US              37.783      -122.417     westus
    North Central US     41.8819     -87.6278     northcentralus
    South Central US     29.4167     -98.5        southcentralus
    North Europe         53.3478     -6.2597      northeurope
    West Europe          52.3667     4.9          westeurope
    Japan West           34.6939     135.5022     japanwest
    Japan East           35.68       139.77       japaneast
    Brazil South         -23.55      -46.633      brazilsouth
    Australia East       -33.86      151.2094     australiaeast
    Australia Southeast  -37.8136    144.9631     australiasoutheast
    South India          12.9822     80.1636      southindia
    Central India        18.5822     73.9197      centralindia
    West India           19.088      72.868       westindia
    Canada Central       43.653      -79.383      canadacentral
    Canada East          46.817      -71.217      canadaeast
    UK South             50.941      -0.799       uksouth
    UK West              53.427      -3.084       ukwest
    West Central US      40.890      -110.234     westcentralus
    West US 2            47.233      -119.852     westus2
    Korea Central        37.5665     126.9780     koreacentral
    Korea South          35.1796     129.0756     koreasouth
    France Central       46.3772     2.3730       francecentral
    France South         43.8345     2.1972       francesouth
    Australia Central    -35.3075    149.1244     australiacentral
    Australia Central 2  -35.3075    149.1244     australiacentral2

    To check if the Standard_A0 instance is aivalable in your region you can launch this command:

    Azure:~$ az vm list-skus -l centralus --output table | grep Standard_A0
    virtualMachines   centralus    Standard_A0                  ['MaxResourceVolumeMB=20480', 'OSVhdSizeMB=1047552', 'vCPUs=1', 'MemoryGB=0.75', 'MaxDataDiskCount=1', 'LowPriorityCapable=False', 'PremiumIO=False']  None

    Now we can save the file in the editor and start to run this terraform init command in order to load plugin and modules grabbing the Azure ARM provider

    Azure:~/azure-terraform-beginners$ terraform init
    
    Initializing provider plugins...
    - Checking for available provider plugins on https://releases.hashicorp.com...
    - Downloading plugin for provider "azurerm" (1.13.0)...
    
    The following providers do not have any version constraints in configuration,
    so the latest version was installed.
    
    To prevent automatic upgrades to new major versions that may contain breaking
    changes, it is recommended to add version = "..." constraints to the
    corresponding provider blocks in configuration, with the constraint strings
    suggested below.
    
    * provider.azurerm: version = "~> 1.13"
    
    Terraform has been successfully initialized!
    
    You may now begin working with Terraform. Try running "terraform plan" to see
    any changes that are required for your infrastructure. All Terraform commands
    should now work.
    
    If you ever set or change modules or backend configuration for Terraform,
    rerun this command to reinitialize your working directory. If you forget, other
    commands will detect it and remind you to do so if necessary.

    The next step is to run terraform plan that is like a dry run showing you what the command would do, it is similar to whatif in powershell

    @Azure:~/azure-terraform-beginners$ terraform plan
    Refreshing Terraform state in-memory prior to plan...
    The refreshed state will be used to calculate this plan, but will not be
    persisted to local or remote state storage.
    
    
    ------------------------------------------------------------------------
    
    An execution plan has been generated and is shown below.
    Resource actions are indicated with the following symbols:
      + create
    
    Terraform will perform the following actions:
    
      + azurerm_network_interface.tf-guide-nic
          id:                                                                    <computed>
          applied_dns_servers.#:                                                 <computed>
          dns_servers.#:                                                         <computed>
          enable_accelerated_networking:                                         "false"
          enable_ip_forwarding:                                                  "false"
          internal_dns_name_label:                                               <computed>
          internal_fqdn:                                                         <computed>
          ip_configuration.#:                                                    "1"
          ip_configuration.0.application_gateway_backend_address_pools_ids.#:    <computed>
          ip_configuration.0.application_security_group_ids.#:                   <computed>
          ip_configuration.0.load_balancer_backend_address_pools_ids.#:          <computed>
          ip_configuration.0.load_balancer_inbound_nat_rules_ids.#:              <computed>
          ip_configuration.0.name:                                               "tfguideipconfig"
          ip_configuration.0.primary:                                            <computed>
          ip_configuration.0.private_ip_address_allocation:                      "dynamic"
          ip_configuration.0.public_ip_address_id:                               "${azurerm_public_ip.tf-guide-pip.id}"
          ip_configuration.0.subnet_id:                                          "${azurerm_subnet.subnet.id}"
          location:                                                              "centralus"
          mac_address:                                                           <computed>
          name:                                                                  "tfguidetf-guide-nic"
          network_security_group_id:                                             "${azurerm_network_security_group.tf-guide-sg.id}"
          private_ip_address:                                                    <computed>
          private_ip_addresses.#:                                                <computed>
          resource_group_name:                                                   "terraform-beginners-cloudnatives"
          tags.%:                                                                <computed>
          virtual_machine_id:                                                    <computed>
    
      + azurerm_network_security_group.tf-guide-sg
          id:                                                                    <computed>
          location:                                                              "centralus"
          name:                                                                  "tfguide-sg"
          resource_group_name:                                                   "terraform-beginners-cloudnatives"
          security_rule.#:                                                       "2"
          security_rule.2008300084.access:                                       "Allow"
          security_rule.2008300084.description:                                  ""
          security_rule.2008300084.destination_address_prefix:                   "*"
          security_rule.2008300084.destination_address_prefixes.#:               "0"
          security_rule.2008300084.destination_application_security_group_ids.#: "0"
          security_rule.2008300084.destination_port_range:                       "22"
          security_rule.2008300084.destination_port_ranges.#:                    "0"
          security_rule.2008300084.direction:                                    "Inbound"
          security_rule.2008300084.name:                                         "SSH"
          security_rule.2008300084.priority:                                     "101"
          security_rule.2008300084.protocol:                                     "Tcp"
          security_rule.2008300084.source_address_prefix:                        "*"
          security_rule.2008300084.source_address_prefixes.#:                    "0"
          security_rule.2008300084.source_application_security_group_ids.#:      "0"
          security_rule.2008300084.source_port_range:                            "*"
          security_rule.2008300084.source_port_ranges.#:                         "0"
          security_rule.920215974.access:                                        "Allow"
          security_rule.920215974.description:                                   ""
          security_rule.920215974.destination_address_prefix:                    "*"
          security_rule.920215974.destination_address_prefixes.#:                "0"
          security_rule.920215974.destination_application_security_group_ids.#:  "0"
          security_rule.920215974.destination_port_range:                        "80"
          security_rule.920215974.destination_port_ranges.#:                     "0"
          security_rule.920215974.direction:                                     "Inbound"
          security_rule.920215974.name:                                          "HTTP"
          security_rule.920215974.priority:                                      "100"
          security_rule.920215974.protocol:                                      "Tcp"
          security_rule.920215974.source_address_prefix:                         "*"
          security_rule.920215974.source_address_prefixes.#:                     "0"
          security_rule.920215974.source_application_security_group_ids.#:       "0"
          security_rule.920215974.source_port_range:                             "*"
          security_rule.920215974.source_port_ranges.#:                          "0"
          tags.%:                                                                <computed>
    
      + azurerm_public_ip.tf-guide-pip
          id:                                                                    <computed>
          domain_name_label:                                                     "cloudnative2018"
          fqdn:                                                                  <computed>
          ip_address:                                                            <computed>
          location:                                                              "centralus"
          name:                                                                  "tfguide-ip"
          public_ip_address_allocation:                                          "dynamic"
          resource_group_name:                                                   "terraform-beginners-cloudnatives"
          sku:                                                                   "Basic"
          tags.%:                                                                <computed>
    
      + azurerm_resource_group.tf_azure_guide
          id:                                                                    <computed>
          location:                                                              "centralus"
          name:                                                                  "terraform-beginners-cloudnatives"
          tags.%:                                                                <computed>
    
      + azurerm_subnet.subnet
          id:                                                                    <computed>
          address_prefix:                                                        "10.0.10.0/24"
          ip_configurations.#:                                                   <computed>
          name:                                                                  "tfguidesubnet"
          resource_group_name:                                                   "terraform-beginners-cloudnatives"
          virtual_network_name:                                                  "vnet"
    
      + azurerm_virtual_machine.site
          id:                                                                    <computed>
          availability_set_id:                                                   <computed>
          delete_data_disks_on_termination:                                      "false"
          delete_os_disk_on_termination:                                         "true"
          identity.#:                                                            <computed>
          location:                                                              "centralus"
          name:                                                                  "cloudnative2018-site"
          network_interface_ids.#:                                               <computed>
          os_profile.#:                                                          "1"
          os_profile.4035639915.admin_password:                                  <sensitive>
          os_profile.4035639915.admin_username:                                  "adminuser"
          os_profile.4035639915.computer_name:                                   "cloudnative2018"
          os_profile.4035639915.custom_data:                                     <computed>
          os_profile_linux_config.#:                                             "1"
          os_profile_linux_config.2972667452.disable_password_authentication:    "false"
          os_profile_linux_config.2972667452.ssh_keys.#:                         "0"
          resource_group_name:                                                   "terraform-beginners-cloudnatives"
          storage_data_disk.#:                                                   <computed>
          storage_image_reference.#:                                             "1"
          storage_image_reference.1458860473.id:                                 ""
          storage_image_reference.1458860473.offer:                              "UbuntuServer"
          storage_image_reference.1458860473.publisher:                          "Canonical"
          storage_image_reference.1458860473.sku:                                "16.04-LTS"
          storage_image_reference.1458860473.version:                            "latest"
          storage_os_disk.#:                                                     "1"
          storage_os_disk.0.caching:                                             "ReadWrite"
          storage_os_disk.0.create_option:                                       "FromImage"
          storage_os_disk.0.disk_size_gb:                                        <computed>
          storage_os_disk.0.managed_disk_id:                                     <computed>
          storage_os_disk.0.managed_disk_type:                                   "Standard_LRS"
          storage_os_disk.0.name:                                                "cloudnative2018-osdisk"
          storage_os_disk.0.write_accelerator_enabled:                           "false"
          tags.%:                                                                <computed>
          vm_size:                                                               "Standard_A0"
    
      + azurerm_virtual_network.vnet
          id:                                                                    <computed>
          address_space.#:                                                       "1"
          address_space.0:                                                       "10.0.0.0/16"
          location:                                                              "centralus"
          name:                                                                  "vnet"
          resource_group_name:                                                   "terraform-beginners-cloudnatives"
          subnet.#:                                                              <computed>
          tags.%:                                                                <computed>
    
    
    Plan: 7 to add, 0 to change, 0 to destroy.
    
    ------------------------------------------------------------------------
    
    Note: You didn't specify an "-out" parameter to save this plan, so Terraform
    can't guarantee that exactly these actions will be performed if
    "terraform apply" is subsequently run.

    We have 7 new resources to add and we can create this infrastracture using the command terraform apply , after some seconds terraform will ask you to confirm with yes, you can using the autoapprove to avoid to type yes everytime.

    @Azure:~/azure-terraform-beginners$ terraform apply
    
    An execution plan has been generated and is shown below.
    Resource actions are indicated with the following symbols:
      + create
    
    Terraform will perform the following actions:
    
      + azurerm_network_interface.tf-guide-nic
          id:                                                                    <computed>
          applied_dns_servers.#:                                                 <computed>
          dns_servers.#:                                                         <computed>
          enable_accelerated_networking:                                         "false"
          enable_ip_forwarding:                                                  "false"
          internal_dns_name_label:                                               <computed>
          internal_fqdn:                                                         <computed>
          ip_configuration.#:                                                    "1"
          ip_configuration.0.application_gateway_backend_address_pools_ids.#:    <computed>
          ip_configuration.0.application_security_group_ids.#:                   <computed>
          ip_configuration.0.load_balancer_backend_address_pools_ids.#:          <computed>
          ip_configuration.0.load_balancer_inbound_nat_rules_ids.#:              <computed>
          ip_configuration.0.name:                                               "tfguideipconfig"
          ip_configuration.0.primary:                                            <computed>
          ip_configuration.0.private_ip_address_allocation:                      "dynamic"
          ip_configuration.0.public_ip_address_id:                               "${azurerm_public_ip.tf-guide-pip.id}"
          ip_configuration.0.subnet_id:                                          "${azurerm_subnet.subnet.id}"
          location:                                                              "centralus"
          mac_address:                                                           <computed>
          name:                                                                  "tfguidetf-guide-nic"
          network_security_group_id:                                             "${azurerm_network_security_group.tf-guide-sg.id}"
          private_ip_address:                                                    <computed>
          private_ip_addresses.#:                                                <computed>
          resource_group_name:                                                   "terraform-beginners-cloudnatives"
          tags.%:                                                                <computed>
          virtual_machine_id:                                                    <computed>
    
      + azurerm_network_security_group.tf-guide-sg
          id:                                                                    <computed>
          location:                                                              "centralus"
          name:                                                                  "tfguide-sg"
          resource_group_name:                                                   "terraform-beginners-cloudnatives"
          security_rule.#:                                                       "2"
          security_rule.2008300084.access:                                       "Allow"
          security_rule.2008300084.description:                                  ""
          security_rule.2008300084.destination_address_prefix:                   "*"
          security_rule.2008300084.destination_address_prefixes.#:               "0"
          security_rule.2008300084.destination_application_security_group_ids.#: "0"
          security_rule.2008300084.destination_port_range:                       "22"
          security_rule.2008300084.destination_port_ranges.#:                    "0"
          security_rule.2008300084.direction:                                    "Inbound"
          security_rule.2008300084.name:                                         "SSH"
          security_rule.2008300084.priority:                                     "101"
          security_rule.2008300084.protocol:                                     "Tcp"
          security_rule.2008300084.source_address_prefix:                        "*"
          security_rule.2008300084.source_address_prefixes.#:                    "0"
          security_rule.2008300084.source_application_security_group_ids.#:      "0"
          security_rule.2008300084.source_port_range:                            "*"
          security_rule.2008300084.source_port_ranges.#:                         "0"
          security_rule.920215974.access:                                        "Allow"
          security_rule.920215974.description:                                   ""
          security_rule.920215974.destination_address_prefix:                    "*"
          security_rule.920215974.destination_address_prefixes.#:                "0"
          security_rule.920215974.destination_application_security_group_ids.#:  "0"
          security_rule.920215974.destination_port_range:                        "80"
          security_rule.920215974.destination_port_ranges.#:                     "0"
          security_rule.920215974.direction:                                     "Inbound"
          security_rule.920215974.name:                                          "HTTP"
          security_rule.920215974.priority:                                      "100"
          security_rule.920215974.protocol:                                      "Tcp"
          security_rule.920215974.source_address_prefix:                         "*"
          security_rule.920215974.source_address_prefixes.#:                     "0"
          security_rule.920215974.source_application_security_group_ids.#:       "0"
          security_rule.920215974.source_port_range:                             "*"
          security_rule.920215974.source_port_ranges.#:                          "0"
          tags.%:                                                                <computed>
    
      + azurerm_public_ip.tf-guide-pip
          id:                                                                    <computed>
          domain_name_label:                                                     "cloudnative2018"
          fqdn:                                                                  <computed>
          ip_address:                                                            <computed>
          location:                                                              "centralus"
          name:                                                                  "tfguide-ip"
          public_ip_address_allocation:                                          "dynamic"
          resource_group_name:                                                   "terraform-beginners-cloudnatives"
          sku:                                                                   "Basic"
          tags.%:                                                                <computed>
    
      + azurerm_resource_group.tf_azure_guide
          id:                                                                    <computed>
          location:                                                              "centralus"
          name:                                                                  "terraform-beginners-cloudnatives"
          tags.%:                                                                <computed>
    
      + azurerm_subnet.subnet
          id:                                                                    <computed>
          address_prefix:                                                        "10.0.10.0/24"
          ip_configurations.#:                                                   <computed>
          name:                                                                  "tfguidesubnet"
          resource_group_name:                                                   "terraform-beginners-cloudnatives"
          virtual_network_name:                                                  "vnet"
    
      + azurerm_virtual_machine.site
          id:                                                                    <computed>
          availability_set_id:                                                   <computed>
          delete_data_disks_on_termination:                                      "false"
          delete_os_disk_on_termination:                                         "true"
          identity.#:                                                            <computed>
          location:                                                              "centralus"
          name:                                                                  "cloudnative2018-site"
          network_interface_ids.#:                                               <computed>
          os_profile.#:                                                          "1"
          os_profile.4035639915.admin_password:                                  <sensitive>
          os_profile.4035639915.admin_username:                                  "adminuser"
          os_profile.4035639915.computer_name:                                   "cloudnative2018"
          os_profile.4035639915.custom_data:                                     <computed>
          os_profile_linux_config.#:                                             "1"
          os_profile_linux_config.2972667452.disable_password_authentication:    "false"
          os_profile_linux_config.2972667452.ssh_keys.#:                         "0"
          resource_group_name:                                                   "terraform-beginners-cloudnatives"
          storage_data_disk.#:                                                   <computed>
          storage_image_reference.#:                                             "1"
          storage_image_reference.1458860473.id:                                 ""
          storage_image_reference.1458860473.offer:                              "UbuntuServer"
          storage_image_reference.1458860473.publisher:                          "Canonical"
          storage_image_reference.1458860473.sku:                                "16.04-LTS"
          storage_image_reference.1458860473.version:                            "latest"
          storage_os_disk.#:                                                     "1"
          storage_os_disk.0.caching:                                             "ReadWrite"
          storage_os_disk.0.create_option:                                       "FromImage"
          storage_os_disk.0.disk_size_gb:                                        <computed>
          storage_os_disk.0.managed_disk_id:                                     <computed>
          storage_os_disk.0.managed_disk_type:                                   "Standard_LRS"
          storage_os_disk.0.name:                                                "cloudnative2018-osdisk"
          storage_os_disk.0.write_accelerator_enabled:                           "false"
          tags.%:                                                                <computed>
          vm_size:                                                               "Standard_A0"
    
      + azurerm_virtual_network.vnet
          id:                                                                    <computed>
          address_space.#:                                                       "1"
          address_space.0:                                                       "10.0.0.0/16"
          location:                                                              "centralus"
          name:                                                                  "vnet"
          resource_group_name:                                                   "terraform-beginners-cloudnatives"
          subnet.#:                                                              <computed>
          tags.%:                                                                <computed>
    
    
    Plan: 7 to add, 0 to change, 0 to destroy.
    
    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
    
    azurerm_resource_group.tf_azure_guide: Creating...
      location: "" => "centralus"
      name:     "" => "terraform-beginners-cloudnatives"
      tags.%:   "" => "<computed>"
    azurerm_resource_group.tf_azure_guide: Creation complete after 2s (ID: /subscriptions/2ac9601a-099e-4e3e-91a9-...roups/terraform-beginners-cloudnatives)
    azurerm_public_ip.tf-guide-pip: Creating...
      domain_name_label:            "" => "cloudnative2018"
      fqdn:                         "" => "<computed>"
      ip_address:                   "" => "<computed>"
      location:                     "" => "centralus"
      name:                         "" => "tfguide-ip"
      public_ip_address_allocation: "" => "dynamic"
      resource_group_name:          "" => "terraform-beginners-cloudnatives"
      sku:                          "" => "Basic"
      tags.%:                       "" => "<computed>"
    azurerm_virtual_network.vnet: Creating...
      address_space.#:     "" => "1"
      address_space.0:     "" => "10.0.0.0/16"
      location:            "" => "centralus"
      name:                "" => "vnet"
      resource_group_name: "" => "terraform-beginners-cloudnatives"
      subnet.#:            "" => "<computed>"
      tags.%:              "" => "<computed>"
    azurerm_network_security_group.tf-guide-sg: Creating...
      location:                                                              "" => "centralus"
      name:                                                                  "" => "tfguide-sg"
      resource_group_name:                                                   "" => "terraform-beginners-cloudnatives"
      security_rule.#:                                                       "" => "2"
      security_rule.2008300084.access:                                       "" => "Allow"
      security_rule.2008300084.description:                                  "" => ""
      security_rule.2008300084.destination_address_prefix:                   "" => "*"
      security_rule.2008300084.destination_address_prefixes.#:               "" => "0"
      security_rule.2008300084.destination_application_security_group_ids.#: "" => "0"
      security_rule.2008300084.destination_port_range:                       "" => "22"
      security_rule.2008300084.destination_port_ranges.#:                    "" => "0"
      security_rule.2008300084.direction:                                    "" => "Inbound"
      security_rule.2008300084.name:                                         "" => "SSH"
      security_rule.2008300084.priority:                                     "" => "101"
      security_rule.2008300084.protocol:                                     "" => "Tcp"
      security_rule.2008300084.source_address_prefix:                        "" => "*"
      security_rule.2008300084.source_address_prefixes.#:                    "" => "0"
      security_rule.2008300084.source_application_security_group_ids.#:      "" => "0"
      security_rule.2008300084.source_port_range:                            "" => "*"
      security_rule.2008300084.source_port_ranges.#:                         "" => "0"
      security_rule.920215974.access:                                        "" => "Allow"
      security_rule.920215974.description:                                   "" => ""
      security_rule.920215974.destination_address_prefix:                    "" => "*"
      security_rule.920215974.destination_address_prefixes.#:                "" => "0"
      security_rule.920215974.destination_application_security_group_ids.#:  "" => "0"
      security_rule.920215974.destination_port_range:                        "" => "80"
      security_rule.920215974.destination_port_ranges.#:                     "" => "0"
      security_rule.920215974.direction:                                     "" => "Inbound"
      security_rule.920215974.name:                                          "" => "HTTP"
      security_rule.920215974.priority:                                      "" => "100"
      security_rule.920215974.protocol:                                      "" => "Tcp"
      security_rule.920215974.source_address_prefix:                         "" => "*"
      security_rule.920215974.source_address_prefixes.#:                     "" => "0"
      security_rule.920215974.source_application_security_group_ids.#:       "" => "0"
      security_rule.920215974.source_port_range:                             "" => "*"
      security_rule.920215974.source_port_ranges.#:                          "" => "0"
      tags.%:                                                                "" => "<computed>"
    azurerm_public_ip.tf-guide-pip: Still creating... (10s elapsed)
    azurerm_virtual_network.vnet: Still creating... (10s elapsed)
    azurerm_network_security_group.tf-guide-sg: Still creating... (10s elapsed)
    azurerm_virtual_network.vnet: Creation complete after 13s (ID: /subscriptions/2ac9601a-099e-4e3e-91a9-...Microsoft.Network/virtualNetworks/vnet)
    azurerm_subnet.subnet: Creating...
      address_prefix:       "" => "10.0.10.0/24"
      ip_configurations.#:  "" => "<computed>"
      name:                 "" => "tfguidesubnet"
      resource_group_name:  "" => "terraform-beginners-cloudnatives"
      virtual_network_name: "" => "vnet"
    azurerm_network_security_group.tf-guide-sg: Creation complete after 13s (ID: /subscriptions/2ac9601a-099e-4e3e-91a9-...twork/networkSecurityGroups/tfguide-sg)
    azurerm_public_ip.tf-guide-pip: Creation complete after 16s (ID: /subscriptions/2ac9601a-099e-4e3e-91a9-...t.Network/publicIPAddresses/tfguide-ip)
    azurerm_subnet.subnet: Still creating... (10s elapsed)
    azurerm_subnet.subnet: Creation complete after 11s (ID: /subscriptions/2ac9601a-099e-4e3e-91a9-...ualNetworks/vnet/subnets/tfguidesubnet)
    azurerm_network_interface.tf-guide-nic: Creating...
      applied_dns_servers.#:                                              "" => "<computed>"
      dns_servers.#:                                                      "" => "<computed>"
      enable_accelerated_networking:                                      "" => "false"
      enable_ip_forwarding:                                               "" => "false"
      internal_dns_name_label:                                            "" => "<computed>"
      internal_fqdn:                                                      "" => "<computed>"
      ip_configuration.#:                                                 "" => "1"
      ip_configuration.0.application_gateway_backend_address_pools_ids.#: "" => "<computed>"
      ip_configuration.0.application_security_group_ids.#:                "" => "<computed>"
      ip_configuration.0.load_balancer_backend_address_pools_ids.#:       "" => "<computed>"
      ip_configuration.0.load_balancer_inbound_nat_rules_ids.#:           "" => "<computed>"
      ip_configuration.0.name:                                            "" => "tfguideipconfig"
      ip_configuration.0.primary:                                         "" => "<computed>"
      ip_configuration.0.private_ip_address_allocation:                   "" => "dynamic"
      ip_configuration.0.public_ip_address_id:                            "" => "/subscriptions/2ac9601a-099e-4e3e-91a9-6b79cd3e35e6/resourceGroups/terraform-beginners-cloudnatives/providers/Microsoft.Network/publicIPAddresses/tfguide-ip"
      ip_configuration.0.subnet_id:                                       "" => "/subscriptions/2ac9601a-099e-4e3e-91a9-6b79cd3e35e6/resourceGroups/terraform-beginners-cloudnatives/providers/Microsoft.Network/virtualNetworks/vnet/subnets/tfguidesubnet"
      location:                                                           "" => "centralus"
      mac_address:                                                        "" => "<computed>"
      name:                                                               "" => "tfguidetf-guide-nic"
      network_security_group_id:                                          "" => "/subscriptions/2ac9601a-099e-4e3e-91a9-6b79cd3e35e6/resourceGroups/terraform-beginners-cloudnatives/providers/Microsoft.Network/networkSecurityGroups/tfguide-sg"
      private_ip_address:                                                 "" => "<computed>"
      private_ip_addresses.#:                                             "" => "<computed>"
      resource_group_name:                                                "" => "terraform-beginners-cloudnatives"
      tags.%:                                                             "" => "<computed>"
      virtual_machine_id:                                                 "" => "<computed>"
    azurerm_network_interface.tf-guide-nic: Creation complete after 2s (ID: /subscriptions/2ac9601a-099e-4e3e-91a9-.../networkInterfaces/tfguidetf-guide-nic)
    azurerm_virtual_machine.site: Creating...
      availability_set_id:                                                "" => "<computed>"
      delete_data_disks_on_termination:                                   "" => "false"
      delete_os_disk_on_termination:                                      "" => "true"
      identity.#:                                                         "" => "<computed>"
      location:                                                           "" => "centralus"
      name:                                                               "" => "cloudnative2018-site"
      network_interface_ids.#:                                            "" => "1"
      network_interface_ids.0:                                            "" => "/subscriptions/2ac9601a-099e-4e3e-91a9-6b79cd3e35e6/resourceGroups/terraform-beginners-cloudnatives/providers/Microsoft.Network/networkInterfaces/tfguidetf-guide-nic"
      os_profile.#:                                                       "" => "1"
      os_profile.4035639915.admin_password:                               "<sensitive>" => "<sensitive>"
      os_profile.4035639915.admin_username:                               "" => "adminuser"
      os_profile.4035639915.computer_name:                                "" => "cloudnative2018"
      os_profile.4035639915.custom_data:                                  "" => "<computed>"
      os_profile_linux_config.#:                                          "" => "1"
      os_profile_linux_config.2972667452.disable_password_authentication: "" => "false"
      os_profile_linux_config.2972667452.ssh_keys.#:                      "" => "0"
      resource_group_name:                                                "" => "terraform-beginners-cloudnatives"
      storage_data_disk.#:                                                "" => "<computed>"
      storage_image_reference.#:                                          "" => "1"
      storage_image_reference.1458860473.id:                              "" => ""
      storage_image_reference.1458860473.offer:                           "" => "UbuntuServer"
      storage_image_reference.1458860473.publisher:                       "" => "Canonical"
      storage_image_reference.1458860473.sku:                             "" => "16.04-LTS"
      storage_image_reference.1458860473.version:                         "" => "latest"
      storage_os_disk.#:                                                  "" => "1"
      storage_os_disk.0.caching:                                          "" => "ReadWrite"
      storage_os_disk.0.create_option:                                    "" => "FromImage"
      storage_os_disk.0.disk_size_gb:                                     "" => "<computed>"
      storage_os_disk.0.managed_disk_id:                                  "" => "<computed>"
      storage_os_disk.0.managed_disk_type:                                "" => "Standard_LRS"
      storage_os_disk.0.name:                                             "" => "cloudnative2018-osdisk"
      storage_os_disk.0.write_accelerator_enabled:                        "" => "false"
      tags.%:                                                             "" => "<computed>"
      vm_size:                                                            "" => "Standard_A0"
    azurerm_virtual_machine.site: Still creating... (10s elapsed)
    azurerm_virtual_machine.site: Still creating... (20s elapsed)
    azurerm_virtual_machine.site: Still creating... (30s elapsed)
    azurerm_virtual_machine.site: Still creating... (40s elapsed)
    azurerm_virtual_machine.site: Still creating... (50s elapsed)
    azurerm_virtual_machine.site: Still creating... (1m0s elapsed)
    azurerm_virtual_machine.site: Still creating... (1m10s elapsed)
    azurerm_virtual_machine.site: Still creating... (1m20s elapsed)
    azurerm_virtual_machine.site: Still creating... (1m30s elapsed)
    azurerm_virtual_machine.site: Still creating... (1m40s elapsed)
    azurerm_virtual_machine.site: Still creating... (1m50s elapsed)
    azurerm_virtual_machine.site: Still creating... (2m0s elapsed)
    azurerm_virtual_machine.site: Still creating... (2m10s elapsed)
    azurerm_virtual_machine.site: Provisioning with 'file'...
    azurerm_virtual_machine.site: Provisioning with 'remote-exec'...
    azurerm_virtual_machine.site (remote-exec): Connecting to remote host via SSH...
    azurerm_virtual_machine.site (remote-exec):   Host: cloudnative2018.centralus.cloudapp.azure.com
    azurerm_virtual_machine.site (remote-exec):   User: adminuser
    azurerm_virtual_machine.site (remote-exec):   Password: true
    azurerm_virtual_machine.site (remote-exec):   Private key: false
    azurerm_virtual_machine.site (remote-exec):   SSH Agent: false
    azurerm_virtual_machine.site (remote-exec):   Checking Host Key: false
    azurerm_virtual_machine.site (remote-exec): Connected!
    azurerm_virtual_machine.site: Still creating... (2m20s elapsed)
    azurerm_virtual_machine.site: Still creating... (2m30s elapsed)
    azurerm_virtual_machine.site: Still creating... (2m40s elapsed)
    azurerm_virtual_machine.site: Still creating... (2m50s elapsed)
    azurerm_virtual_machine.site: Still creating... (3m0s elapsed)
    azurerm_virtual_machine.site: Still creating... (3m10s elapsed)
    azurerm_virtual_machine.site: Still creating... (3m20s elapsed)
    azurerm_virtual_machine.site: Still creating... (3m30s elapsed)
    azurerm_virtual_machine.site: Still creating... (3m40s elapsed)
    azurerm_virtual_machine.site (remote-exec): Your demo is now ready.
    azurerm_virtual_machine.site: Creation complete after 3m45s (ID: /subscriptions/-...e/virtualMachines/cloudnative2018-site)
    
    Apply complete! Resources: 7 added, 0 changed, 0 destroyed.
    
    Outputs:
    
    App_Server_URL = http://cloudnative2018.centralus.cloudapp.azure.com
    _instructions = This output contains plain text. You can add variables too.
    public_dns = cloudnative2018.centralus.cloudapp.azure.com

    We just needed 3 minutes and 40 seconds to deploy this infrastructures and all their resources with a cloud app web page

    This is temporary hosted here http://cloudnative2018.centralus.cloudapp.azure.com/

    And now let’s explain why all this was possible, there are 3 files named main.tf, outputs.tf and variables.tf that are not required but can add values, first we are going to open main.tf where terraform code lives. There are explanatory comments helping to understand each section of the code.

    ##############################################################################
    # HashiCorp Beginner's Guide to Using Terraform on Azure
    # 
    # This Terraform configuration will create the following:
    #
    # * Resource group with a virtual network and subnet
    # * An Ubuntu Linux server running Apache
    
    ##############################################################################
    # Shared infrastructure resources
    
    # First we'll create a resource group. In Azure every resource belongs to a 
    # resource group. Think of it as a container to hold all your resources. 
    # You can find a complete list of Azure resources supported by Terraform here:
    # https://www.terraform.io/docs/providers/azurerm/
    resource "azurerm_resource_group" "tf_azure_guide" {
      name     = "${var.resource_group}"
      location = "${var.location}"
    }
    
    # The next resource is a Virtual Network. We can dynamically place it into the
    # resource group without knowing its name ahead of time. Terraform handles all
    # of that for you, so everything is named consistently every time. Say goodbye
    # to weirdly-named mystery resources in your Azure Portal. To see how all this
    # works visually, run `terraform graph` and copy the output into the online
    # GraphViz tool: http://www.webgraphviz.com/
    resource "azurerm_virtual_network" "vnet" {
      name                = "${var.virtual_network_name}"
      location            = "${azurerm_resource_group.tf_azure_guide.location}"
      address_space       = ["${var.address_space}"]
      resource_group_name = "${azurerm_resource_group.tf_azure_guide.name}"
    }
    
    # Next we'll build a subnet to run our VMs in. These variables can be defined 
    # via environment variables, a config file, or command line flags. Default 
    # values will be used if the user does not override them. You can find all the
    # default variables in the variables.tf file. You can customize this demo by
    # making a copy of the terraform.tfvars.example file.
    resource "azurerm_subnet" "subnet" {
      name                 = "${var.prefix}subnet"
      virtual_network_name = "${azurerm_virtual_network.vnet.name}"
      resource_group_name  = "${azurerm_resource_group.tf_azure_guide.name}"
      address_prefix       = "${var.subnet_prefix}"
    }
    
    ##############################################################################
    # Build an Ubuntu 16.04 Linux VM
    #
    # Now that we have a network, we'll deploy an Ubuntu 16.04 Linux server.
    # An Azure Virtual Machine has several components. In this example we'll build
    # a security group, a network interface, a public ip address, a storage 
    # account and finally the VM itself. Terraform handles all the dependencies 
    # automatically, and each resource is named with user-defined variables.
    
    # Security group to allow inbound access on port 80 (http) and 22 (ssh)
    resource "azurerm_network_security_group" "tf-guide-sg" {
      name                = "${var.prefix}-sg"
      location            = "${var.location}"
      resource_group_name = "${azurerm_resource_group.tf_azure_guide.name}"
    
      security_rule {
        name                       = "HTTP"
        priority                   = 100
        direction                  = "Inbound"
        access                     = "Allow"
        protocol                   = "Tcp"
        source_port_range          = "*"
        destination_port_range     = "80"
        source_address_prefix      = "*"
        destination_address_prefix = "*"
      }
    
      security_rule {
        name                       = "SSH"
        priority                   = 101
        direction                  = "Inbound"
        access                     = "Allow"
        protocol                   = "Tcp"
        source_port_range          = "*"
        destination_port_range     = "22"
        source_address_prefix      = "*"
        destination_address_prefix = "*"
      }
    }
    
    # A network interface. This is required by the azurerm_virtual_machine 
    # resource. Terraform will let you know if you're missing a dependency.
    resource "azurerm_network_interface" "tf-guide-nic" {
      name                      = "${var.prefix}tf-guide-nic"
      location                  = "${var.location}"
      resource_group_name       = "${azurerm_resource_group.tf_azure_guide.name}"
      network_security_group_id = "${azurerm_network_security_group.tf-guide-sg.id}"
    
      ip_configuration {
        name                          = "${var.prefix}ipconfig"
        subnet_id                     = "${azurerm_subnet.subnet.id}"
        private_ip_address_allocation = "Dynamic"
        public_ip_address_id          = "${azurerm_public_ip.tf-guide-pip.id}"
      }
    }
    
    # Every Azure Virtual Machine comes with a private IP address. You can also 
    # optionally add a public IP address for Internet-facing applications and 
    # demo environments like this one.
    resource "azurerm_public_ip" "tf-guide-pip" {
      name                         = "${var.prefix}-ip"
      location                     = "${var.location}"
      resource_group_name          = "${azurerm_resource_group.tf_azure_guide.name}"
      public_ip_address_allocation = "Dynamic"
      domain_name_label            = "${var.hostname}"
    }
    
    # And finally we build our virtual machine. This is a standard Ubuntu instance.
    # We use the shell provisioner to run a Bash script that configures Apache for 
    # the demo environment. Terraform supports several different types of 
    # provisioners including Bash, Powershell and Chef.
    resource "azurerm_virtual_machine" "site" {
      name                = "${var.hostname}-site"
      location            = "${var.location}"
      resource_group_name = "${azurerm_resource_group.tf_azure_guide.name}"
      vm_size             = "${var.vm_size}"
    
      network_interface_ids         = ["${azurerm_network_interface.tf-guide-nic.id}"]
      delete_os_disk_on_termination = "true"
    
      storage_image_reference {
        publisher = "${var.image_publisher}"
        offer     = "${var.image_offer}"
        sku       = "${var.image_sku}"
        version   = "${var.image_version}"
      }
    
      storage_os_disk {
        name              = "${var.hostname}-osdisk"
        managed_disk_type = "Standard_LRS"
        caching           = "ReadWrite"
        create_option     = "FromImage"
      }
    
      os_profile {
        computer_name  = "${var.hostname}"
        admin_username = "${var.admin_username}"
        admin_password = "${var.admin_password}"
      }
    
      os_profile_linux_config {
        disable_password_authentication = false
      }
    
      # It's easy to transfer files or templates using Terraform.
      provisioner "file" {
        source      = "files/setup.sh"
        destination = "/home/${var.admin_username}/setup.sh"
    
        connection {
          type     = "ssh"
          user     = "${var.admin_username}"
          password = "${var.admin_password}"
          host     = "${azurerm_public_ip.tf-guide-pip.fqdn}"
        }
      }
    
      # This shell script starts our Apache server and prepares the demo environment.
      provisioner "remote-exec" {
        inline = [
          "chmod +x /home/${var.admin_username}/setup.sh",
          "sudo /home/${var.admin_username}/setup.sh",
        ]
    
        connection {
          type     = "ssh"
          user     = "${var.admin_username}"
          password = "${var.admin_password}"
          host     = "${azurerm_public_ip.tf-guide-pip.fqdn}"
        }
      }
    }
    
    ##############################################################################
    # Azure MySQL Database
    
    # Terraform can build any type of infrastructure, not just virtual machines. 
    # Azure offers managed MySQL database servers and a whole host of other 
    # resources. Each resource is documented with all the available settings:
    # https://www.terraform.io/docs/providers/azurerm/r/mysql_server.html
    
    # Uncomment the code below to add a MySQL server to your resource group.
    
    # resource "azurerm_mysql_server" "mysql" {
    #   name                = "${var.mysql_hostname}"
    #   location            = "${azurerm_resource_group.tf_azure_guide.location}"
    #   resource_group_name = "${azurerm_resource_group.tf_azure_guide.name}"
    #   ssl_enforcement     = "Disabled"
    
    #   sku {
    #     name     = "MYSQLB50"
    #     capacity = 50
    #     tier     = "Basic"
    #   }
    
    #   administrator_login          = "mysqladmin"
    #   administrator_login_password = "Everything-is-bananas-010101"
    #   version                      = "5.7"
    #   storage_mb                   = "51200"
    #   ssl_enforcement              = "Disabled"
    # }
    
    # # This is a sample database that we'll populate with the MySQL sample data
    # # set provided here: https://github.com/datacharmer/test_db. With Terraform,
    # # everything is Infrastructure as Code. No more manual steps, aging runbooks,
    # # tribal knowledge or outdated wiki instructions. Terraform is your executable
    # # documentation, and it will build infrastructure correctly every time.
    # resource "azurerm_mysql_database" "employees" {
    #   name                = "employees"
    #   resource_group_name = "${azurerm_resource_group.tf_azure_guide.name}"
    #   server_name         = "${azurerm_mysql_server.mysql.name}"
    #   charset             = "utf8"
    #   collation           = "utf8_unicode_ci"
    # }
    
    # # This firewall rule allows database connections from anywhere and is suited
    # # for demo environments. Don't do this in production. 
    # resource "azurerm_mysql_firewall_rule" "demo" {
    #   name                = "tf-guide-demo"
    #   resource_group_name = "${azurerm_resource_group.tf_azure_guide.name}"
    #   server_name         = "${azurerm_mysql_server.mysql.name}"
    #   start_ip_address    = "0.0.0.0"
    #   end_ip_address      = "0.0.0.0"
    # }

    Now that the demo is complete we can delete all the infrastractures using only one command: terraform destroy. Thanks to the state file .tfstate it takes track of what is built and is stored safely in the cloud and not in your local on-premise storage. tfstate files are considered as snapshot, it keeps track of all the last change, and it is importat to protect that state file so we should make a backup just in case you accidentally delete it. Sometimes secrets and credentials are stored in the state files, we can use Terraform Enterprise UI that can encrypt that file at rest. On the Enterprise version state files are stored remotely and a local file can reference that state file, helping to break things into modules.

    As you can see in just 3 minutes you removed all the resources

    @Azure:~/azure-terraform-beginners$ terraform destroy
    azurerm_resource_group.tf_azure_guide: Refreshing state... (ID: /subscriptions/2ac9601a-099e-4e3e-91a9-...roups/terraform-beginners-cloudnatives)
    azurerm_virtual_network.vnet: Refreshing state... (ID: /subscriptions/2ac9601a-099e-4e3e-91a9-...Microsoft.Network/virtualNetworks/vnet)
    azurerm_public_ip.tf-guide-pip: Refreshing state... (ID: /subscriptions/2ac9601a-099e-4e3e-91a9-...t.Network/publicIPAddresses/tfguide-ip)
    azurerm_network_security_group.tf-guide-sg: Refreshing state... (ID: /subscriptions/2ac9601a-099e-4e3e-91a9-...twork/networkSecurityGroups/tfguide-sg)
    azurerm_subnet.subnet: Refreshing state... (ID: /subscriptions/2ac9601a-099e-4e3e-91a9-...ualNetworks/vnet/subnets/tfguidesubnet)
    azurerm_network_interface.tf-guide-nic: Refreshing state... (ID: /subscriptions/2ac9601a-099e-4e3e-91a9-.../networkInterfaces/tfguidetf-guide-nic)
    azurerm_virtual_machine.site: Refreshing state... (ID: /subscriptions/2ac9601a-099e-4e3e-91a9-...e/virtualMachines/cloudnative2018-site)
    
    An execution plan has been generated and is shown below.
    Resource actions are indicated with the following symbols:
      - destroy
    
    Terraform will perform the following actions:
    
      - azurerm_network_interface.tf-guide-nic
    
      - azurerm_network_security_group.tf-guide-sg
    
      - azurerm_public_ip.tf-guide-pip
    
      - azurerm_resource_group.tf_azure_guide
    
      - azurerm_subnet.subnet
    
      - azurerm_virtual_machine.site
    
      - azurerm_virtual_network.vnet
    
    
    Plan: 0 to add, 0 to change, 7 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_virtual_machine.site: Destroying... (ID: /subscriptions/2ac9601a-099e-4e3e-91a9-...e/virtualMachines/cloudnative2018-site)
    azurerm_virtual_machine.site: Still destroying... (ID: /subscriptions/2ac9601a-099e-4e3e-91a9-...e/virtualMachines/cloudnative2018-site, 10s elapsed)
    azurerm_virtual_machine.site: Still destroying... (ID: /subscriptions/2ac9601a-099e-4e3e-91a9-...e/virtualMachines/cloudnative2018-site, 20s elapsed)
    azurerm_virtual_machine.site: Still destroying... (ID: /subscriptions/2ac9601a-099e-4e3e-91a9-...e/virtualMachines/cloudnative2018-site, 30s elapsed)
    azurerm_virtual_machine.site: Still destroying... (ID: /subscriptions/2ac9601a-099e-4e3e-91a9-...e/virtualMachines/cloudnative2018-site, 40s elapsed)
    azurerm_virtual_machine.site: Still destroying... (ID: /subscriptions/2ac9601a-099e-4e3e-91a9-...e/virtualMachines/cloudnative2018-site, 50s elapsed)
    azurerm_virtual_machine.site: Still destroying... (ID: /subscriptions/2ac9601a-099e-4e3e-91a9-...e/virtualMachines/cloudnative2018-site, 1m0s elapsed)
    azurerm_virtual_machine.site: Still destroying... (ID: /subscriptions/2ac9601a-099e-4e3e-91a9-...e/virtualMachines/cloudnative2018-site, 1m10s elapsed)
    azurerm_virtual_machine.site: Still destroying... (ID: /subscriptions/2ac9601a-099e-4e3e-91a9-...e/virtualMachines/cloudnative2018-site, 1m20s elapsed)
    azurerm_virtual_machine.site: Still destroying... (ID: /subscriptions/2ac9601a-099e-4e3e-91a9-...e/virtualMachines/cloudnative2018-site, 1m30s elapsed)
    azurerm_virtual_machine.site: Still destroying... (ID: /subscriptions/2ac9601a-099e-4e3e-91a9-...e/virtualMachines/cloudnative2018-site, 1m40s elapsed)
    azurerm_virtual_machine.site: Still destroying... (ID: /subscriptions/2ac9601a-099e-4e3e-91a9-...e/virtualMachines/cloudnative2018-site, 1m50s elapsed)
    azurerm_virtual_machine.site: Still destroying... (ID: /subscriptions/2ac9601a-099e-4e3e-91a9-...e/virtualMachines/cloudnative2018-site, 2m0s elapsed)
    azurerm_virtual_machine.site: Still destroying... (ID: /subscriptions/2ac9601a-099e-4e3e-91a9-...e/virtualMachines/cloudnative2018-site, 2m10s elapsed)
    azurerm_virtual_machine.site: Still destroying... (ID: /subscriptions/2ac9601a-099e-4e3e-91a9-...e/virtualMachines/cloudnative2018-site, 2m20s elapsed)
    azurerm_virtual_machine.site: Still destroying... (ID: /subscriptions/2ac9601a-099e-4e3e-91a9-...e/virtualMachines/cloudnative2018-site, 2m30s elapsed)
    azurerm_virtual_machine.site: Still destroying... (ID: /subscriptions/2ac9601a-099e-4e3e-91a9-...e/virtualMachines/cloudnative2018-site, 2m40s elapsed)
    azurerm_virtual_machine.site: Still destroying... (ID: /subscriptions/2ac9601a-099e-4e3e-91a9-...e/virtualMachines/cloudnative2018-site, 2m50s elapsed)
    azurerm_virtual_machine.site: Still destroying... (ID: /subscriptions/2ac9601a-099e-4e3e-91a9-...e/virtualMachines/cloudnative2018-site, 3m0s elapsed)
    azurerm_virtual_machine.site: Still destroying... (ID: /subscriptions/2ac9601a-099e-4e3e-91a9-...e/virtualMachines/cloudnative2018-site, 3m10s elapsed)
    azurerm_virtual_machine.site: Destruction complete after 3m14s
    azurerm_network_interface.tf-guide-nic: Destroying... (ID: /subscriptions/2ac9601a-099e-4e3e-91a9-.../networkInterfaces/tfguidetf-guide-nic)
    azurerm_network_interface.tf-guide-nic: Destruction complete after 1s
    azurerm_network_security_group.tf-guide-sg: Destroying... (ID: /subscriptions/2ac9601a-099e-4e3e-91a9-...twork/networkSecurityGroups/tfguide-sg)
    azurerm_public_ip.tf-guide-pip: Destroying... (ID: /subscriptions/2ac9601a-099e-4e3e-91a9-...t.Network/publicIPAddresses/tfguide-ip)
    azurerm_subnet.subnet: Destroying... (ID: /subscriptions/2ac9601a-099e-4e3e-91a9-...ualNetworks/vnet/subnets/tfguidesubnet)
    azurerm_subnet.subnet: Destruction complete after 1s
    azurerm_virtual_network.vnet: Destroying... (ID: /subscriptions/2ac9601a-099e-4e3e-91a9-...Microsoft.Network/virtualNetworks/vnet)
    azurerm_network_security_group.tf-guide-sg: Still destroying... (ID: /subscriptions/2ac9601a-099e-4e3e-91a9-...twork/networkSecurityGroups/tfguide-sg, 10s elapsed)
    azurerm_public_ip.tf-guide-pip: Still destroying... (ID: /subscriptions/2ac9601a-099e-4e3e-91a9-...t.Network/publicIPAddresses/tfguide-ip, 10s elapsed)
    azurerm_network_security_group.tf-guide-sg: Destruction complete after 11s
    azurerm_virtual_network.vnet: Still destroying... (ID: /subscriptions/2ac9601a-099e-4e3e-91a9-...Microsoft.Network/virtualNetworks/vnet, 10s elapsed)
    azurerm_public_ip.tf-guide-pip: Destruction complete after 12s
    azurerm_virtual_network.vnet: Destruction complete after 11s
    azurerm_resource_group.tf_azure_guide: Destroying... (ID: /subscriptions/2ac9601a-099e-4e3e-91a9-...roups/terraform-beginners-cloudnatives)
    azurerm_resource_group.tf_azure_guide: Still destroying... (ID: /subscriptions/2ac9601a-099e-4e3e-91a9-...roups/terraform-beginners-cloudnatives, 10s elapsed)
    azurerm_resource_group.tf_azure_guide: Still destroying... (ID: /subscriptions/2ac9601a-099e-4e3e-91a9-...roups/terraform-beginners-cloudnatives, 20s elapsed)
    azurerm_resource_group.tf_azure_guide: Still destroying... (ID: /subscriptions/2ac9601a-099e-4e3e-91a9-...roups/terraform-beginners-cloudnatives, 30s elapsed)
    azurerm_resource_group.tf_azure_guide: Still destroying... (ID: /subscriptions/2ac9601a-099e-4e3e-91a9-...roups/terraform-beginners-cloudnatives, 40s elapsed)
    azurerm_resource_group.tf_azure_guide: Destruction complete after 49s
    
    Destroy complete! Resources: 7 destroyed.

    Another interesting thing of Terraform is that it can be used in conjuction with ARM Templates and that we can have different providers like AWS, Azure, and GCP in a single Terraform file.

    As you can listen from Sean Carolan video it is not that easy to move an application from a cloud vendor to another, but this task can be simplified thanks to Terraform separating things that are common or shared on whatever cloud you run your app on, they could be your setup scripts or chef cookbook or an ansible playbook or puppet module, put it in shared folder and you are going to have other folders for each cloud so each directory  have inside different terraform code for each platform and they vary slightly because each cloud provider is different, they provide different API, different settings and different way to authenticate, so it gives you an easy way to write code that will work on each cloud provider but without having to rewrite all the stuff that is comon aross all three or more, storing all your code in your source repo and be able to easily provision you app on multiple clouds vendor.

    There is also a Terraform Enterprise version that is suggested to be used by team, it supports SAML, Active Directory integration so you can log in with your credential, it has the feature to add workspaces automatically for you. It has ACL to grant to some users access only to the terraform code they need. Collaboration is enhanced so that if you commit your code to your git rep someone can do code review. Multiple users can collaborate on code without stepping on each other’s toes working on the different part of the infrastructure on Terraform.

    Visual Studio Code supports Terraform highlighting thanks to its extensions.

    That’s all , here some great resources for learning Terraform:

    https://github.com/contino/terraform-learn
    https://github.com/hashicorp/best-practices/tree/master/terraform

    https://blog.gruntwork.io/a-comprehensive-guide-to-terraform-b3d32832baca#.ijq70izhc

    https://blog.gruntwork.io/terraform-tips-tricks-loops-if-statements-and-gotchas-f739bbae55f9
    https://www.gruntwork.io/infrastructure-as-code-library/
    https://github.com/wardviaene/terraform-course

    Leave a Reply

    Your email address will not be published. Required fields are marked *

    This site uses Akismet to reduce spam. Learn how your comment data is processed.