Article available only in Spanish
1. Introducción
En este artículo se muestra cómo crear un cluster de máquinas virtuales Windows con Terraform en Azure con uso de módulos externos de Terraform Registry.
Si no estás familiarizado con Terraform, recomiendo eches un vistazo a los artículos previos de este blog listados a continuación, ya que se hace uso de diferentes elementos importantes previamente explicados en ellos:
2. Consideraciones Previas
En el artículo Terraform: Creación de Cluster de Máquinas Virtuales Windows vimos como crear un cluster de máquinas virtuales Windows usando solamente recursos del proveedor de Azure para Terraform (azurerm). En este artículo se muestra cómo crear el mismo cluster pero haciendo uso de módulos de Terraform Registry para Azure. El uso de módulos nos permite reutilizar código con características comunes, escribir mucho menos código en nuestros proyectos y en definitiva "no volver a reinventar la rueda" en nuestros proyectos.
No obstante, el uso de módulos externos requiere de la verificación de los componentes que nos permite generar, los componentes que crea por defecto y hasta que punto podemos parametrizar todos estos componentes ya que no siempre permiten definir una infraestructura exactamente como nosotros necesitamos. Saber utilizar los parametros de entrada, salida y dependencias de los módulos y comprender la lista de recursos que generan es fundamental cuando se trabaja con ellos. Una vez conocido bien todo lo que el módulo nos permite generar podemos complementar la infraestructura desplegada usando nuestro propio código HCL.
En este artículo voy a usar los módulos Terraform Azure RM Compute y Terraform Azure RM for Network de Terraform Registry. El primero nos permite crear máquinas virtuales y el segundo recursos de redes.
3. Configuración de Terraform
La configuración de nuestro proyecto de Terraform es la misma a la ya explicada en el artículo Terraform: Creación de Cluster de Máquinas Virtuales Windows en Azure en lo que se refiere a la estructura del proyecto, fichero variables.tf y fichero terraform.tfvars por lo que no volveré a incluirlos. Puedes verlos en el enlace anterior.
Este es el contenido de nuestro fichero main.tf con las explicaciones de cada bloque:
# Referencia al proveedor de Azure y configuración del service principal.
# El valor de client_secret será asignado a traves de la variable de entorno ARM_CLIENT_SECRET.
provider "azurerm" {
# Non-beta version >= 2.5.0 and < 3.0.0
version = "~>2.5"
# Configure service principal
subscription_id = var.azure_terraform_sp["subscription_id"]
client_id = var.azure_terraform_sp["client_id"]
tenant_id = var.azure_terraform_sp["tenant_id"]
# Required. Leave it empty if non-used.
features {}
}
# Referencia al blob (key) del contenedor (container_name) en la storage account de Azure (storage_account_name)
# para almacenar de forma remota y centralizada el estado de nuestro proyecto de Terraform.
# Este bloque no permite el uso de variables.
# El valor del atributo access_key es asignado mediante la variable de entorno ARM_ACCESS_KEY.
terraform {
backend "azurerm" {
resource_group_name = "jm-inn-core-rg"
storage_account_name = "jminnstgacc"
container_name = "terraform"
key = "tf-learn-vms-cluster-registry-modules.tfstate"
}
}
# Crea grupo de recursos donde se incluirán las máquinas virtuales y resto de componentes
resource "azurerm_resource_group" "rg" {
name = var.azure_new_resource_group["name"]
location = var.azure_new_resource_group["location"]
tags = var.azure_new_resource_group_tags
}
# Data source para referenciar Azure Key Vault con secretos de usuario y contraseña
data "azurerm_key_vault" "kv" {
name = var.azure_key_vault_name
resource_group_name = var.azure_key_vault_resource_group_name
}
# Data Source para obtener nombre de usuario administrador guardado en Azure Key Vault
data "azurerm_key_vault_secret" "vm_username" {
name = "vm-username-default"
key_vault_id = data.azurerm_key_vault.kv.id
}
# Data Source para obtener password de usuario administrador guardado en Azure Key Vault
data "azurerm_key_vault_secret" "vm_password" {
name = "vm-password-default"
key_vault_id = data.azurerm_key_vault.kv.id
}
# Módulo Terraform Azure RM Compute de Terraform Registry para creación de máquinas virtuales y recursos de computación.
# Referencia al módulo Terraform Azure RM for Network para ubicar las máquinas virtuales en la red virtual vía tarjetas de red (NICs)
module "vms" {
source = "Azure/compute/azurerm"
version = "3.5.0"
resource_group_name = azurerm_resource_group.rg.name
location = azurerm_resource_group.rg.location
tags = azurerm_resource_group.rg.tags
admin_username = data.azurerm_key_vault_secret.vm_username.value
admin_password = data.azurerm_key_vault_secret.vm_password.value
vm_size = var.vm_size
vm_os_simple = "WindowsServer"
is_windows_image = "true"
remote_port = "3389"
nb_instances = 2
nb_public_ip = 2
public_ip_dns = ["${var.prefix}-ip1", "${var.prefix}-ip2"]
vnet_subnet_id = module.network.vnet_subnets[0]
vm_hostname = var.prefix
}
# Módulo Terraform Azure RM for Network de Terraform Registry para creación de recursos de red
module "network" {
source = "Azure/network/azurerm"
version = "3.1.1"
resource_group_name = azurerm_resource_group.rg.name
vnet_name = "${var.prefix}-vnet"
}
# Regla de seguridad que permite tráfico entrante TCP en el puerto 80. No es posible crearla directamente en el módulo utilizado Terraform Azure RM Compute.
# Se asocia a la Network Security Group creada en el módulo "network".
resource "azurerm_network_security_rule" "rule_tcp_80" {
network_security_group_name = module.vms.network_security_group_name
resource_group_name = azurerm_resource_group.rg.name
name = "TCP_80"
priority = 200
direction = "Inbound"
access = "Allow"
protocol = "Tcp"
source_port_range = "*"
destination_port_range = "80"
source_address_prefix = "*"
destination_address_prefix = "*"
}
# Extensión para instalar IIS en las máquinas virtuales. No es posible hacerlo mediante el módulo Terraform Azure RM Compute.
resource "azurerm_virtual_machine_extension" "iis-windows-vm-extension" {
count = 2
name = "${var.prefix}-vm-${count.index}-extension"
virtual_machine_id = module.vms.vm_ids[count.index]
publisher = "Microsoft.Compute"
type = "CustomScriptExtension"
type_handler_version = "1.9"
settings = <<SETTINGS
{
"commandToExecute": "powershell Install-WindowsFeature -name Web-Server - IncludeManagementTools;"
}
SETTINGS
tags = var.azure_new_resource_group_tags
}
Como aspectos destacados vamos a comentar los siguientes:
- Los módulos utilizados crean infraestructura "por debajo" de forma transparente al usuario por lo que es importante leer muy bien la documentación asociada a cada módulo para entender qué recursos y cómo se están creando exactamente. Por ejemplo, el módulo Terraform Azure RM for Network crea una red virtual y una subred con rangos de direcciones establecidos por defecto (
10.0.0.0/16
y 10.0.0.0/24
respectivamente). Es posible que tengas que utilizar rangos diferentes. Por ello, sería necesario acudir a la documentación para ver que atributos de entrada pueden ser establecidos. Podrás comprobar que podríamos usar los atributos address_space
y subnet_prefixes
para fijar los rangos de red y subred respectivamente.
- El módulo Terraform Azure RM Compute para creación de máquinas virtuales nos permite establecer el número de máquinas virtuales a crear mediante el atributo
nb_instances
. En caso de modificar el valor por defecto ("1"), se crea un availability set para contener las máquinas virtuales cuyo identificador podría obtenerse mediante el atributo de salida availability_set_id
. En la documentación tienes la lista de recursos que puede crear el módulo según el valor del número de instancias. El atributo remote_port
nos permite fijar un puerto sobre el que se creará una regla en el Network Security Group asociado a la red que permite filtrar tráfico TCP entrante, en este caso sobre el puerto 3389 para permitir conexión RDP. Por último mediante el atributo vnet_subnet_id
podemos asignar la subred sobre la que se conectarán las máquinas virtuales vía tarjetas de red NIC (creadas de forma implicita por el módulo). El resto de atributos puedes verlos en la documentación del módulo.
- Si los módulos no ofrecen soporte para la creación de determinada infraestructura relacionada necesaria en tu proyecto siempre puedes añadir tu código HCL complementario propio una vez obtenidos los identificadores de los recursos generados, vía parámetros de salida del módulo o configurando data sources. Es el caso de la creación de la extensión para instalar IIS en las máquinas virtuales o la creación de la regla que permite tráfico TCP entrante en el puerto 80 de la Network Security Group asociada a la red virtual.
4. Ejecución de Terraform y Verificación en Azure
La ejecución de nuestro proyecto de Terraform sigue el mismo proceso que el ya explicado en el artículo Terraform: Creación de Máquinas Virtuales Windows en Azure por lo que iré directamente a verificar el resultado de la creación de infraestructura en Azure:
En la imagen superior vemos cómo se han creado las dos máquinas virtuales vm-cl-reg-md-vmWindows-0 y vm-cl-reg-md-vmWindows-1 junto con los componentes relacionados correspondientes. También vemos la existencia del availability set vm-cl-reg-md-avset. Si accedemos al availability set, podemos comprobar la existencia de dos fault domains y dos update domains, con cada máquina virtual en fault y update domains diferentes:
Por tanto, verificamos que el contenido creado con módulos de Terraform Registry es el mismo que el creado en el artículo Terraform: Creación de Cluster de Máquinas Virtuales Windows en el que solo usamos referencias directas a recursos del proveedor de Azure para Terraform. La diferencia en este artículo es que el código utilizado ha sido mucho menor.
Referencias