Introducción
Todo entorno en la nube necesita una base sólida y un perímetro seguro. En lugar de exponer servidores directamente a internet, las arquitecturas modernas exigen centros de datos privados virtuales, enrutamiento seguro y alta disponibilidad. En este artículo, aprenderás a desplegar Azure Load Balancer con Azure CLI, construyendo una infraestructura web robusta desde cero.
A lo largo de este ejercicio, resolveremos el problema de la distribución de tráfico y la exposición de recursos aplicando el modelo Zero Trust. Nuestras máquinas virtuales no tendrán IPs públicas, pero seguirán siendo capaces de actualizarse y servir contenido web de forma segura.
Para lograrlo, orquestaremos servicios clave como Azure Virtual Network (VNet), Network Security Groups (NSG), Azure NAT Gateway y, por supuesto, un balanceador de carga que distribuirá el tráfico entre múltiples máquinas virtuales con Nginx. ¡Manos a la obra!
Requisitos Previos
Antes de comenzar a ejecutar comandos, asegúrate de tener el siguiente entorno de trabajo configurado:
- Cuenta de Microsoft Azure: Una suscripción activa (puedes usar la capa gratuita).
- Visual Studio Code (VS Code): Tu editor de código principal.
- Azure CLI: Instalado en tu sistema operativo (Windows, macOS o Linux).
- Terminal Bash: Configurada como terminal integrada dentro de VS Code para ejecutar el script sin problemas de sintaxis.
Documentacion Azure CLI
https://learn.microsoft.com/es-es/cli/azure/?view=azure-cli-latest
Repositorio GitHub
https://github.com/DavidGonzalezCloud/azure-cli-journey.git
Paso a Paso del Ejercicio
Capa 1: Los Cimientos de Red y Aislamiento Lógico
El primer paso para desplegar Azure Load Balancer con Azure CLI es construir el bloque de terreno donde vivirá nuestra arquitectura. Creamos un grupo de recursos, una red virtual (VNet) con un espacio de direcciones amplio y una subred específica. Aislar recursos en subredes nos permitirá aplicar reglas de seguridad granulares más adelante.
# 1. DEFINICION ESTRICTA DE VARIABLES
RG_NAME="rg-portafolio-alb"
LOCATION="eastus"
VNET_NAME="vnet-frontend"
SUBNET_NAME="snet-web"
# 2. CREACION DE UN GRUPO DE RECURSOS
echo "Creando Grupo de Recursos: $RG_NAME en la region $LOCATION..."
az group create \
--name $RG_NAME \
--location $LOCATION
# 3. Creacion de Vnet y la subred en un solo comando
echo "Desplegando la Red Virtual ($VNET_NAME) y la Subred ($SUBNET_NAME)..."
az network vnet create \
--resource-group $RG_NAME \
--name $VNET_NAME \
--address-prefixes 10.0.0.0/16 \
--subnet-name $SUBNET_NAME \
--subnet-prefixes 10.0.1.0/24Bash
Capa 2: Seguridad Perimetral y Zero Trust
Bajo el modelo moderno de nube, no confiamos en nada por defecto. En lugar de asignar reglas a cada máquina (una pesadilla administrativa), creamos un Network Security Group (NSG) y lo asociamos directamente a la subred. Indicamos explícitamente que el único tráfico permitido hacia la subred es el protocolo TCP por el puerto 80.

# 4. Crear el Network Security Group (NSG)
echo "Creando el NSG para la capa web..."
az network nsg create \
--resource-group $RG_NAME \
--name nsg-web \
--location $LOCATION
# 5. Creamos la regla de firewall para permitir HTTP (puerto 80)
echo "Creando regla que permite trafico HTTP entrante..."
az network nsg rule create \
--resource-group $RG_NAME \
--nsg-name nsg-web \
--name Allow-HTTP \
--protocol tcp \
--priority 100 \
--destination-port-range 80 \
--access Allow \
--direction Inbound
# 6. Asociamos el NSG con la Subred.
echo "Asociamos el NSG con la Subred de los servidores web..."
az network vnet subnet update \
--resource-group $RG_NAME \
--vnet-name $VNET_NAME \
--name $SUBNET_NAME \
--network-security-group nsg-webBash
Capa 3: Enrutamiento de Salida con NAT Gateway
Para que nuestras máquinas sean inmutables y seguras, no les daremos una IP Pública. Sin embargo, necesitan salir a internet para descargar actualizaciones y el paquete de Nginx. Aquí entra el NAT Gateway, creando un túnel unidireccional: permite la salida total de las VMs enmascarando su IP privada, pero bloquea cualquier conexión que intente entrar desde internet por esa vía.
# Definición de variables para el NAT Gateway
NAT_GW_NAME="ngw-prod-web"
NAT_PIP_NAME="pip-ngw-prod-web"
# 7. Provisionamos la IP publica para el NAT Gateway (Debe ser Standard)
echo "Creando IP Publica para el NAT Gateway..."
az network public-ip create \
--resource-group $RG_NAME \
--name $NAT_PIP_NAME \
--sku Standard \
--allocation-method Static \
--location $LOCATION
# 8. Desplegar el NAT gateway
echo "Desplegando el NAT gateway..."
az network nat gateway create \
--resource-group $RG_NAME \
--name $NAT_GW_NAME \
--public-ip-address $NAT_PIP_NAME \
--location $LOCATION
# 9. Asociamos el NAT Gateway con la subnet web existente.
echo "Asociando NAT Gateway con la Subred web..."
az network vnet subnet update \
--resource-group $RG_NAME \
--vnet-name $VNET_NAME \
--name $SUBNET_NAME \
--nat-gateway $NAT_GW_NAMEBash
Capa 4: Distribución de Tráfico y Alta Disponibilidad
Este es el cerebro de nuestro proyecto. Queremos que los usuarios accedan a nuestra página, pero sin tocar directamente los servidores. El Load Balancer con su IP pública actuará como la fachada de tu aplicación.
Además, configuraremos un Health Probe (sondeo de salud) que enviará un “ping” TCP cada 10 segundos para verificar que Nginx esté sano. Crucialmente, usaremos el parámetro --disable-outbound-snat true en la regla de balanceo para forzar a las máquinas a usar el NAT Gateway para salir a internet.
# Definimos las variables para el Load Balancer
ALB_NAME="alb-prod-web"
ALB_PIP="pip-alb-web"
# 10. Creacion de la IP Publica Standard
echo "Creando la IP Publica Standard para el ALB..."
az network public-ip create \
--resource-group $RG_NAME \
--name $ALB_PIP \
--location $LOCATION \
--allocation-method Static
# 11. Creacion de Azure Load Balancer
echo "Desplegando Azure Load Balancer $ALB_NAME..."
az network lb create \
--resource-group $RG_NAME \
--name $ALB_NAME \
--sku Standard \
--public-ip-address $ALB_PIP \
--frontend-ip-name frontend-ip \
--backend-pool-name backend-pool
# 12. Creacion del Health Probe (Sondeo de salud de cada servidor)
echo "Creando el health Probe en el puerto 80..."
az network lb probe create \
--resource-group $RG_NAME \
--lb-name $ALB_NAME \
--name probe-http \
--protocol tcp \
--port 80 \
--interval 10
# 13. Creacion de la regla de balanceo
echo "Creando Regla de Balanceo de Carga..."
az network lb rule create \
--resource-group $RG_NAME \
--lb-name $ALB_NAME \
--name rule-http \
--protocol tcp \
--frontend-port 80 \
--backend-port 80 \
--frontend-ip-name frontend-ip \
--probe-name probe-http \
--disable-outbound-snat trueBash
Capa 5: Cómputo y Servidores Web
Finalmente, desplegamos nuestra carga de trabajo. Primero creamos las tarjetas de red (NICs) y las asociamos al Backend Pool de nuestro balanceador. Luego, provisionamos dos máquinas virtuales (Ubuntu 22.04) en Zonas de Disponibilidad separadas (--zone $i), obligando a Azure a colocarlas en edificios físicamente distintos dentro de la región.
Gracias al parámetro --custom-data, inyectamos un archivo de inicialización que instala y configura Nginx automáticamente.
#cloud-config
package_upgrade: true
packages:
- nginx
- python3
write_files:
- owner: www-data:www-data
path: /var/www/html/index.html
content: |
<!DOCTYPE html>
<html>
<body style="background-color: #F8F9FA; color: #212529; font-family: sans-serif; text-align: center; padding-top: 100px;">
<h1>Cloud Journey</h1>
<h2>Infraestructura de Alta Disponibilidad</h2>
<p>Respondiendo exitosamente desde el clúster detrás del Load Balancer</p>
<div style="background-color: #0078D4; color: white; padding: 15px; display: inline-block; border-radius: 8px; font-weight: bold; margin-top: 20px;">
Trafico enrutado por Azure ALB
</div>
<footer style="margin-top: 80px; color: #0B1120;">
<span style="color: #00BCF2;">■</span> Nodo Activo
</footer>
</body>
</html>
runcmd:
- systemctl restart nginx
YAML# 14. Creamos dos Network Interface Cards (NICs)
for i in 1 2; do
echo "Creando Tarjeta de Red (NIC) para el servidor 0$i..."
az network nic create \
--resource-group $RG_NAME \
--name nic-web-0$i \
--vnet-name $VNET_NAME \
--subnet $SUBNET_NAME \
--lb-name $ALB_NAME \
--lb-address-pools backend-pool
done
# Variable para mantener maquinas virtuales de bajo costo
VM_SIZE="Standard_B1s"
# 15. Creamos dos maquinas virtuales para el backend
for i in 1 2; do
echo "Creando Maquina Virtual (VM) vm-web-0$i en la Zona $i..."
az vm create \
--resource-group $RG_NAME \
--name vm-web-0$i \
--nics nic-web-0$i \
--size $VM_SIZE \
--image Ubuntu2204 \
--admin-username azureuser \
--generate-ssh-keys \
--custom-data cloud-init.yaml \
--zone $i \
--no-wait
doneBash
El “Viaje de la Petición” (Resumen del Flujo)
Para visualizar cómo interactúa todo esto en microsegundos cuando un usuario visita tu sitio web:
- Un usuario escribe la IP Pública de tu Load Balancer en su navegador.
- La petición TCP por el puerto 80 llega a la puerta frontal de Azure y el Load Balancer la recibe.
- El Load Balancer revisa su Health Probe: “Ambas máquinas están sanas. La última petición fue a VM-01, así que esta irá a VM-02”.
- El paquete es redirigido a la tarjeta de red (nic-web-02) en la VNet.
- Antes de llegar, choca con el NSG. Este inspecciona el paquete, verifica que es TCP/80 y lo aprueba.
- El servidor Nginx en la
vm-web-02procesa el HTML de tu portafolio y lo devuelve exactamente por el mismo camino hacia el usuario.
Conclusión
¡Felicidades! Has logrado desplegar una infraestructura empresarial de alta disponibilidad en Azure. Configuraste una red aislada, blindaste la entrada con un NSG, aseguraste la salida de tus servidores con un NAT Gateway y distribuiste el tráfico eficientemente utilizando Azure Load Balancer. Aplicar estas prácticas de infraestructura inmutable y Zero Trust te preparan para arquitecturas en la nube a gran escala.
¿Qué te pareció este flujo de trabajo con la CLI de Azure? Anímate a replicarlo en tu entorno y, si tienes problemas durante el despliegue o dudas sobre alguna capa, ¡déjalo en la caja de comentarios abajo y lo resolveremos juntos en la comunidad de Cloud Journey!