Infrastructure as Code has become the order of the day. In this article, “Configure a Linux virtual machine in Azure using Terraform”, I seek to guide you to building your first Linux Virtual Machine in Azure. Consider these set of steps as a project to enforce your terraform knowledge.
Configure Your Environment
Configure Deployment Parts
Create your vars.tf file
#Variable file used to store details of repetitive references
variable "location" {
description = "availability zone that is a string type variable"
type = string
default = "eastus2"
}
variable "prefix" {
type = string
default = "emc-eus2-corporate"
}
Create your providers.tf file
#Variable file used to store details of repetitive references
variable "location" {
type = string
default = "eastus2"
}
variable "prefix" {
type = string
default = "emc-eus2-corporate"
}
In the next steps, we create the main.tf file and add the following cmdlets.
Create a virtual network
#Create virtual network and subnets
resource "azurerm_virtual_network" "emc-eus2-corporate-network-vnet" {
name = "emc-eus2-corporate-network-vnet"
location = azurerm_resource_group.emc-eus2-corporate-resources-rg.location
resource_group_name = azurerm_resource_group.emc-eus2-corporate-resources-rg.name
address_space = ["172.20.0.0/16"]
tags = {
environment = "Production"
}
}
Create a subnet
#Create subnet - presentation tier
resource "azurerm_subnet" "presentation-subnet" {
name = "presentation-subnet"
resource_group_name = azurerm_resource_group.emc-eus2-corporate-resources-rg.name
virtual_network_name = azurerm_virtual_network.emc-eus2-corporate-network-vnet.name
address_prefixes = ["172.20.1.0/24"]
}
#Create subnet - data access tier
resource "azurerm_subnet" "data-access-subnet" {
name = "data-access-subnet"
resource_group_name = azurerm_resource_group.emc-eus2-corporate-resources-rg.name
virtual_network_name = azurerm_virtual_network.emc-eus2-corporate-network-vnet.name
address_prefixes = ["172.20.2.0/24"]
}
Create a public IP address
#Create Public IP Address
resource "azurerm_public_ip" "emc-eus2-corporate-nic-01-pip" {
name = "emc-eus2-corporate-nic-01-pip"
location = azurerm_resource_group.emc-eus2-corporate-resources-rg.location
resource_group_name = azurerm_resource_group.emc-eus2-corporate-resources-rg.name
allocation_method = "Dynamic"
}
Create a network security group and SSH inbound rule
# Create Network Security Group and rule
resource "azurerm_network_security_group" "emc-eus2-corporate-nsg" {
name = "emc-eus2-corporate-nsg"
location = azurerm_resource_group.emc-eus2-corporate-resources-rg.location
resource_group_name = azurerm_resource_group.emc-eus2-corporate-resources-rg.name
security_rule {
name = "SSH"
priority = 1001
direction = "Inbound"
access = "Allow"
protocol = "Tcp"
source_port_range = "*"
destination_port_range = "22"
source_address_prefix = "*"
destination_address_prefix = "*"
}
}
Create a virtual network interface card
# Create network interface
resource "azurerm_network_interface" "corporate-webserver-vm-01-nic" {
name = "corporate-webserver-vm-01-nic"
location = azurerm_resource_group.emc-eus2-corporate-resources-rg.location
resource_group_name = azurerm_resource_group.emc-eus2-corporate-resources-rg.name
ip_configuration {
name = "corporate-webserver-vm-01-nic-ip"
subnet_id = azurerm_subnet.presentation-subnet.id
private_ip_address_allocation = "Dynamic"
public_ip_address_id = azurerm_public_ip.corporate-webserver-vm-01-ip.id
}
}
Connect the network security group to the network interface
# Connect the security group to the network interface
resource "azurerm_network_interface_security_group_association" "corporate-webserver-vm-01-nsg-link" {
network_interface_id = azurerm_network_interface.corporate-webserver-vm-01-nic.id
network_security_group_id = azurerm_network_security_group.emc-eus2-corporate-nsg.id
}
Create a storage account for boot diagnostics
# Generate random text for a unique storage account name
resource "random_id" "randomId" {
keepers = {
# Generate a new ID only when a new resource group is defined
resource_group = azurerm_resource_group.emc-eus2-corporate-resources-rg.name
}
byte_length = 8
}
Create a storage account for boot diagnostics
# Create storage account for boot diagnostics
resource "azurerm_storage_account" "corpwebservervm01storage" {
name = "diag${random_id.randomId.hex}"
location = azurerm_resource_group.emc-eus2-corporate-resources-rg.location
resource_group_name = azurerm_resource_group.emc-eus2-corporate-resources-rg.name
account_tier = "Standard"
account_replication_type = "LRS"
}
Create SSH Key
# Create (and display) an SSH key
resource "tls_private_key" "linuxsrvuserprivkey" {
algorithm = "RSA"
rsa_bits = 4096
}
Create a virtual machine
# Create virtual machine
resource "azurerm_linux_virtual_machine" "emc-eus2-corporate-webserver-vm-01" {
name = "emc-eus2-corporate-webserver-vm-01"
location = azurerm_resource_group.emc-eus2-corporate-resources-rg.location
resource_group_name = azurerm_resource_group.emc-eus2-corporate-resources-rg.name
network_interface_ids = [azurerm_network_interface.corporate-webserver-vm-01-nic.id]
size = "Standard_DC1ds_v3"
os_disk {
name = "corpwebservervm01disk"
caching = "ReadWrite"
storage_account_type = "Premium_LRS"
}
source_image_reference {
publisher = "Canonical"
offer = "0001-com-ubuntu-server-focal"
sku = "20_04-lts-gen2"
version = "latest"
}
computer_name = "corporate-webserver-vm-01"
admin_username = "linuxsrvuser"
disable_password_authentication = true
admin_ssh_key {
username = "linuxsrvuser"
public_key = tls_private_key.linuxsrvuserprivkey.public_key_openssh
}
}
Terraform Plan
The terraform plan command evaluates a Terraform configuration to determine the desired state of all the resources it declares, then compares that desired state to the real infrastructure objects being managed with the current working directory and workspace. It uses state data to determine which real objects correspond to which declared resources, and checks the current state of each resource using the relevant infrastructure provider’s API.
terraform plan
Terraform Apply
The terraform apply command performs a plan just like terraform plan does, but then actually carries out the planned changes to each resource using the relevant infrastructure provider’s API. It asks for confirmation from the user before making any changes, unless it was explicitly told to skip approval.
terraform apply
Command to find an image based on the SKU.
samuel@Azure:~$ az vm image list -s "2019-Datacenter" --output table You are viewing an offline list of images, use --all to retrieve an up-to-date list Offer Publisher Sku Urn UrnAlias Version ------------- ---------------------- --------------- ----------------------------------------------------------- ----------------- --------- WindowsServer MicrosoftWindowsServer 2019-Datacenter MicrosoftWindowsServer:WindowsServer:2019-Datacenter:latest Win2019Datacenter latest samuel@Azure:~$
samuel@Azure:~$ az vm image list -s "18.04-LTS" --output table You are viewing an offline list of images, use --all to retrieve an up-to-date list Offer Publisher Sku Urn UrnAlias Version ------------ ----------- --------- --------------------------------------- ---------- --------- UbuntuServer Canonical 18.04-LTS Canonical:UbuntuServer:18.04-LTS:latest UbuntuLTS latest
Command to find an image based on the Publisher.
samuel@Azure:~$ az vm image list -p "Microsoft" --output table You are viewing an offline list of images, use --all to retrieve an up-to-date list Offer Publisher Sku Urn UrnAlias Version ------------- ---------------------- ---------------------------------- ------------------------------------------------------------------------------ ----------------------- --------- WindowsServer MicrosoftWindowsServer 2022-Datacenter MicrosoftWindowsServer:WindowsServer:2022-Datacenter:latest Win2022Datacenter latest WindowsServer MicrosoftWindowsServer 2022-datacenter-azure-edition-core MicrosoftWindowsServer:WindowsServer:2022-datacenter-azure-edition-core:latest Win2022AzureEditionCore latest WindowsServer MicrosoftWindowsServer 2019-Datacenter MicrosoftWindowsServer:WindowsServer:2019-Datacenter:latest Win2019Datacenter latest
samuel@Azure:~$ az vm image list -p "Canonical" --output table You are viewing an offline list of images, use --all to retrieve an up-to-date list Offer Publisher Sku Urn UrnAlias Version ------------ ----------- --------- --------------------------------------- ---------- --------- UbuntuServer Canonical 18.04-LTS Canonical:UbuntuServer:18.04-LTS:latest UbuntuLTS latest
At this point, the required pieces to build a Linux Virtual Machine on Azure is complete. It’s time to test your code.
You can learn more from Hashicorp by visiting the following link.
This article was helpful in troubleshooting issues with the Ubuntu SKU.
