Creating the required infrastructure with Terraform – Immutable Infrastructure with Packer-1
Our goal was to build a scalable LAMP stack, so we will define a VM scale set using the apache-webserver image we created and a single VM with the mysql-dbserver image. A VM scale set is an autoscaling group of VMs that will scale out and scale back horizontally based on traffic, similar to how we did with containers on Kubernetes.
We will create the following resources:
• A new resource group called lamp-rg
• A virtual network within the resource group called lampvnet
• A subnet within lampvnet called lampsub
• Within the subnet, we create a Network Interface Card (NIC) for the database called db-nic that contains the following:
A network security group called db-nsg
A VM called db that uses the custom mysql-dbserver image
• We then create a VM scale set that includes the following:
A network profile called webnp
A backend address pool
A load balancer called web-lb
A public IP address attached to web-lb
An HTTP probe that checks the health of port 80
The following figure explains the topology graphically:

Figure 10.3 – Scalable LAMP stack topology diagram
To access resources for this section, switch to the following directory:
$ cd ~/modern-devops/ch10/terraform
We use the following Terraform template, main.tf, to define the configuration.
We first define the Terraform providers:
terraform {
required_providers {
azurerm = {
source = “azurerm”
}
}
}
provider “azurerm” {
subscription_id = var.subscription_id
client_id = var.client_id
client_secret = var.client_secret
tenant_id = var.tenant_id
}
We then define the custom image data sources so that we can use them within our configuration:
data “azurerm_image” “websig” {
name = “apache-webserver”
resource_group_name = “packer-rg”
}
data “azurerm_image” “dbsig” {
name = “mysql-dbserver”
resource_group_name = “packer-rg”
}
We then define the resource group, virtual network, and subnet:
resource “azurerm_resource_group” “main” {
name = var.rg_name
location = var.location
}
resource “azurerm_virtual_network” “main” {
name = “lampvnet”
address_space = [“10.0.0.0/16”]
location = var.location
resource_group_name = azurerm_resource_group.main.name
}
resource “azurerm_subnet” “main” {
name = “lampsub”
resource_group_name = azurerm_resource_group.main.name
virtual_network_name = azurerm_virtual_network.main.name
address_prefixes = [“10.0.2.0/24”]
}
As the Apache web servers will remain behind a network load balancer, we will define the load balancer and the public IP address that we will attach to it:
resource “azurerm_public_ip” “main” {
name = “webip”
location = var.location
resource_group_name = azurerm_resource_group.main.name
allocation_method = “Static”
domain_name_label = azurerm_resource_group.main.name
}
resource “azurerm_lb” “main” {
name = “web-lb”
location = var.location
resource_group_name = azurerm_resource_group.main.name frontend_ip_configuration {
name = “PublicIPAddress”
public_ip_address_id = azurerm_public_ip.main.id
}
tags = {}
}
We will then define a backend address pool to the load balancer so that we can use this within the
Apache VM scale set:
resource “azurerm_lb_backend_address_pool” “bpepool” {
loadbalancer_id
= azurerm_lb.main.id
name
= “BackEndAddressPool”
}
We will define an HTTP probe on port 80 for a health check and attach it to the load balancer:
resource “azurerm_lb_probe” “main” {
loadbalancer_id
= azurerm_lb.main.id
name
= “http-running-probe”
port
= 80
}
We need a NAT rule to map the load balancer ports to the backend pool port, and therefore, we will define a load balancer rule that will map port 80 on the load balancer with port 80 of the backend pool VMs. We will also attach the HTTP health check probe in this config:
resource “azurerm_lb_rule” “lbnatrule” {
resource_group_name = azurerm_resource_group.main.name
loadbalancer_id = azurerm_lb.main.id
name = “http”
protocol = “Tcp”
frontend_port = 80
backend_port = 80
backend_address_pool_ids = [ azurerm_lb_backend_address_pool.bpepool.id ]
frontend_ip_configuration_name = “PublicIPAddress”
probe_id = azurerm_lb_probe.main.id
}