Introducción
Si estás buscando como desplegar un servidor web en Azure con CLI, has llegado al lugar indicado. En el mundo del Cloud Engineering, no basta con saber hacer clics en un portal web; la verdadera escalabilidad, seguridad y eficiencia se logran mediante la automatización y la Infraestructura como Código (IaC).
En este artículo, te guiaré a través del despliegue de una arquitectura de Infraestructura como Servicio (IaaS) robusta y lista para producción. Resolveremos un desafío arquitectónico clásico: la separación del cómputo y el almacenamiento. Al desacoplar nuestro disco de datos del sistema operativo de la máquina virtual (Ubuntu), garantizamos que la información crítica sobreviva a fallos del servidor y pueda migrarse fácilmente.
Prepárate para ensuciarte las manos en la terminal. Veremos desde la creación de redes seguras hasta la inyección de configuraciones de arranque y el montaje de particiones en Linux, todo mientras resolvemos problemas reales que ocurren en el día a día de un Cloud Engineer.
Requisitos Previos
Dado que estaremos trabajando mediante línea de comandos (CLI) en un entorno local, asegúrate de tener listo tu entorno de trabajo con las siguientes herramientas:
- Visual Studio Code (VS Code): Nuestro editor de código principal.
- Azure CLI: Instalado en tu sistema operativo local (Ubuntu, Windows vía WSL, o macOS).
- Extensiones de VS Code: Se recomienda la extensión oficial de Azure CLI Tools y YAML para el autocompletado y validación de sintaxis.
- Una suscripción activa de Microsoft Azure: Con permisos suficientes para crear recursos (Owner o Contributor).
- Terminal Bash/Zsh: Para ejecutar los scripts de despliegue y administración.
Documentacion oficial de Azure CLI
https://learn.microsoft.com/es-es/cli/azure/?view=azure-cli-latest
Repositorio en GitHub del Proyecto
Paso a Paso del Ejercicio
Fase 1: Fundamentos de Arquitectura y Preparación
Antes de lanzar comandos al aire, un buen arquitecto organiza su entorno. Para este proyecto, hemos estructurado nuestro código en scripts de Bash (deploy.sh) y archivos de configuración.
Buenas prácticas aplicadas:
- Rutas relativas: En nuestros scripts, utilizaremos rutas relativas (como
./config/cloud-init.yaml) para mantener el repositorio limpio y portable. - Identificación visual: Hemos integrado comandos
echo(a los cuales puedes agregar códigos de color ANSI) para que la consola nos indique claramente qué recurso se está creando en cada fase.
Fase 2: Desplegar servidor web en Azure con CLI (Infraestructura como Código)
En esta fase, construiremos la columna vertebral de nuestra infraestructura. Analicemos paso a paso el script de despliegue que hemos llamado deploy.sh.
Redes y Seguridad (El Cimiento)
Toda infraestructura en la nube comienza con la red. Nuestro script primero crea el Resource Group, que actuará como el contenedor lógico. Luego, provisionamos una Virtual Network (VNet) y una Subnet para aislar nuestro entorno.
Para la salida a internet, utilizamos una IP Pública con SKU Standard y asignación estática, lo que garantiza que nuestra IP no cambiará si la máquina virtual se reinicia. Finalmente, aplicamos el Principio de Menor Privilegio creando un Network Security Group (NSG) que solo permite tráfico por los puertos 80 (HTTP) y 22 (SSH).
# 1. Crear el grupo de recursos adonde se alojara toda la Infraestructura.
echo "CREANDO GRUPO DE RECURSOS"
az group create \
--name ProyectoWeb-RG \
--location eastus
# 2. Crear la Vnet y la Subnet.
echo "CREANDO VIRTUAL NETWORK Y SUBNET"
az network vnet create \
--resource-group ProyectoWeb-RG \
--name WebVNet \
--address-prefix 10.0.0.0/16 \
--subnet-name WebSubnet \
--subnet-prefix 10.0.1.0/24
# 3. Crear una Public IP.
echo "CREANDO DIRECCION DE IP PUBLICA"
az network public-ip create \
--resource-group ProyectoWeb-RG \
--name WebPublicIP \
--sku Standard \
--allocation-method Static
#4. Crear un Network Security Group
echo "CREANDO NETWORK SECURITY GROUP"
az network nsg create \
--resource-group ProyectoWeb-RG \
--name WebNSG
#5. Crear regla en el NSG para permitir tráfico Web (HTTP - Puerto 80)
echo "CREANDO REGLA EN NSG PARA PERMITIR TRAFICO HTTP EN PUERTO 80"
az network nsg rule create \
--resource-group ProyectoWeb-RG \
--nsg-name WebNSG \
--name Allow-HTTP \
--priority 100 \
--destination-port-range 80 \
--access Allow \
--protocol Tcp
#6. Crear regla en el NSG para permitir administración (SSH - Puerto 22)
echo "CREANDO REGLA EN NSG PARA PERMITIR CONECXION CON SSH"
az network nsg rule create \
--resource-group ProyectoWeb-RG \
--nsg-name WebNSG \
--name Allow-SSH \
--priority 110 \
--destination-port-range 22 \
--access Allow \
--protocol TcpBash
Cómputo y Automatización (El Cerebro)
A continuación, desplegamos nuestra máquina virtual WebServer-VM (tamaño Standard_B2s). Aquí es donde la magia de la automatización ocurre mediante la bandera --custom-data. Le inyectamos el archivo cloud-init.yaml, el cual se encarga de actualizar los repositorios, instalar Apache e inyectar un archivo index.html personalizado durante el primer arranque, eliminando la necesidad de instalación manual.
# 7. Crear una VM
echo "CREANDO MAQUINA VIRTUAL"
az vm create \
--resource-group ProyectoWeb-RG \
--name WebServer-VM \
--image Ubuntu2204 \
--size Standard_B2s \
--vnet-name WebVNet \
--subnet WebSubnet \
--public-ip-address WebPublicIP \
--nsg WebNSG \
--admin-username azureuser \
--generate-ssh-keys \
--custom-data ./config/cloud-init.yaml \
--os-disk-name WebServer-OS-Disk \
--os-disk-size-gb 32 \
--storage-sku StandardSSD_LRSBash# cloud-init.yaml
#cloud-config
package_upgrade: true
packages:
- apache2
runcmd:
- echo "<h1>Bienvenido al Servidor Web de David - Proyecto CLI</h1><p>Desplegado con infraestructura como codigo en Azure.</p>" | sudo tee /var/www/html/index.html
- systemctl restart apache2YAMLAlmacenamiento Desacoplado (La Bóveda)
En lugar de guardar los datos en el disco temporal del sistema operativo, creamos un disco gestionado (Managed Disk) independiente.
💡 Tip de Arquitecto (Optimización de Costos): Los discos Premium en Azure se cobran por niveles (“Tiers”). El nivel P3 tiene un límite de 16GB. En lugar de solicitar un tamaño arbitrario como 8GB o 10GB, es mejor aprovechar todo el espacio por el que estás pagando solicitando directamente el límite superior del Tier.
Por motivos de seguridad empresarial, deshabilitamos el acceso público al disco (--public-network-access Disabled) y forzamos el cifrado con claves de la plataforma de Azure. Finalmente, lo adjuntamos a la VM en el LUN 0.
# Fragmento de deploy.sh (Almacenamiento)
az disk create \
--resource-group ProyectoWeb-RG \
--name DataDisk-01 \
--sku Premium_LRS \
--size-gb 8 \
--tier P3 \
--public-network-access Disabled \
--network-access-policy DenyAll \
--encryption-type EncryptionAtRestWithPlatformKey
az vm disk attach \
--resource-group ProyectoWeb-RG \
--vm-name WebServer-VM \
--name DataDisk-01 \
--lun 0BashFase 3: Administración Linux (SysAdmin en el Servidor)
Una vez que la infraestructura está viva, debemos acceder a la máquina mediante SSH para configurar el disco a nivel del Sistema Operativo. Azure nos adjuntó el disco físico, pero Linux aún no sabe cómo usarlo.
Al ejecutar lsblk, verás la anatomía clásica de discos en Azure: sda (Sistema Operativo), sdb (Disco temporal efímero en /mnt, ¡nunca guardes datos críticos aquí!), y nuestro nuevo disco crudo sdc.
Usaremos parted para darle una tabla de particiones GPT, mkfs.ext4 para darle formato y finalmente lo montaremos en /datos.
El toque Senior (Persistencia): Si reinicias el servidor ahora, perderás el montaje. Para que sobreviva, extraemos el UUID del disco y lo inyectamos en el archivo /etc/fstab. Es vital incluir el parámetro nofail; esto le dice a Linux que si el disco de datos tarda en responder o falla, el sistema operativo principal igual debe arrancar, evitando una caída total del servidor.
# 1. OBTENIENDO DIRECCION IP DEL SERVIDOR
echo "OBTENIENDO DIRECCION IP DEL SERVIDOR"
az vm show -d -g ProyectoWeb-RG -n WebServer-VM --query publicIps -o tsv
# 2. CONECTANDO CON VM CON SSH (CAMBIAR DIRECCION IP ANTES DE EJECUTAR)
ssh azureuser@13.72.98.203
# 3. VERIFICAMOS EL HARDWARE DE LA VM
lsblk
# 4. SI NO APARECE EL SDC EJECUTAMOS EL SIGUIENTE CODIGO
sudo parted /dev/sdc --script mklabel gpt mkpart primary ext4 0% 100%
# 5. VAMOS A DARLE FORMATO DE ARCHIVO DE LINUX (ext4)
sudo mkfs.ext4 /dev/sdc1
# 6. CREAR BODEGA DE DATOS SEGURA Y CONECTAMOS LA PARTICION
sudo mkdir /datos
sudo mount /dev/sdc1 /datos
# 7. VERIFICAMOS EL ALMACENAMIENTO
df -h
# 8. EXTRAEMOS EL UUID A UNA VARIABLE PARA USARLO DESPUES
UUID=$(sudo blkid -s UUID -o value /dev/sdc1)
# 9. INYECTAMOS CONFIGURACION PARA QUE LINUX RECUERDE CONECTARSE AL DISCO DE DATOS
echo "UUID=${UUID} /datos ext4 defaults,nofail 1 2" | sudo tee -a /etc/fstab
# 10. OBLIGAMOS A LINUX A REGARDAR TODAS LAS CONFIGURACIONES DE MONTAJE
sudo mount -aBashFase 4: Troubleshooting y Retos de la Vida Real
En la vida real, los laboratorios no siempre salen perfectos a la primera. Aquí documentamos tres incidencias clave que enfrentamos y cómo resolverlas:
- Zero-Day Bug en Azure CLI: Al ejecutar
az vm create, recibimos un error de parseo JSON (Extra data: line 1 column 4). Tras investigar, determinamos que era un bug reciente introducido en la versión 2.83.0 de la CLI.- Solución: Se realizó un downgrade seguro a la versión estable 2.82.0 usando el gestor de paquetes
apten Ubuntu, lo que nos permitió desbloquear el despliegue.
- Solución: Se realizó un downgrade seguro a la versión estable 2.82.0 usando el gestor de paquetes
- Problemas de Permisos en Linux: Al intentar ejecutar el script localmente con
./deploy.sh, la terminal devolvió el mensajePermission denied.- Solución: Por defecto, los archivos nuevos solo tienen permisos de lectura y escritura. Utilizamos el comando
chmod +x deploy.shpara otorgar permisos de ejecución al propietario.
- Solución: Por defecto, los archivos nuevos solo tienen permisos de lectura y escritura. Utilizamos el comando
Conclusión
Con este ejercicio, has pasado de simplemente conocer los comandos de Azure a aplicar mentalidad de arquitecto y SysAdmin. Logramos aprovisionar una máquina virtual segura, configurarla automáticamente mediante cloud-init y proteger nuestros datos desacoplando el almacenamiento del cómputo; además, fortalecimos nuestra capacidad de troubleshooting enfrentándonos a errores reales de la CLI y de Linux.
La mejor forma de dominar estas habilidades es la práctica. Anímate a replicar este entorno, destruirlo y volverlo a crear (¡la magia de la nube!). Si tuviste algún problema diferente al ejecutar los comandos, o tienes dudas sobre los niveles de discos Premium, ¡déjalo en los comentarios! Estaré encantado de ayudarte en tu camino como Cloud Engineer.