To round off things nicely, I thought I would follow on from two previous posts about creating Azure Virtual Machines. First we went through how to create an Azure Virtual Machine using PowerShell, then we went through with ARM templates. Now we’re going to use Terraform for the third try.
Create an Azure Virtual Machine with PowerShell
Create an Azure Virtual Machine with an ARM template
Setting the scene
Let’s assume that we have nothing setup. No virtual network, no storage, nothing. So we will be using Terraform to define everything.
The plan
- Create our terraform file
- Create the AzureRM provider in terraform
- Define the Azure resource group
- Define a virtual network and subnet
- Define a new public IP address
- Define a Network Interface for our VM
- Define the Virtual Machine
- Build the Virtual Machine
- The whole file in one
- Conclusion
1. Create the terraform file
Let’s create our terraform file and name it main.tf
touch main.tf
2. Create the AzureRM provider in terraform
Open up main.tf in your editor of choice and add the azure provider to the top of the file
provider "azurerm" {
version = "= 2.0.0"
features {}
}
3. Define the Azure resource group
Now let’s create our new resource group that everything will live inside
resource "azurerm_resource_group" "rg" {
name = "my-first-terraform-rg"
location = "northeurope"
}
4. Define a virtual network and subnet
resource "azurerm_virtual_network" "myvnet" {
name = "my-vnet"
address_space = ["10.0.0.0/16"]
location = "northeurope"
resource_group_name = azurerm_resource_group.rg.name
}
resource "azurerm_subnet" "frontendsubnet" {
name = "frontendSubnet"
resource_group_name = azurerm_resource_group.rg.name
virtual_network_name = azurerm_virtual_network.myvnet.name
address_prefix = "10.0.1.0/24"
}
5. Define a new public IP address
resource "azurerm_public_ip" "myvm1publicip" {
name = "pip1"
location = "northeurope"
resource_group_name = azurerm_resource_group.rg.name
allocation_method = "Dynamic"
sku = "Basic"
}
6. Define a Network Interface for our VM
resource "azurerm_network_interface" "myvm1nic" {
name = "myvm1-nic"
location = "northeurope"
resource_group_name = azurerm_resource_group.rg.name
ip_configuration {
name = "ipconfig1"
subnet_id = azurerm_subnet.frontendsubnet.id
private_ip_address_allocation = "Dynamic"
public_ip_address_id = azurerm_public_ip.myvm1publicip.id
}
}
7. Define the Virtual Machine
resource "azurerm_windows_virtual_machine" "example" {
name = "myvm1"
location = "northeurope"
resource_group_name = azurerm_resource_group.rg.name
network_interface_ids = [azurerm_network_interface.myvm1nic.id]
size = "Standard_B1s"
admin_username = "adminuser"
admin_password = "Password123!"
source_image_reference {
publisher = "MicrosoftWindowsServer"
offer = "WindowsServer"
sku = "2019-Datacenter"
version = "latest"
}
os_disk {
caching = "ReadWrite"
storage_account_type = "Standard_LRS"
}
}
8. Build the Virtual Machine
Login to Azure with the CLI
There are several ways to authenticate with Azure to run our terraform file, for this example I’m going to suggest the Azure CLI
Make sure you have the Azure CLI installed, then run:
az login
Which should bring up a browser window for you to login to your Azure subscription.
Run terraform init
Now we need to run terrafrom init to prepare the directory and pull down the resources that we have defined in our file.
terraform init
Build our terraform file
terraform apply
Time taken: 3m10s
- The whole file in one
provider "azurerm" {
version = "= 2.0.0"
features {}
}
resource "azurerm_resource_group" "rg" {
name = "my-first-terraform-rg"
location = "northeurope"
}
resource "azurerm_virtual_network" "myvnet" {
name = "my-vnet"
address_space = ["10.0.0.0/16"]
location = "northeurope"
resource_group_name = azurerm_resource_group.rg.name
}
resource "azurerm_subnet" "frontendsubnet" {
name = "frontendSubnet"
resource_group_name = azurerm_resource_group.rg.name
virtual_network_name = azurerm_virtual_network.myvnet.name
address_prefix = "10.0.1.0/24"
}
resource "azurerm_public_ip" "myvm1publicip" {
name = "pip1"
location = "northeurope"
resource_group_name = azurerm_resource_group.rg.name
allocation_method = "Dynamic"
sku = "Basic"
}
resource "azurerm_network_interface" "myvm1nic" {
name = "myvm1-nic"
location = "northeurope"
resource_group_name = azurerm_resource_group.rg.name
ip_configuration {
name = "ipconfig1"
subnet_id = azurerm_subnet.frontendsubnet.id
private_ip_address_allocation = "Dynamic"
public_ip_address_id = azurerm_public_ip.myvm1publicip.id
}
}
resource "azurerm_windows_virtual_machine" "example" {
name = "myvm1"
location = "northeurope"
resource_group_name = azurerm_resource_group.rg.name
network_interface_ids = [azurerm_network_interface.myvm1nic.id]
size = "Standard_B1s"
admin_username = "adminuser"
admin_password = "Password123!"
source_image_reference {
publisher = "MicrosoftWindowsServer"
offer = "WindowsServer"
sku = "2019-Datacenter"
version = "latest"
}
os_disk {
caching = "ReadWrite"
storage_account_type = "Standard_LRS"
}
}
10. Conclusion
So there we have it, a new Virtual Machine built in Azure using terraform. I personally really like the formatting and syntax compared to ARM templates. Of course I think terraform plan is where the magic is, which ARM template CURRENTLY has no answer for. I’m sure it will come soon enough to ARM, but in the mean time. Terraform really is a great solution for IaC (Infrastructure as Code).