Cómo desplegar y monitorear aplicaciones web en Azure con Terraform: Guía paso a paso
Tags: azure, terraform, automations, spanish
Published: 2024-05-19 12:31:52

---
title: Cómo desplegar y monitorear aplicaciones web en Azure con Terraform: Guía paso a paso
published: true
tags: Azure, Terraform, Automations, Spanish
canonical_url: https://danieljsaldana.dev/como-desplegar-y-monitorear-aplicaciones-web-en-azure-con-terraform-guia-paso-a-paso/
cover_image: https://dev-to-uploads.s3.amazonaws.com/uploads/articles/tg3aagm0rpwv02ojeger.png
---

En este post, quiero compartir cómo desarrollé un módulo de Terraform para desplegar varios recursos en Azure que son esenciales para monitorear una aplicación web. Este módulo permite implementar de manera eficiente y repetible servicios como Log Analytics, Application Insights, grupos de acción y pruebas web estándar de Application Insights.

### Recursos de Azure utilizados

El módulo desplegará los siguientes recursos de Azure:

- **Grupos de Recursos (Resource Groups)**: Contenedores que mantienen los recursos relacionados de Azure juntos.
- **Log Analytics Workspace** : Servicio que proporciona una solución unificada de gestión de logs y análisis de datos.
- **Application Insights** : Servicio que ayuda a monitorear el rendimiento y uso de aplicaciones web.
- **Monitor Action Groups** : Grupos de acción que pueden ejecutar respuestas automáticas a las alertas.
- **Key Vault** : Servicio para gestionar y mantener de manera segura secretos, claves y certificados.
- **Application Insights Standard Web Test** : Pruebas web que monitorean la disponibilidad y el rendimiento de aplicaciones web.

Este módulo es ideal para usuarios de servicios de aplicaciones web estáticas que desean monitorear sus aplicaciones, ver logs y obtener métricas detalladas sobre el rendimiento de sus aplicaciones web.

## Contenido de main.tf

### Configuración del Proveedor de Azure

Primero, inicializamos el proveedor de Azure. Esto es esencial para gestionar cualquier recurso en Azure con Terraform.

```
provider "azurerm" {
  features {}
}

```

### Creación del Grupo de Recursos

Definimos la creación de un grupo de recursos de manera condicional, basado en una variable. Esto permite mayor flexibilidad y reutilización del módulo, ya que podemos decidir dinámicamente si queremos crear un grupo de recursos.

```
resource "azurerm_resource_group" "resource_group" {
  count = var.create_resource ? 1 : 0

  name = "log-analytics-workspace"
  location = "West Europe"
}

```

### Log Analytics Workspace

Creamos un espacio de trabajo de Log Analytics, que será utilizado para centralizar los datos de monitoreo y diagnóstico.

```
resource "azurerm_log_analytics_workspace" "analytics_workspace" {
  count = var.create_resource ? 1 : 0

  name = "shared-workspace"
  location = "westeurope"
  resource_group_name = azurerm_resource_group.resource_group[0].name
  sku = "PerGB2018"
  retention_in_days = 30
  tags = var.tags
}

```

### Application Insights

Deployamos instancias de Application Insights. Este recurso es fundamental para monitorear el rendimiento de las aplicaciones y detectar problemas potenciales.

```
resource "azurerm_application_insights" "application_insights" {
  for_each = var.create_resource ? var.resources : {}
  name = each.value.app_insights_name
  location = var.location
  resource_group_name = var.resource_group_name
  workspace_id = azurerm_log_analytics_workspace.analytics_workspace[0].id
  application_type = each.value.application_type
  tags = each.value.tags
}

```

### Monitor Action Group

Creamos un grupo de acción para la detección inteligente de Application Insights. Estos grupos son esenciales para definir respuestas automáticas a alertas específicas, mejorando la capacidad de respuesta ante incidentes.

```
resource "azurerm_monitor_action_group" "application_insights_smart_detection" {
  count = var.create_resource ? 1 : 0

  name = "Application Insights Smart Detection"
  resource_group_name = var.resource_group_name
  short_name = "SmartDetect"
  location = "Global"

  arm_role_receiver {
    name = "Monitoring Contributor"
    role_id = "749f88d5-cbae-40b8-bcfc-e573ddc772fa"
    use_common_alert_schema = true
  }

  arm_role_receiver {
    name = "Monitoring Reader"
    role_id = "43d0d8ad-25c7-4714-9337-8ba259a9fe05"
    use_common_alert_schema = true
  }
}

```

### Key Vault

Configuramos el almacenamiento de secretos en Azure Key Vault. Esto asegura que los secretos y claves de las aplicaciones estén protegidos y gestionados de manera segura.

```
resource "azurerm_key_vault_secret" "app_insights_secrets_app_insights_connection_string" {
  depends_on = [azurerm_application_insights.application_insights]
  for_each = var.create_resource ? { for k, v in var.resources : k => v } : {}

  name = format("%s-insights-key", each.value.app_insights_name)
  value = azurerm_application_insights.application_insights[each.key].connection_string
  key_vault_id = data.azurerm_key_vault.vault.id
}

```

### Application Insights Standard Web Test

Configuramos pruebas web estándar para monitorear la disponibilidad y el rendimiento de nuestras aplicaciones web desde varias ubicaciones geográficas.

```
resource "azurerm_application_insights_standard_web_test" "web_test" {
  for_each = { for k, v in var.resources : k => v if var.create_resource && v.domain != "" }

  name = each.value.app_insights_name
  resource_group_name = var.resource_group_name
  location = var.location
  application_insights_id = azurerm_application_insights.application_insights[each.key].id
  geo_locations = [
    "emea-fr-pra-edge",
    "emea-nl-ams-azr",
    "apac-jp-kaw-edge",
    "latam-br-gru-edge"
  ]

  description = "Web test for ${each.value.app_insights_name}"
  enabled = true
  frequency = 300
  retry_enabled = true
  tags = var.tags
  timeout = 30

  request {
    url = format("http://%s", each.value.domain)
  }
}

```

### Output de Cadenas de Conexión e IDs de aplicaciones

Finalmente, definimos los outputs que incluyen las cadenas de conexión y los IDs de las aplicaciones para facilitar la integración con otros módulos o scripts.

```
output "connection_string" {
  value = {
    for k, v in var.resources :
    k => var.create_resource ? try(azurerm_application_insights.application_insights[k].connection_string, null) : null
  }
  sensitive = true
}

output "app_ids" {
  value = {
    for k, v in var.resources :
    k => var.create_resource ? try(azurerm_application_insights.application_insights[k].app_id, null) : null
  }
}

```

## Contenido de variables.tf

Definimos las variables necesarias en el archivo `variables.tf`. Las variables permiten una configuración flexible y reutilizable del módulo, adaptándolo a diferentes entornos y necesidades específicas.

```
variable "create_resource" {
  type = bool
  default = true

  validation {
    condition = var.create_resource == true || var.create_resource == false
    error_message = "El valor de create_resource debe ser verdadero o falso."
  }
}

variable "resource_group_name" {
  description = "The name of the resource group"
  type = string

  validation {
    condition = length(var.resource_group_name) > 0
    error_message = "The resource group name must be provided."
  }
}

variable "location" {
  description = "The location for all resources"
  type = string

  validation {
    condition = length(var.location) > 0
    error_message = "The location must be provided."
  }
}

variable "resources" {
  description = "Map of resource configurations"
  type = map(object({
    app_insights_name = string
    application_type = string
    static_web_apps = list(string)
    domain = optional(string)
    tags = optional(map(string))
  }))

  validation {
    condition = length(var.resources) > 0
    error_message = "At least one resource must be provided."
  }
}

variable "vault_name" {
  description = "The name of the Vault to store the keys"
  type = string

  validation {
    condition = length(var.vault_name) > 0
    error_message = "The Vault name must be provided."
  }
}

variable "tags" {
  description = "Un mapa de etiquetas"
  type = map(string)

  validation {
    condition = length(var.tags) > 0
    error_message = "Se debe proporcionar al menos una etiqueta."
  }
}

```

## Contenido de data.tf

En el archivo `data.tf`, obtenemos datos de Key Vault necesarios para configurar los secretos de las aplicaciones.

```
data "azurerm_key_vault" "vault" {
  name = var.vault_name
  resource_group_name = var.resource_group_name
}

```

## Contenido de outputs.tf

Definimos outputs en el archivo `outputs.tf` para las cadenas de conexión y los IDs de las aplicaciones. Esto facilita la integración y el uso de estos datos en otros módulos o scripts.

```
output "connection_string" {
  value = {
    for k, v in var.resources :
    k => var.create_resource ? try(azurerm_application_insights.application_insights[k].connection_string, null) : null
  }
  sensitive = true

}

output "app_ids" {
  value = {
    for k, v in var.resources :
    k => var.create_resource ? try(azurerm_application_insights.application_insights[k].app_id, null) : null
  }
}

```

## Ejemplo de Configuración

Aquí tienes un ejemplo de configuración para utilizar este módulo:

```
create_resource = true
resource_group_name = "ejemplo-grupo-recursos"
location = "westeurope"
resources = {
  "resource1" = {
    app_insights_name = "appinsights-frontend"
    application_type = "web"
    static_web_apps = ["frontend-test"]
    domain = "frontend.com"
  },
  "resource2" = {
    app_insights_name = "appinsights-backend"
    application_type = "web"
    static_web_apps = ["backend-test"]
    domain = ""
  }
}
tags = {
  Project = "Proyecto Ejemplo"
  Tier = "Gratis"
  Environment = "Producción"
}
vault_name = "vault-ejemplo"

```

## Conclusión

Este módulo de Terraform facilita la gestión de recursos en Azure, asegurando una configuración coherente y repetible. Al utilizar variables y condicionales, podemos adaptarlo a diferentes entornos y necesidades específicas. Este módulo es especialmente útil para aquellos que utilizan servicios de aplicaciones web estáticas en Azure y desean monitorear sus aplicaciones, ver logs y obtener métricas detalladas. ¡Espero que este post te haya proporcionado una visión clara de cómo desarrollar un módulo de Terraform para Azure! ¡Gracias por leer!