This post guides you though the creation of a Ubuntu Virtual Machine within Auzre, using Terraform. It assume you have setup a Azure account created. You can sign up for a free trail if you do not.
Install terraform, and the Azure ‘az cli’ tool. The command below assumes a .deb based Linux distro.
$ wget "https://releases.hashicorp.com/terraform/0.12.29/terraform_0.12.29_linux_amd64.zip" $ unzip terraform_0.12.29_linux_amd64.zip $ curl -sL https://aka.ms/InstallAzureCLIDeb | sudo bash
Running ‘az login’ will launch web browser, and log you into Azure. The ‘az account show’ will give you the details of your session.
$ az login $ az account show { "environmentName": "AzureCloud", "homeTenantId": "removed", "id": "removed", "isDefault": true, "managedByTenants": [], "name": "Free Trial", "state": "Enabled", "tenantId": "removed", "user": { "name": "[email protected]", "type": "user" } }
This basic .tf file below will serve as a test to ensure that your terraform is working. It will create a single resource group, which serves as a management container for collections of resources.
provider "azurerm" { # The "feature" block is required for AzureRM provider 2.x. # If you are using version 1.x, the "features" block is not allowed. version = "~>2.0" features {} } resource "azurerm_resource_group" "example" { name = "example" location = "West Europe" }
Having created the .tf file above, now run an apply (you should of course always run a plan before to sanity check what will be created)
$ ./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_resource_group.example will be created + resource "azurerm_resource_group" "example" { + id = (known after apply) + location = "westeurope" + name = "example" } Plan: 1 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.example: Creating... azurerm_resource_group.example: Creation complete after 0s [id=/subscriptions/199284ea-bc26-4f86-adc0-30e420d6b709/resourceGroups/example] Apply complete! Resources: 1 added, 0 changed, 0 destroyed.
A full example
The terraform below creates all of the resources required to spin up a Ubuntu 18.04 LTS Linux server. You’ll need to modify the below with your own username and password. The output of the TF will show you the IP address. You might need to run ‘terraform refresh && terraform output
‘ after your apply as for me the IP address didn’t show the first time.
provider "azurerm" { # The "feature" block is required for AzureRM provider 2.x. # If you are using version 1.x, the "features" block is not allowed. version = "~>2.0" features {} } resource "azurerm_resource_group" "west_rg1" { name = "West_Europe_RG1" location = "West Europe" } resource "azurerm_virtual_network" "network1" { name = "vn1" address_space = ["10.0.0.0/16"] location = azurerm_resource_group.west_rg1.location resource_group_name = azurerm_resource_group.west_rg1.name tags = { environment = "Terraform Demo" } } resource "azurerm_subnet" "internal" { name = "internal" resource_group_name = azurerm_resource_group.west_rg1.name virtual_network_name = azurerm_virtual_network.network1.name address_prefixes = ["10.0.1.0/24"] } resource "azurerm_network_security_group" "ssh" { name = "SSH Inbound" location = azurerm_resource_group.west_rg1.location resource_group_name = azurerm_resource_group.west_rg1.name security_rule { name = "test123" priority = 100 direction = "Inbound" access = "Allow" protocol = "Tcp" source_port_range = "*" destination_port_range = "22" source_address_prefix = "*" destination_address_prefix = "*" } } resource "azurerm_network_interface" "main" { name = "test-nic" location = azurerm_resource_group.west_rg1.location resource_group_name = azurerm_resource_group.west_rg1.name ip_configuration { name = "testconfiguration1" subnet_id = azurerm_subnet.internal.id private_ip_address_allocation = "Dynamic" public_ip_address_id = azurerm_public_ip.example.id } } resource "azurerm_network_interface_security_group_association" "example" { network_interface_id = azurerm_network_interface.main.id network_security_group_id = azurerm_network_security_group.ssh.id } resource "azurerm_public_ip" "example" { name = "acceptanceTestPublicIp1" resource_group_name = azurerm_resource_group.west_rg1.name location = azurerm_resource_group.west_rg1.location allocation_method = "Dynamic" } resource "azurerm_virtual_machine" "main" { name = "test-vm" location = azurerm_resource_group.west_rg1.location resource_group_name = azurerm_resource_group.west_rg1.name network_interface_ids = [azurerm_network_interface.main.id] vm_size = "Standard_DS1_v2" delete_os_disk_on_termination = true delete_data_disks_on_termination = true storage_image_reference { publisher = "Canonical" offer = "UbuntuServer" sku = "18.04-LTS" version = "latest" } storage_os_disk { name = "myosdisk1" caching = "ReadWrite" create_option = "FromImage" managed_disk_type = "Standard_LRS" } os_profile { computer_name = "testvm" admin_username = "pookey" admin_password = "Password12*" } os_profile_linux_config { disable_password_authentication = false } } output "instance_ip_addr" { value = azurerm_public_ip.example.ip_address }
Known Issues
When trying to destroy the resources, a few issues cropped up. To resolve the issue, simply wait a few minutes and re-run.
Error: Error deleting Network Security Group "acceptanceTestSecurityGroup1" (Resource Group "West_Europe_RG1"): Code="Canceled" Message="Operation was canceled." Details=[{"code":"CanceledAndSupersededDueToAnotherOperation","message":"Operation DeleteNetworkSecurityGroupOperation (d8d816f9-7a51-4a6e-a7e6-1dd43de5e34c) was canceled and superseded by operation DeleteNetworkSecurityGroupOperation (7a7ff9fa-580b-43ce-bab6-14b941f897b9)."}] Error: Error deleting Network Security Group "acceptanceTestSecurityGroup1" (Resource Group "West_Europe_RG1"): network.SecurityGroupsClient#Delete: Failure sending request: StatusCode=400 -- Original Error: Code="NetworkSecurityGroupOldReferencesNotCleanedUp" Message="Network security group acceptanceTestSecurityGroup1 cannot be deleted because old references for the following Nics: (\n/subscriptions/199284ea-bc26-4f86-adc0-30e420d6b709/resourceGroups/West_Europe_RG1/providers/Microsoft.Network/networkSecurityGroups/acceptanceTestSecurityGroup1:/subscriptions/199284ea-bc26-4f86-adc0-30e420d6b709/resourceGroups/West_Europe_RG1/providers/Microsoft.Network/networkInterfaces/test-nic) and Subnet: (\n/subscriptions/199284ea-bc26-4f86-adc0-30e420d6b709/resourceGroups/West_Europe_RG1/providers/Microsoft.Network/networkSecurityGroups/acceptanceTestSecurityGroup1:) have not been released yet." Details=[] Error: Error deleting Network Security Group "acceptanceTestSecurityGroup1" (Resource Group "West_Europe_RG1"): network.SecurityGroupsClient#Delete: Failure sending request: StatusCode=400 -- Original Error: Code="NetworkSecurityGroupOldReferencesNotCleanedUp" Message="Network security group acceptanceTestSecurityGroup1 cannot be deleted because old references for the following Nics: (\n/subscriptions/199284ea-bc26-4f86-adc0-30e420d6b709/resourceGroups/West_Europe_RG1/providers/Microsoft.Network/networkSecurityGroups/acceptanceTestSecurityGroup1:/subscriptions/199284ea-bc26-4f86-adc0-30e420d6b709/resourceGroups/West_Europe_RG1/providers/Microsoft.Network/networkInterfaces/test-nic) and Subnet: (\n/subscriptions/199284ea-bc26-4f86-adc0-30e420d6b709/resourceGroups/West_Europe_RG1/providers/Microsoft.Network/networkSecurityGroups/acceptanceTestSecurityGroup1:) have not been released yet." Details=[]