Cerraste el módulo 1 con los cimientos puestos: la cuenta, la jerarquía de facturación, los grupos de recursos rg-contoso-reservas-dev y rg-contoso-reservas-pro, el esquema de etiquetado obligatorio y un script de Azure CLI que despliega todo eso de forma idempotente. Ahora empieza la construcción real de la plataforma, y lo hacemos por la pieza menos glamurosa y más inevitable: una máquina virtual.

Contoso Airlines tiene un problema muy común en cualquier migración. Su motor de disponibilidad heredado —el proceso que calcula qué plazas quedan libres en cada vuelo y a qué precio— es una aplicación Java monolítica escrita hace once años, con dependencias del sistema operativo, rutas absolutas y un servicio que arranca con un script propio. Nadie en el equipo se atreve a reescribirlo antes de la temporada alta. Diego Salas lo resume en una frase: «funciona, no lo entiende nadie del todo, y si lo tocamos ahora no vendemos billetes en julio».

Esa aplicación no puede ir a un servicio de plataforma todavía. Necesita un servidor con acceso al sistema operativo. En Azure, eso es una máquina virtual. En esta lección aprenderás cuándo una VM es la respuesta correcta y cuándo es una pereza cara, qué recursos arrastra consigo, cómo elegir tamaño y disco sin arruinarte, cómo crearla y configurarla desde Azure CLI, y —sobre todo— cómo apagarla de forma que deje de facturar de verdad, que es un matiz que sorprende a casi todo el mundo la primera vez.

Aviso de coste: esta lección crea recursos que se facturan por hora. Un tamaño Standard_B1s con disco Standard SSD cuesta muy poco al día, pero no cuesta cero. Al final de la lección tienes la limpieza completa; ejecútala si no vas a seguir usando la VM.

Contenido

  1. VM frente a PaaS: cuándo tiene sentido cada uno
  2. Anatomía de una máquina virtual en Azure
  3. Familias y tamaños de VM: cómo leer la nomenclatura
  4. Discos: tipos, rendimiento y coste
  5. Imágenes: marketplace, imágenes propias y galerías
  6. Crear la VM del motor de disponibilidad con Azure CLI
  7. Conectarse por SSH e instalar el servicio
  8. Configuración inicial automática: cloud-init y extensiones
  9. Estados de una VM y qué se factura en cada uno
  10. Instantáneas e imágenes: copias y clones
  11. Limpieza al terminar
  12. Errores Comunes y Consejos
  13. Ejercicios
  14. Conclusión

  1. VM frente a PaaS: cuándo tiene sentido cada uno

En la lección 01-02 viste el modelo de responsabilidad compartida: con IaaS gestionas el sistema operativo hacia arriba; con PaaS, solo tu aplicación y sus datos. La pregunta práctica no es cuál es «mejor», sino qué te obliga a quedarte abajo.

Situación Elección razonable Por qué
Software heredado con dependencias del SO, servicios propios, rutas fijas Máquina virtual Necesitas control total del sistema operativo
Licencia de terceros que exige instalación en servidor Máquina virtual El fabricante no soporta otro modelo
Aplicación web moderna (Java, .NET, Node, Python) empaquetable App Service (02-03) Menos superficie que administrar y parchear
Proceso por eventos, ejecución corta e intermitente Azure Functions (06-03) Pagas por ejecución, no por servidor encendido
Aplicación ya contenerizada Container Apps / AKS (06-01, 06-02) Portabilidad y densidad
Necesitas GPU, kernel personalizado o software de red a bajo nivel Máquina virtual Solo IaaS te da ese nivel

El coste real de una VM no es la factura mensual: es el trabajo recurrente que trae consigo. Parches del sistema operativo, copias de seguridad, endurecimiento de la configuración, supervisión del agente, rotación de claves. Con App Service, buena parte de eso desaparece de tu lista.

Por eso la decisión de Contoso queda registrada así, y conviene que la interiorices porque marca todo el módulo:

  • El motor de disponibilidad heredado va a VM, como paso intermedio y explícitamente temporal.
  • Contoso Reservas (web pública) y la nueva API de Disponibilidad van a App Service (lección 02-03).
  • La VM se moderniza más adelante, cuando el equipo pueda reescribir el motor; en el módulo 6 verás a dónde acaba yendo.

Esto es exactamente lo que el Cloud Adoption Framework llama rehost («lift and shift»): mueves primero, optimizas después. Es una estrategia legítima siempre que el «después» tenga fecha. Si no la tiene, la VM se queda diez años.

  1. Anatomía de una máquina virtual en Azure

Cuando en el portal pulsas «Crear máquina virtual», Azure no crea un recurso: crea varios, cada uno con su propio ciclo de vida y su propia línea en la factura. Entender esto evita la sorpresa clásica de borrar la VM y seguir pagando.

graph TD
    RG["Grupo de recursos<br/>rg-contoso-reservas-dev"] --> VM["Máquina virtual<br/>vm-motor-disponibilidad-dev"]
    VM --> OSD["Disco de SO gestionado<br/>(persistente)"]
    VM --> TMP["Disco temporal /mnt<br/>(volátil, no se factura aparte)"]
    VM --> DAT["Discos de datos<br/>(opcionales, persistentes)"]
    VM --> NIC["Interfaz de red (NIC)"]
    NIC --> SUBNET["Subred de una red virtual"]
    NIC --> PIP["IP pública<br/>(opcional)"]
    NIC --> NSG["Grupo de seguridad de red<br/>(filtra el tráfico)"]

Los recursos que arrastra una VM:

  • Disco de sistema operativo: disco gestionado, persistente. Sobrevive a la VM si no marcas su borrado.
  • Disco temporal: espacio local del host físico, montado normalmente en /mnt (Linux) o D: (Windows). Su contenido se pierde si la VM se desasigna o se mueve de host. Sirve para archivos de intercambio y ficheros de trabajo desechables. Nunca para datos.
  • Discos de datos: opcionales, persistentes, se conectan y desconectan en caliente.
  • NIC: la tarjeta de red virtual. Vive dentro de una subred de una red virtual.
  • IP pública: opcional. Si es estática, se factura aunque la VM esté apagada.
  • NSG: el cortafuegos de nivel de red. Puede asociarse a la NIC o a la subred (lección 02-05).

La regla mental útil: la VM es el cómputo; todo lo demás sobrevive a la VM. Por eso el módulo 1 terminaba con esa consulta de discos huérfanos e IP públicas sin asociar.

  1. Familias y tamaños de VM: cómo leer la nomenclatura

Azure ofrece cientos de tamaños agrupados en familias, cada una optimizada para un perfil de carga.

Familia Perfil Cuándo usarla Ejemplo típico en Contoso
B (ráfagas) Acumula créditos de CPU cuando está ociosa y los gasta en picos Entornos de desarrollo, servidores poco cargados con picos cortos La VM de pruebas del motor de disponibilidad
D (uso general) Equilibrio CPU/memoria (≈4 GB por vCPU) Servidores de aplicación, web, cargas normales El motor de disponibilidad en producción
E (memoria) ≈8 GB por vCPU Bases de datos, cachés, análisis en memoria Un servidor de informes heredado
F (cómputo) ≈2 GB por vCPU, CPU más rápida Cálculo intensivo, procesamiento por lotes Cálculo nocturno de tarifas
L (almacenamiento) Discos NVMe locales muy rápidos Bases NoSQL, almacenes de datos grandes No aplica hoy
N (GPU) Aceleración gráfica o de IA Entrenamiento de modelos, render No aplica hoy
M (memoria masiva) Cientos de GB o TB de RAM SAP HANA, bases enormes No aplica hoy

Leer un nombre de tamaño

Un nombre como Standard_D4ds_v5 se descompone así:

Standard_D 4 d s _v5
          │ │ │ │  │
          │ │ │ │  └── versión de la generación (v5, v6…)
          │ │ │ └───── s = admite almacenamiento premium (Premium SSD)
          │ │ └─────── d = incluye disco temporal local
          │ └───────── número de vCPU (4)
          └─────────── familia (D = uso general)

Otros sufijos que aparecen a menudo:

Sufijo Significado
a Procesador AMD
p Procesador Arm (Ampere); más barato, pero requiere binarios Arm
s Compatible con almacenamiento premium
d Con disco temporal local
i Instancia aislada (host físico dedicado)
m Variante con más memoria dentro de la familia

Ejemplos concretos para orientarte:

  • Standard_B1s: 1 vCPU, 1 GB de RAM. Ideal para probar y para laboratorios como el de esta lección.
  • Standard_B2ms: 2 vCPU, 8 GB. Un entorno de desarrollo decente.
  • Standard_D4ds_v5: 4 vCPU, 16 GB. Un servidor de aplicación de producción modesto.
  • Standard_E8ds_v5: 8 vCPU, 64 GB. Una base de datos en VM.

Para ver qué hay disponible en tu región y con qué precio orientativo, la CLI te ayuda:

# Tamaños disponibles en West Europe, filtrando la serie B y mostrando
# solo lo que importa para decidir: nombre, vCPU y memoria.
az vm list-sizes \
  --location westeurope \
  --query "[?starts_with(name, 'Standard_B')].{Tamaño:name, vCPU:numberOfCores, MemoriaMB:memoryInMb}" \
  --output table

az vm list-sizes devuelve el catálogo de la región; el --query con JMESPath que aprendiste en 01-06 filtra por prefijo y renombra las columnas. Ojo: no todos los tamaños están disponibles en todas las regiones ni en todas las suscripciones (hay cuotas, como viste en 01-05).

Consejo de dimensionamiento: empieza pequeño. Cambiar el tamaño de una VM en Azure es una operación de minutos (az vm resize), no un proyecto. Sobredimensionar «por si acaso» es el error de coste número uno de las migraciones, y Azure Advisor te lo recordará en el módulo 8.

  1. Discos: tipos, rendimiento y coste

Los discos de Azure son discos gestionados: tú creas un recurso de disco y Azure se ocupa de las cuentas de almacenamiento, la replicación y la disponibilidad por debajo. Antes existían los discos no gestionados en cuentas propias; hoy no hay razón para usarlos.

Tipo Tecnología Rendimiento Casos de uso Coste relativo
Standard HDD Disco magnético Bajo, latencia variable (ms) Copias, archivos, cargas de acceso esporádico €
Standard SSD SSD Moderado y más consistente Desarrollo, pruebas, servidores web ligeros €€
Premium SSD SSD, IOPS garantizadas Alto, latencia de un dígito en ms Producción, bases de datos, aplicaciones sensibles €€€
Premium SSD v2 SSD, IOPS y rendimiento configurables aparte del tamaño Alto y ajustable con precisión Producción con necesidades finas €€€
Ultra Disk SSD de latencia submilisegundo Muy alto, IOPS y MB/s ajustables en caliente SAP HANA, bases OLTP extremas €€€€

Detalles que conviene tener claros desde el principio:

  • El rendimiento depende del tamaño en Standard y Premium SSD clásicos: un disco P10 (128 GB) da menos IOPS que un P30 (1 TB). Si necesitas más IOPS, a veces la solución es un disco más grande, no uno más caro.
  • Solo los tamaños de VM con s en el nombre admiten Premium SSD.
  • El SLA de instancia única del 99,9 % exige discos Premium SSD (o superiores) en todos los discos de la VM. Con discos Standard no hay SLA de instancia única; para eso hacen falta zonas o conjuntos de disponibilidad, y de eso trata la lección 02-02.
  • El disco temporal no se factura por separado, pero es volátil: se pierde al desasignar la VM o si Azure la mueve de host físico. Trátalo como una carpeta /tmp grande.
  • Los discos se facturan por capacidad aprovisionada, no por espacio usado: un disco de 1 TB con 10 GB escritos cuesta como 1 TB. Y sigue costando aunque la VM esté apagada.

Decisión de Contoso Airlines para el motor de disponibilidad:

  • Desarrollo: Standard_B1s + disco de SO Standard SSD de 30 GB. Suficiente para validar el despliegue.
  • Producción (cuando llegue el momento): Standard_D4ds_v5 + Premium SSD, para tener SLA y latencia predecible.

  1. Imágenes: marketplace, imágenes propias y galerías

Una imagen es la plantilla del disco de sistema operativo desde la que arranca la VM.

  • Imágenes del marketplace: publicadas por Microsoft o por terceros. Incluyen desde sistemas operativos limpios (Ubuntu, Debian, RHEL, Windows Server) hasta appliances con software preinstalado. Algunas llevan coste de licencia adicional por hora además del cómputo: fíjate siempre en el precio antes de desplegar.
  • Imágenes propias (personalizadas): creadas a partir de una VM que ya has configurado. Sirven para el patrón golden image: instalas y endureces una vez, despliegas cien veces iguales.
  • Azure Compute Gallery: el servicio para organizar imágenes propias con versiones, replicarlas a varias regiones y compartirlas entre suscripciones. Es lo que usarás cuando las imágenes dejen de ser una y pasen a ser un catálogo.

Buscar imágenes desde la CLI:

# Alias cómodos que Azure mantiene (UbuntuLTS, Debian11, Win2022Datacenter...).
az vm image list --output table

# Búsqueda real en el marketplace: todas las imágenes de Ubuntu Server 22.04
# publicadas por Canonical y disponibles en West Europe.
az vm image list \
  --publisher Canonical \
  --location westeurope \
  --all \
  --query "[?contains(sku, '22_04')].{Publicador:publisher, Oferta:offer, SKU:sku, Version:version}" \
  --output table

El identificador completo de una imagen tiene el formato Publicador:Oferta:SKU:Versión, por ejemplo Canonical:ubuntu-24_04-lts:server:latest. Usar latest es cómodo para pruebas; en producción fija una versión concreta para que dos despliegues del mismo script produzcan lo mismo.

  1. Crear la VM del motor de disponibilidad con Azure CLI

Vamos al grano. Creamos la VM de desarrollo del motor de disponibilidad, con autenticación solo por clave SSH (nunca contraseña), tamaño económico y las etiquetas obligatorias de Contoso.

Paso 1: generar el par de claves SSH

# Genera un par de claves ed25519 (más corto y moderno que RSA).
# -C añade un comentario que ayuda a identificar la clave luego.
ssh-keygen -t ed25519 -f ~/.ssh/contoso_motor -C "[email protected]"

Esto crea dos ficheros: ~/.ssh/contoso_motor (clave privada, no sale nunca de tu equipo) y ~/.ssh/contoso_motor.pub (clave pública, la que subimos a Azure). Si el comando pide una frase de paso, ponla: protege la clave si te roban el portátil.

Paso 2: crear la máquina virtual

#!/usr/bin/env bash
set -euo pipefail

# ---- Parámetros (misma nomenclatura que el módulo 1) ----
GRUPO="rg-contoso-reservas-dev"
REGION="westeurope"
VM="vm-motor-disponibilidad-dev"
IMAGEN="Canonical:ubuntu-24_04-lts:server:latest"
TAMANO="Standard_B1s"

# ---- Creación de la VM ----
az vm create \
  --resource-group "${GRUPO}" \
  --name "${VM}" \
  --image "${IMAGEN}" \
  --size "${TAMANO}" \
  --admin-username azureuser \
  --ssh-key-values ~/.ssh/contoso_motor.pub \
  --public-ip-sku Standard \
  --public-ip-address-allocation static \
  --os-disk-name "disco-so-${VM}" \
  --os-disk-size-gb 30 \
  --storage-sku StandardSSD_LRS \
  --nsg-rule SSH \
  --tags entorno=desarrollo \
         proyecto=contoso-reservas \
         centro-coste=CC-1042 \
         [email protected] \
         criticidad=baja \
  --output table

Qué hace cada opción, una por una:

Opción Efecto
--image Imagen de partida, en formato Publicador:Oferta:SKU:Versión
--size Tamaño de VM (familia B, 1 vCPU, 1 GB)
--admin-username Usuario administrador que se crea en el sistema
--ssh-key-values Clave pública que se instala en ~/.ssh/authorized_keys. Al indicarla, Azure deshabilita el acceso por contraseña
--public-ip-sku Standard SKU Standard: cerrada por defecto, compatible con zonas. La SKU Basic está retirada
--public-ip-address-allocation static La IP no cambia al reiniciar. Recuerda: se factura aunque la VM esté apagada
--os-disk-name Nombre explícito del disco, para no acabar con nombres aleatorios
--storage-sku StandardSSD_LRS Tipo de disco del sistema operativo
--nsg-rule SSH Crea un NSG con una regla de entrada para el puerto 22
--tags Las etiquetas obligatorias del esquema de Contoso, en minúsculas y sin acentos

Si no indicas red virtual, az vm create crea una con un nombre derivado (vm-motor-disponibilidad-devVNET) y una subred por defecto. Para el laboratorio vale; en producción no. En la lección 02-05 diseñaremos vnet-contoso-pro con sus subredes y conectaremos ahí las VM con --vnet-name y --subnet.

Advertencia de seguridad: --nsg-rule SSH abre el puerto 22 a todo internet (0.0.0.0/0). Es aceptable durante diez minutos en un laboratorio; no lo es en producción. En 02-05 verás cómo restringirlo por IP de origen y, mejor aún, cómo usar Azure Bastion para no exponer SSH en absoluto.

La salida incluye la IP pública asignada. También puedes recuperarla en cualquier momento:

IP=$(az vm show \
  --resource-group rg-contoso-reservas-dev \
  --name vm-motor-disponibilidad-dev \
  --show-details \
  --query publicIps \
  --output tsv)
echo "IP pública: ${IP}"

--show-details (o -d) es el que hace que az vm show incluya datos de red; sin él, la consulta devuelve vacío. Es una de esas rarezas de la CLI que conviene memorizar.

  1. Conectarse por SSH e instalar el servicio

# Conexión con la clave privada correspondiente.
ssh -i ~/.ssh/contoso_motor azureuser@"${IP}"

Ya dentro de la VM, simulamos el despliegue del motor de disponibilidad. El motor real es Java, así que instalamos el entorno de ejecución y un servicio HTTP mínimo que responda como lo haría el motor:

# --- Dentro de la VM ---
sudo apt-get update
sudo apt-get install -y openjdk-21-jre-headless nginx

# Página de salud que imita la respuesta del motor heredado.
echo '{"servicio":"motor-disponibilidad","estado":"ok","version":"legado-3.4"}' \
  | sudo tee /var/www/html/salud.json

sudo systemctl enable --now nginx
curl -s http://localhost/salud.json

Desde tu equipo, comprueba que responde por internet. Antes hay que abrir el puerto 80 en el NSG, porque solo abrimos el 22:

# Regla de entrada para HTTP en el NSG que creó az vm create.
az network nsg rule create \
  --resource-group rg-contoso-reservas-dev \
  --nsg-name "vm-motor-disponibilidad-devNSG" \
  --name permitir-http \
  --priority 320 \
  --protocol Tcp \
  --destination-port-ranges 80 \
  --access Allow \
  --direction Inbound \
  --output none

curl -s "http://${IP}/salud.json"

La prioridad (320) determina el orden de evaluación: número más bajo, se evalúa antes. En 02-05 verás las reglas por defecto y las etiquetas de servicio con detalle.

  1. Configuración inicial automática: cloud-init y extensiones

Instalar a mano funciona una vez. Para hacerlo cien veces iguales hay dos mecanismos.

cloud-init (Linux)

cloud-init es el estándar de la industria para configurar una máquina Linux en su primer arranque. Se pasa un fichero YAML y Azure lo inyecta.

#cloud-config
package_update: true
packages:
  - openjdk-21-jre-headless
  - nginx
write_files:
  - path: /var/www/html/salud.json
    content: '{"servicio":"motor-disponibilidad","estado":"ok","version":"legado-3.4"}'
    permissions: '0644'
runcmd:
  - systemctl enable --now nginx

Guárdalo como init-motor.yaml y úsalo al crear la VM:

az vm create \
  --resource-group rg-contoso-reservas-dev \
  --name vm-motor-disponibilidad-dev \
  --image Canonical:ubuntu-24_04-lts:server:latest \
  --size Standard_B1s \
  --admin-username azureuser \
  --ssh-key-values ~/.ssh/contoso_motor.pub \
  --custom-data init-motor.yaml \
  --output none

Bloque a bloque: package_update refresca el índice de paquetes; packages instala; write_files crea ficheros con permisos concretos; runcmd ejecuta órdenes al final. La primera línea #cloud-config es obligatoria y debe ser exactamente esa: sin ella, cloud-init ignora el fichero. Puedes verificar el resultado dentro de la VM con cloud-init status --wait y revisar /var/log/cloud-init-output.log cuando algo no salga.

Extensiones de VM

Las extensiones son agentes pequeños que Azure instala y ejecuta dentro de la VM después del arranque, a través del agente de Azure. A diferencia de cloud-init, se pueden aplicar a una VM ya existente y se gestionan desde el plano de control.

Extensión Para qué sirve
customScript Ejecuta un script arbitrario (el comodín)
AzureMonitorLinuxAgent Envía métricas y registros a Log Analytics (módulo 7)
AADSSHLoginForLinux Inicio de sesión SSH con identidad de Microsoft Entra ID (módulo 4)
NetworkWatcherAgentLinux Diagnósticos de red (lección 02-05)
# Ejecutar un script de configuración en una VM ya creada.
az vm extension set \
  --resource-group rg-contoso-reservas-dev \
  --vm-name vm-motor-disponibilidad-dev \
  --name customScript \
  --publisher Microsoft.Azure.Extensions \
  --version 2.1 \
  --settings '{"commandToExecute":"echo motor-disponibilidad-desplegado > /var/www/html/estado.txt"}' \
  --output none

Criterio práctico: cloud-init para la configuración base inmutable del primer arranque; extensiones para agentes de plataforma y para actuar sobre máquinas ya desplegadas. Si acabas escribiendo scripts largos en cualquiera de los dos, la respuesta real es una imagen propia o un contenedor.

  1. Estados de una VM y qué se factura en cada uno

Este apartado es el que más dinero ahorra de toda la lección.

Estado Comando ¿Se factura el cómputo? ¿Se factura el disco? Notas
En ejecución az vm start Sí Sí Estado normal
Detenida (parada desde dentro del SO) sudo shutdown -h now Sí Sí El hardware sigue reservado
Detenida (desasignada) az vm deallocate No Sí Libera el host; se pierde el disco temporal
Eliminada az vm delete No Depende Los discos y la IP pueden sobrevivir

Léelo otra vez: apagar la VM desde dentro del sistema operativo NO deja de facturar el cómputo. Azure mantiene los recursos del host reservados para ti. Solo la desasignación libera el hardware y detiene el cargo por cómputo.

# Detener y desasignar: esto sí para el reloj del cómputo.
az vm deallocate \
  --resource-group rg-contoso-reservas-dev \
  --name vm-motor-disponibilidad-dev

# Comprobar el estado real de la VM.
az vm get-instance-view \
  --resource-group rg-contoso-reservas-dev \
  --name vm-motor-disponibilidad-dev \
  --query "instanceView.statuses[?starts_with(code,'PowerState')].displayStatus" \
  --output tsv

Consecuencias de desasignar que debes conocer:

  • Se pierde el contenido del disco temporal (/mnt).
  • Si la IP pública es dinámica, se libera y al arrancar recibirás otra. Con estática la conservas, pero la pagas mientras exista.
  • La IP privada dinámica también puede cambiar al reasignar.

Contoso aplica esto de forma sistemática: las VM de rg-contoso-reservas-dev se desasignan cada noche y los fines de semana. En el módulo 7 automatizarás ese apagado con Azure Automation, y en el módulo 8 verás cuánto representa en la factura (típicamente, más de la mitad del gasto de los entornos que no son producción).

  1. Instantáneas e imágenes: copias y clones

Dos mecanismos que se confunden a menudo:

Mecanismo Qué es Uso típico
Instantánea (snapshot) Copia puntual de un disco concreto Punto de retorno antes de un cambio arriesgado
Imagen Plantilla de una VM completa (SO + discos de datos), normalmente generalizada Crear muchas VM idénticas
# 1. Instantánea del disco de sistema operativo antes de actualizar el motor.
DISCO_ID=$(az vm show \
  --resource-group rg-contoso-reservas-dev \
  --name vm-motor-disponibilidad-dev \
  --query "storageProfile.osDisk.managedDisk.id" \
  --output tsv)

az snapshot create \
  --resource-group rg-contoso-reservas-dev \
  --name "snap-motor-$(date +%Y%m%d)" \
  --source "${DISCO_ID}" \
  --tags entorno=desarrollo proyecto=contoso-reservas centro-coste=CC-1042 \
  --output table

Primero obtenemos el ID de recurso del disco (esa cadena /subscriptions/.../disks/... que viste en 01-05) y después creamos la instantánea a partir de él. Una instantánea ocupa y se factura; bórrala cuando ya no la necesites.

Para una imagen generalizada de Linux, el proceso completo es: sudo waagent -deprovision+user dentro de la VM, luego az vm deallocate, az vm generalize y az image create. Una VM generalizada ya no se puede volver a usar: solo sirve como origen de imagen. No lo hagas con la máquina que necesitas mañana.

Para copias de seguridad de verdad (con política, retención y recuperación granular) no se usan instantáneas manuales, sino Azure Backup, que verás en la lección 07-05.

  1. Limpieza al terminar

# Opción A: borrar solo la VM y sus recursos asociados (--yes evita la confirmación).
az vm delete \
  --resource-group rg-contoso-reservas-dev \
  --name vm-motor-disponibilidad-dev \
  --yes

# Comprobación imprescindible: ¿quedaron discos o IP huérfanos?
az disk list --resource-group rg-contoso-reservas-dev --output table
az network public-ip list --resource-group rg-contoso-reservas-dev --output table
az network nic list --resource-group rg-contoso-reservas-dev --output table

# Opción B (laboratorio): borrar el grupo entero. Irreversible.
# az group delete --name rg-contoso-reservas-dev --yes --no-wait

az vm delete no borra por defecto el disco de SO, la NIC ni la IP pública. Al crear la VM puedes pedir que se borren con ella:

az vm create ... \
  --os-disk-delete-option Delete \
  --nic-delete-option Delete \
  --data-disk-delete-option Delete

Recuerda que el grupo rg-contoso-reservas-pro tiene el bloqueo no-borrar-produccion (CanNotDelete) que pusiste en 01-05: cualquier intento de borrado ahí fallará hasta que lo retires. Es exactamente lo que queremos.

Errores Comunes y Consejos

  • Creer que apagar la VM deja de facturar. Solo az vm deallocate detiene el cargo por cómputo. Apagar desde el sistema operativo no.
  • Borrar la VM y dejar discos e IP huérfanos. Se facturan por existir. Revisa siempre después de borrar, o usa las opciones --*-delete-option Delete.
  • Guardar datos en el disco temporal. /mnt se vacía al desasignar o al migrar de host. Ahí solo va lo desechable.
  • Sobredimensionar la VM «por si acaso». Redimensionar es un az vm resize de dos minutos con un reinicio. Empieza pequeño.
  • Abrir SSH o RDP a todo internet. El puerto 22 abierto recibe intentos de acceso automatizados en minutos. Restringe por IP de origen o usa Azure Bastion (02-05).
  • Usar contraseñas en lugar de claves SSH. Con --ssh-key-values Azure deshabilita el acceso por contraseña. No hay ninguna razón para lo contrario.
  • Usar latest en la versión de imagen en producción. Dos despliegues idénticos pueden dar máquinas distintas. Fija la versión.
  • Olvidar --show-details en az vm show. Sin él no verás las IP y creerás que la VM no tiene red.
  • Consejo de nomenclatura: nombra explícitamente disco, NIC e IP (disco-so-…, nic-…, ip-…). Los nombres automáticos con sufijos aleatorios convierten la limpieza en arqueología.
  • Consejo de licencias: si migras Windows Server o SQL Server con Software Assurance, mira Azure Hybrid Benefit (lección 08-03) antes de desplegar; el ahorro puede superar el 40 %.

Ejercicios

Ejercicio 1: elegir tamaño y disco con criterio

Para cada caso de Contoso Airlines, propón familia, tamaño aproximado y tipo de disco de SO, y justifica la elección:

  1. VM de pruebas donde Diego Salas valida cada versión del motor de disponibilidad; se usa dos horas al día.
  2. Motor de disponibilidad en producción durante la temporada alta: 4 vCPU y 16 GB estimados, latencia importante, requiere SLA de instancia única.
  3. Proceso nocturno que recalcula tarifas: dos horas de CPU al 100 %, poca memoria, sin persistencia relevante.
  4. Servidor de informes heredado que carga en memoria un cubo de 48 GB.

Ejercicio 2: desplegar el motor con cloud-init y verificar el ahorro

  1. Escribe un init-motor.yaml que instale nginx, cree /var/www/html/salud.json con {"servicio":"motor-disponibilidad","estado":"ok"} y arranque el servicio.
  2. Crea vm-motor-disponibilidad-dev en rg-contoso-reservas-dev con Standard_B1s, disco Standard SSD de 30 GB, clave SSH y las cuatro etiquetas obligatorias.
  3. Abre el puerto 80 en el NSG y comprueba la respuesta desde tu equipo.
  4. Desasigna la VM y demuestra con un comando que su estado es deallocated.

Ejercicio 3: auditoría de gasto oculto

Escribe los comandos de Azure CLI que respondan a estas preguntas en la suscripción de desarrollo:

  1. ¿Qué VM hay y en qué estado de energía está cada una?
  2. ¿Hay discos sin conectar a ninguna VM y cuántos GB suman?
  3. ¿Hay IP públicas sin asociar?
  4. ¿Qué VM no tienen la etiqueta propietario?

Soluciones

Solución 1:

Caso Propuesta Justificación
1. Pruebas dos horas al día Standard_B2s + Standard SSD La serie B acumula créditos mientras está ociosa; con desasignación nocturna el coste es mínimo. No necesita SLA
2. Producción del motor Standard_D4ds_v5 + Premium SSD Uso general equilibrado 4 vCPU/16 GB; el SLA de instancia única del 99,9 % exige discos Premium en todos los discos
3. Recálculo nocturno Standard_F4s_v2 + Standard SSD Familia de cómputo: más CPU por euro y poca memoria necesaria. Desasignar al terminar
4. Informes con cubo de 48 GB Standard_E8ds_v5 (8 vCPU / 64 GB) + Premium SSD Familia de memoria: ≈8 GB por vCPU, con margen sobre los 48 GB del cubo

Solución 2:

#cloud-config
package_update: true
packages:
  - nginx
write_files:
  - path: /var/www/html/salud.json
    content: '{"servicio":"motor-disponibilidad","estado":"ok"}'
    permissions: '0644'
runcmd:
  - systemctl enable --now nginx
#!/usr/bin/env bash
set -euo pipefail

GRUPO="rg-contoso-reservas-dev"
VM="vm-motor-disponibilidad-dev"

# 2. Creación de la VM con cloud-init y etiquetas obligatorias.
az vm create \
  --resource-group "${GRUPO}" \
  --name "${VM}" \
  --image Canonical:ubuntu-24_04-lts:server:latest \
  --size Standard_B1s \
  --admin-username azureuser \
  --ssh-key-values ~/.ssh/contoso_motor.pub \
  --custom-data init-motor.yaml \
  --os-disk-name "disco-so-${VM}" \
  --os-disk-size-gb 30 \
  --storage-sku StandardSSD_LRS \
  --nsg-rule SSH \
  --tags entorno=desarrollo proyecto=contoso-reservas \
         centro-coste=CC-1042 [email protected] \
  --output none

# 3. Abrir HTTP y probar.
az network nsg rule create \
  --resource-group "${GRUPO}" \
  --nsg-name "${VM}NSG" \
  --name permitir-http --priority 320 \
  --protocol Tcp --destination-port-ranges 80 \
  --access Allow --direction Inbound --output none

IP=$(az vm show -g "${GRUPO}" -n "${VM}" --show-details --query publicIps -o tsv)
curl -s "http://${IP}/salud.json"

# 4. Desasignar y comprobar el estado.
az vm deallocate --resource-group "${GRUPO}" --name "${VM}"
az vm get-instance-view -g "${GRUPO}" -n "${VM}" \
  --query "instanceView.statuses[?starts_with(code,'PowerState')].code" -o tsv
# Salida esperada: PowerState/deallocated

Solución 3:

# 1. VM y su estado de energía (--show-details incluye powerState).
az vm list --show-details \
  --query "[].{VM:name, Grupo:resourceGroup, Estado:powerState, Tamaño:hardwareProfile.vmSize}" \
  --output table

# 2. Discos sin conectar y su tamaño.
az disk list \
  --query "[?diskState=='Unattached'].{Disco:name, GB:diskSizeGb, Grupo:resourceGroup}" \
  --output table

# 3. IP públicas sin asociar a ninguna configuración de red.
az network public-ip list \
  --query "[?ipConfiguration==null].{IP:name, Direccion:ipAddress, Grupo:resourceGroup}" \
  --output table

# 4. VM sin etiqueta propietario.
az vm list \
  --query "[?tags.propietario == \`null\`].{VM:name, Grupo:resourceGroup}" \
  --output table

Los puntos 2 y 3 son la fuente más habitual de gasto invisible: se facturan por existir, no por usarse.

Conclusión

Ya sabes desplegar cómputo IaaS en Azure con criterio. Has visto cuándo una VM es la respuesta correcta —el motor de disponibilidad heredado de Contoso, que no puede reescribirse todavía— y cuándo es simplemente el camino cómodo y caro. Conoces la anatomía completa de una VM y los recursos que arrastra: disco de SO, disco temporal volátil, discos de datos, NIC, IP pública y NSG, cada uno con su ciclo de vida propio. Sabes leer la nomenclatura de tamaños (Standard_D4ds_v5) y elegir familia según el perfil de carga, y comparar tipos de disco entendiendo que el SLA de instancia única exige Premium SSD. Has creado una VM Linux con claves SSH, la has configurado con cloud-init y extensiones, y —lo más rentable de la lección— has interiorizado la diferencia entre detenida y detenida (desasignada), junto con la limpieza que evita discos e IP huérfanos.

Pero esta VM tiene un problema de fondo que ningún tamaño arregla: es una sola máquina. Si el host falla, si hay mantenimiento de plataforma o si en abril se abre la venta de la temporada de verano y llegan diez veces más peticiones de las habituales, no hay red de seguridad. Una instancia única no tiene SLA salvo con discos Premium, y aun así sigue siendo un único punto de fallo.

En la siguiente lección, Escalado y alta disponibilidad del cómputo, resolvemos exactamente eso: escalado vertical frente a horizontal y por qué la nube apuesta por el segundo, conjuntos de escalado de máquinas virtuales con reglas automáticas por métrica y programadas para el pico de venta de Contoso, zonas y conjuntos de disponibilidad con sus dominios de error y actualización, y las cuatro opciones de balanceo de carga de Azure comparadas. Al terminar tendrás la API de Disponibilidad sirviendo detrás de un balanceador con dos instancias en zonas distintas.

Curso de Azure

Módulo 1: Introducción a Azure

Módulo 2: Servicios principales de Azure

Módulo 3: Bases de datos de Azure

Módulo 4: Seguridad en Azure

Módulo 5: Azure DevOps

Módulo 6: Servicios avanzados de Azure

Módulo 7: Monitoreo y gestión

Módulo 8: Gestión y optimización de costos

Módulo 9: Estudios de caso y mejores prácticas

© Copyright 2026. Todos los derechos reservados