Getting started with Terraform on Windows and Azure

Quick guide to deploy “hello world” with Terraform on AzureRM

Advertisements

small-a17be924When reviewing possible for creating declarative infrastructure, I looked at Terraform. In this blog post I show how easy it is to get started and create AzureRM resources with Terraform.

Installing Terraform

To get started with Terraform on windows:

  1. Download terraform for windows
  2. Copy files from the zip to c:\terraform
  3. Add the terraform binaries in your path by running:
set PATH=%PATH%;C:\terraform

To connect to AzureRM API for deployment you need a Service Principle. The Terraform azurerm provider looks like:

provider "azurerm" {
  subscription_id = "..."
  client_id       = "..."
  client_secret   = "..."
  tenant_id       = "..."
}

Follow the guide for creating a Service Principle for AzureRM deployment.

Now you are ready to start using Terraform with AzureRM.

Build your first infrastructure

Make an empty directory from your project: c:\t\TerraformT. Then create a file with your Terraform helloworld.tf template to create your first resourcegroup:

provider "azurerm" {
subscription_id = "..."
client_id       = "..."
client_secret   = "..."
tenant_id       = "..."
}

variable "location" { default = "West Europe" }

resource "azurerm_resource_group" "test" {
name     = "HelloWorld"
location = "${var.location}"
}

Next create an initial terraform plan, run: terraform plan

Refreshing Terraform state prior to plan...

The Terraform execution plan has been generated and is shown below.
Resources are shown in alphabetical order for quick scanning. Green resources
will be created (or destroyed and then created if an existing resource
exists), yellow resources are being changed in-place, and red resources
will be destroyed.

Note: You didn't specify an "-out" parameter to save this plan, so when
"apply" is called, Terraform can't guarantee this is what will execute.

+ azurerm_resource_group.test
location: "" => "westeurope"
name:     "" => "HelloWorld"

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

Next you can apply the plan to Azure, run: terraform apply

azurerm_resource_group.test: Creating...
  location: "" => "westeurope"
  name:     "" => "HelloWorld"
azurerm_resource_group.test: Creation complete

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

The state of your infrastructure has been saved to the path
below. This state is required to modify and destroy your
infrastructure, so keep it safe. To inspect the complete state
use the `terraform show` command.

State path: terraform.tfstate

Now we have created our first azurerm_resource_group. Next we can expand the resource group with more azure infrastructure. Lets add a VM with Windows Datacenter to the deployment:

# Configure the Azure Resource Manager Provider
provider "azurerm" {
  subscription_id = "..."
  client_id       = "..."
  client_secret   = "..."
  tenant_id       = "..."
}

variable "location" { default = "West Europe" }
variable "username" { default = "adminuser" }
variable "password" { default = "Pass654321" }

resource "azurerm_resource_group" "test" {
  name     = "HelloWorld"
  location = "${var.location}"
}

resource "azurerm_virtual_network" "test" {
  name                = "test"
  address_space       = ["10.0.0.0/16"]
  location            = "${var.location}"
  resource_group_name = "${azurerm_resource_group.test.name}"
}

resource "azurerm_subnet" "test" {
  name                 = "test"
  resource_group_name  = "${azurerm_resource_group.test.name}"
  virtual_network_name = "${azurerm_virtual_network.test.name}"
  address_prefix       = "10.0.2.0/24"
}

resource "azurerm_network_interface" "test" {
  name                = "test"
  location            = "${var.location}"
  resource_group_name = "${azurerm_resource_group.test.name}"
  ip_configuration {
    name                          = "testconfiguration1"
    subnet_id                     = "${azurerm_subnet.test.id}"
    private_ip_address_allocation = "dynamic"
  }
}

resource "azurerm_storage_account" "test" {
  name                = "helloworld25662"
  resource_group_name = "${azurerm_resource_group.test.name}"
  location            = "${var.location}"
  account_type        = "Standard_LRS"
}

resource "azurerm_storage_container" "test" {
  name                  = "helloworld"
  resource_group_name   = "${azurerm_resource_group.test.name}"
  storage_account_name  = "${azurerm_storage_account.test.name}"
  container_access_type = "private"
}

resource "azurerm_virtual_machine" "test" {
  name                  = "helloworld"
  location              = "${var.location}"
  resource_group_name   = "${azurerm_resource_group.test.name}"
  network_interface_ids = ["${azurerm_network_interface.test.id}"]
  vm_size               = "Standard_A0"

  storage_image_reference {
    publisher = "MicrosoftWindowsServer"
    offer     = "WindowsServer"
    sku       = "2012-R2-Datacenter"
    version   = "latest"
  }

  storage_os_disk {
    name          = "myosdisk1"
    vhd_uri       = "${azurerm_storage_account.test.primary_blob_endpoint}${azurerm_storage_container.test.name}/myosdisk1.vhd"
    caching       = "ReadWrite"
    create_option = "FromImage"
  }

  os_profile {
    computer_name  = "helloworld"
    admin_username = "${var.username}"
    admin_password = "${var.password}"
  }
}

Run: terraform plan

Refreshing Terraform state prior to plan...

azurerm_resource_group.test: Refreshing state... (ID: /subscriptions/9bdde4e2-946e-4961-b111-fadcea94577d/resourceGroups/HelloWorld)

The Terraform execution plan has been generated and is shown below.
Resources are shown in alphabetical order for quick scanning. Green resources
will be created (or destroyed and then created if an existing resource
exists), yellow resources are being changed in-place, and red resources
will be destroyed.

Note: You didn't specify an "-out" parameter to save this plan, so when
"apply" is called, Terraform can't guarantee this is what will execute.

+ azurerm_network_interface.test
    applied_dns_servers.#:                                                  "" => "<computed>"
    dns_servers.#:                                                          "" => "<computed>"
    internal_dns_name_label:                                                "" => "<computed>"
    internal_fqdn:                                                          "" => "<computed>"
    ip_configuration.#:                                                     "" => "1"
    ip_configuration.~1070970412.load_balancer_backend_address_pools_ids.#: "" => "<computed>"
    ip_configuration.~1070970412.load_balancer_inbound_nat_rules_ids.#:     "" => "<computed>"
    ip_configuration.~1070970412.name:                                      "" => "testconfiguration1"
    ip_configuration.~1070970412.private_ip_address:                        "" => "<computed>"
    ip_configuration.~1070970412.private_ip_address_allocation:             "" => "dynamic"
    ip_configuration.~1070970412.subnet_id:                                 "" => "${azurerm_subnet.test.id}"
    location:                                                               "" => "westeurope"
    mac_address:                                                            "" => "<computed>"
    name:                                                                   "" => "test"
    network_security_group_id:                                              "" => "<computed>"
    private_ip_address:                                                     "" => "<computed>"
    resource_group_name:                                                    "" => "HelloWorld"
    virtual_machine_id:                                                     "" => "<computed>"

+ azurerm_storage_account.test
    account_type:             "" => "Standard_LRS"
    location:                 "" => "westeurope"
    name:                     "" => "helloworld25662"
    primary_blob_endpoint:    "" => "<computed>"
    primary_file_endpoint:    "" => "<computed>"
    primary_location:         "" => "<computed>"
    primary_queue_endpoint:   "" => "<computed>"
    primary_table_endpoint:   "" => "<computed>"
    resource_group_name:      "" => "HelloWorld"
    secondary_blob_endpoint:  "" => "<computed>"
    secondary_location:       "" => "<computed>"
    secondary_queue_endpoint: "" => "<computed>"
    secondary_table_endpoint: "" => "<computed>"

+ azurerm_storage_container.test
    container_access_type: "" => "private"
    name:                  "" => "helloworld"
    properties.#:          "" => "<computed>"
    resource_group_name:   "" => "HelloWorld"
    storage_account_name:  "" => "helloworld25662"

+ azurerm_subnet.test
    address_prefix:            "" => "10.0.2.0/24"
    ip_configurations.#:       "" => "<computed>"
    name:                      "" => "test"
    network_security_group_id: "" => "<computed>"
    resource_group_name:       "" => "HelloWorld"
    route_table_id:            "" => "<computed>"
    virtual_network_name:      "" => "test"

+ azurerm_virtual_machine.test
    availability_set_id:                         "" => "<computed>"
    license_type:                                "" => "<computed>"
    location:                                    "" => "westeurope"
    name:                                        "" => "helloworld"
    network_interface_ids.#:                     "" => "<computed>"
    os_profile.#:                                "" => "1"
    os_profile.522345080.admin_password:         "" => "Pass654321"
    os_profile.522345080.admin_username:         "" => "adminuser"
    os_profile.522345080.computer_name:          "" => "helloworld"
    os_profile.522345080.custom_data:            "" => "<computed>"
    plan.#:                                      "" => "<computed>"
    resource_group_name:                         "" => "HelloWorld"
    storage_image_reference.#:                   "" => "1"
    storage_image_reference.103127886.offer:     "" => "WindowsServer"
    storage_image_reference.103127886.publisher: "" => "MicrosoftWindowsServer"
    storage_image_reference.103127886.sku:       "" => "2012-R2-Datacenter"
    storage_image_reference.103127886.version:   "" => "latest"
    storage_os_disk.#:                           "" => "1"
    storage_os_disk.~808156298.caching:          "" => "ReadWrite"
    storage_os_disk.~808156298.create_option:    "" => "FromImage"
    storage_os_disk.~808156298.image_uri:        "" => ""
    storage_os_disk.~808156298.name:             "" => "myosdisk1"
    storage_os_disk.~808156298.os_type:          "" => ""
    storage_os_disk.~808156298.vhd_uri:          "" => "${azurerm_storage_account.test.primary_blob_endpoint}${azurerm_storage_container.test.name}/myosdisk1.vhd"
    vm_size:                                     "" => "Standard_A0"

+ azurerm_virtual_network.test
    address_space.#:     "" => "1"
    address_space.0:     "" => "10.0.0.0/16"
    location:            "" => "westeurope"
    name:                "" => "test"
    resource_group_name: "" => "HelloWorld"
    subnet.#:            "" => "<computed>"

Plan: 6 to add, 0 to change, 0 to destroy.
And then run: terraform apply
azurerm_resource_group.test: Refreshing state... (ID: /subscriptions/9bdde4e2-946e-4961-b111-fadcea94577d/resourceGroups/HelloWorld)
azurerm_storage_account.test: Creating...
  account_type:             "" => "Standard_LRS"
  location:                 "" => "westeurope"
  name:                     "" => "helloworld25662"
  primary_blob_endpoint:    "" => "<computed>"
  primary_file_endpoint:    "" => "<computed>"
  primary_location:         "" => "<computed>"
  primary_queue_endpoint:   "" => "<computed>"
  primary_table_endpoint:   "" => "<computed>"
  resource_group_name:      "" => "HelloWorld"
  secondary_blob_endpoint:  "" => "<computed>"
  secondary_location:       "" => "<computed>"
  secondary_queue_endpoint: "" => "<computed>"
  secondary_table_endpoint: "" => "<computed>"
azurerm_virtual_network.test: Creating...
  address_space.#:     "" => "1"
  address_space.0:     "" => "10.0.0.0/16"
  location:            "" => "westeurope"
  name:                "" => "test"
  resource_group_name: "" => "HelloWorld"
  subnet.#:            "" => "<computed>"
azurerm_virtual_network.test: Creation complete
azurerm_subnet.test: Creating...
  address_prefix:            "" => "10.0.2.0/24"
  ip_configurations.#:       "" => "<computed>"
  name:                      "" => "test"
  network_security_group_id: "" => "<computed>"
  resource_group_name:       "" => "HelloWorld"
  route_table_id:            "" => "<computed>"
  virtual_network_name:      "" => "test"
azurerm_subnet.test: Creation complete
azurerm_network_interface.test: Creating...
  applied_dns_servers.#:                                                 "" => "<computed>"
  dns_servers.#:                                                         "" => "<computed>"
  internal_dns_name_label:                                               "" => "<computed>"
  internal_fqdn:                                                         "" => "<computed>"
  ip_configuration.#:                                                    "" => "1"
  ip_configuration.1430870016.load_balancer_backend_address_pools_ids.#: "" => "<computed>"
  ip_configuration.1430870016.load_balancer_inbound_nat_rules_ids.#:     "" => "<computed>"
  ip_configuration.1430870016.name:                                      "" => "testconfiguration1"
  ip_configuration.1430870016.private_ip_address:                        "" => "<computed>"
  ip_configuration.1430870016.private_ip_address_allocation:             "" => "dynamic"
  ip_configuration.1430870016.subnet_id:                                 "" => "/subscriptions/9bdde4e2-946e-4961-b111-fadcea94577d/resourceGroups/HelloWorld/providers/Microsoft.Network/virtualNetworks/test/subnets/test"
  location:                                                              "" => "westeurope"
  mac_address:                                                           "" => "<computed>"
  name:                                                                  "" => "test"
  network_security_group_id:                                             "" => "<computed>"
  private_ip_address:                                                    "" => "<computed>"
  resource_group_name:                                                   "" => "HelloWorld"
  virtual_machine_id:                                                    "" => "<computed>"
azurerm_network_interface.test: Creation complete
azurerm_storage_account.test: Still creating... (10s elapsed)
azurerm_storage_account.test: Still creating... (20s elapsed)
azurerm_storage_account.test: Creation complete
azurerm_storage_container.test: Creating...
  container_access_type: "" => "private"
  name:                  "" => "helloworld"
  properties.#:          "" => "<computed>"
  resource_group_name:   "" => "HelloWorld"
  storage_account_name:  "" => "helloworld25662"
azurerm_storage_container.test: Creation complete
azurerm_virtual_machine.test: Creating...
  availability_set_id:                         "" => "<computed>"
  license_type:                                "" => "<computed>"
  location:                                    "" => "westeurope"
  name:                                        "" => "helloworld"
  network_interface_ids.#:                     "" => "1"
  network_interface_ids.214586890:             "" => "/subscriptions/9bdde4e2-946e-4961-b111-fadcea94577d/resourceGroups/HelloWorld/providers/Microsoft.Network/networkInterfaces/test"
  os_profile.#:                                "" => "1"
  os_profile.522345080.admin_password:         "" => "Pass654321"
  os_profile.522345080.admin_username:         "" => "adminuser"
  os_profile.522345080.computer_name:          "" => "helloworld"
  os_profile.522345080.custom_data:            "" => "<computed>"
  plan.#:                                      "" => "<computed>"
  resource_group_name:                         "" => "HelloWorld"
  storage_image_reference.#:                   "" => "1"
  storage_image_reference.103127886.offer:     "" => "WindowsServer"
  storage_image_reference.103127886.publisher: "" => "MicrosoftWindowsServer"
  storage_image_reference.103127886.sku:       "" => "2012-R2-Datacenter"
  storage_image_reference.103127886.version:   "" => "latest"
  storage_os_disk.#:                           "" => "1"
  storage_os_disk.1235954129.caching:          "" => "ReadWrite"
  storage_os_disk.1235954129.create_option:    "" => "FromImage"
  storage_os_disk.1235954129.image_uri:        "" => ""
  storage_os_disk.1235954129.name:             "" => "myosdisk1"
  storage_os_disk.1235954129.os_type:          "" => ""
  storage_os_disk.1235954129.vhd_uri:          "" => "https://helloworld25662.blob.core.windows.net/helloworld/myosdisk1.vhd"
  vm_size:                                     "" => "Standard_A0"
azurerm_virtual_machine.test: Still creating... (10s elapsed)
azurerm_virtual_machine.test: Still creating... (20s elapsed)
azurerm_virtual_machine.test: Still creating... (30s elapsed)
azurerm_virtual_machine.test: Still creating... (40s elapsed)
azurerm_virtual_machine.test: Still creating... (50s elapsed)
azurerm_virtual_machine.test: Still creating... (1m0s elapsed)
azurerm_virtual_machine.test: Still creating... (1m10s elapsed)
azurerm_virtual_machine.test: Still creating... (1m20s elapsed)
azurerm_virtual_machine.test: Still creating... (1m30s elapsed)
azurerm_virtual_machine.test: Still creating... (1m40s elapsed)
azurerm_virtual_machine.test: Still creating... (1m50s elapsed)
azurerm_virtual_machine.test: Still creating... (2m0s elapsed)
azurerm_virtual_machine.test: Still creating... (2m10s elapsed)
azurerm_virtual_machine.test: Still creating... (2m20s elapsed)
azurerm_virtual_machine.test: Still creating... (2m30s elapsed)
azurerm_virtual_machine.test: Still creating... (2m40s elapsed)
azurerm_virtual_machine.test: Still creating... (2m50s elapsed)
azurerm_virtual_machine.test: Still creating... (3m0s elapsed)
azurerm_virtual_machine.test: Still creating... (3m10s elapsed)
azurerm_virtual_machine.test: Still creating... (3m20s elapsed)
azurerm_virtual_machine.test: Still creating... (3m30s elapsed)
azurerm_virtual_machine.test: Still creating... (3m40s elapsed)
azurerm_virtual_machine.test: Still creating... (3m50s elapsed)
azurerm_virtual_machine.test: Still creating... (4m0s elapsed)
azurerm_virtual_machine.test: Still creating... (4m10s elapsed)
azurerm_virtual_machine.test: Still creating... (4m20s elapsed)
azurerm_virtual_machine.test: Still creating... (4m30s elapsed)
azurerm_virtual_machine.test: Still creating... (4m40s elapsed)
azurerm_virtual_machine.test: Still creating... (4m50s elapsed)
azurerm_virtual_machine.test: Still creating... (5m0s elapsed)
azurerm_virtual_machine.test: Still creating... (5m10s elapsed)
azurerm_virtual_machine.test: Still creating... (5m20s elapsed)
azurerm_virtual_machine.test: Still creating... (5m30s elapsed)
azurerm_virtual_machine.test: Still creating... (5m40s elapsed)
azurerm_virtual_machine.test: Still creating... (5m50s elapsed)
azurerm_virtual_machine.test: Still creating... (6m0s elapsed)
azurerm_virtual_machine.test: Still creating... (6m10s elapsed)
azurerm_virtual_machine.test: Still creating... (6m20s elapsed)
azurerm_virtual_machine.test: Still creating... (6m30s elapsed)
azurerm_virtual_machine.test: Still creating... (6m40s elapsed)
azurerm_virtual_machine.test: Creation complete

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

The state of your infrastructure has been saved to the path
below. This state is required to modify and destroy your
infrastructure, so keep it safe. To inspect the complete state
use the `terraform show` command.

State path: terraform.tfstate

The last step is to complete the application life cycle by removing your resources, do: terraform destroy

Do you really want to destroy?
  Terraform will delete all your managed infrastructure.
  There is no undo. Only 'yes' will be accepted to confirm.

  Enter a value: yes

azurerm_resource_group.test: Refreshing state... (ID: /subscriptions/9bdde4e2-946e-4961-b111-fadcea94577d/resourceGroups/HelloWorld)
azurerm_virtual_network.test: Refreshing state... (ID: /subscriptions/9bdde4e2-946e-4961-b111-fadcea94577d/resourceGroups/HelloWorld/providers/Microsoft.Network/virtualNetworks/test)
azurerm_storage_account.test: Refreshing state... (ID: /subscriptions/9bdde4e2-946e-4961-b111-fadcea94577d/resourceGroups/helloworld/providers/Microsoft.Storage/storageAccounts/helloworld25662)
azurerm_storage_container.test: Refreshing state... (ID: helloworld)
azurerm_subnet.test: Refreshing state... (ID: /subscriptions/9bdde4e2-946e-4961-b111-fadcea94577d/resourceGroups/HelloWorld/providers/Microsoft.Network/virtualNetworks/test/subnets/test)
azurerm_network_interface.test: Refreshing state... (ID: /subscriptions/9bdde4e2-946e-4961-b111-fadcea94577d/resourceGroups/HelloWorld/providers/Microsoft.Network/networkInterfaces/test)
azurerm_virtual_machine.test: Refreshing state... (ID: /subscriptions/9bdde4e2-946e-4961-b111-fadcea94577d/resourceGroups/HelloWorld/providers/Microsoft.Compute/virtualMachines/helloworld)
azurerm_virtual_machine.test: Destroying...
azurerm_virtual_machine.test: Still destroying... (10s elapsed)
azurerm_virtual_machine.test: Still destroying... (20s elapsed)
azurerm_virtual_machine.test: Still destroying... (30s elapsed)
azurerm_virtual_machine.test: Still destroying... (40s elapsed)
azurerm_virtual_machine.test: Still destroying... (50s elapsed)
azurerm_virtual_machine.test: Still destroying... (1m0s elapsed)
azurerm_virtual_machine.test: Still destroying... (1m10s elapsed)
azurerm_virtual_machine.test: Still destroying... (1m20s elapsed)
azurerm_virtual_machine.test: Still destroying... (1m30s elapsed)
azurerm_virtual_machine.test: Still destroying... (1m40s elapsed)
azurerm_virtual_machine.test: Still destroying... (1m50s elapsed)
azurerm_virtual_machine.test: Still destroying... (2m0s elapsed)
azurerm_virtual_machine.test: Destruction complete
azurerm_network_interface.test: Destroying...
azurerm_storage_container.test: Destroying...
azurerm_network_interface.test: Destruction complete
azurerm_subnet.test: Destroying...
azurerm_storage_container.test: Destruction complete
azurerm_storage_account.test: Destroying...
azurerm_storage_account.test: Destruction complete
azurerm_subnet.test: Still destroying... (10s elapsed)
azurerm_subnet.test: Destruction complete
azurerm_virtual_network.test: Destroying...
azurerm_virtual_network.test: Still destroying... (10s elapsed)
azurerm_virtual_network.test: Destruction complete
azurerm_resource_group.test: Destroying...
azurerm_resource_group.test: Still destroying... (10s elapsed)
azurerm_resource_group.test: Still destroying... (20s elapsed)
azurerm_resource_group.test: Still destroying... (30s elapsed)
azurerm_resource_group.test: Still destroying... (40s elapsed)
azurerm_resource_group.test: Destruction complete

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

Now you have seen creating a Terraform template, and updating the template with Terraform on AzureRM. More information on what resources are available from the azurerm provider, check the Terraform documentation.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s