Cierras el módulo con la herramienta que más tiempo te va a ahorrar durante el resto del curso y del resto de tu carrera en Azure: la línea de comandos. En la lección anterior quedó claro que portal, CLI, PowerShell y plantillas hablan todos con la misma API de Azure Resource Manager. Lo que cambia es la velocidad, la precisión y —sobre todo— la capacidad de repetir exactamente lo mismo mañana.
Aquí aprenderás a instalar y usar Azure CLI, a consultar sus salidas con --query, a manejar varias suscripciones sin equivocarte de entorno, cuándo tiene más sentido Azure PowerShell, cómo funciona Cloud Shell (y por qué te crea una cuenta de almacenamiento). Y terminarás escribiendo un script completo, comentado, parametrizado e idempotente que despliega la base de la plataforma de Contoso Airlines y sabe borrarla después para no gastar de más.
Contenido
- Por qué automatizar desde la línea de comandos
- Instalar Azure CLI y comprobar la versión
- Iniciar sesión y trabajar con varias suscripciones
- Anatomía de un comando
azy ayuda integrada - Formatos de salida y consultas con
--query - Azure PowerShell y cuándo elegir cada herramienta
- Cloud Shell
- Script completo: la base de Contoso Airlines
- Limpieza: borrar sin dejar rastro de gasto
- Errores Comunes y Consejos
- Ejercicios
- Conclusión
- Por qué automatizar desde la línea de comandos
El portal es excelente para explorar. Para trabajar, tiene tres problemas:
| Problema del portal | Qué aporta la línea de comandos |
|---|---|
| No es repetible: 40 clics hoy, 40 clics distintos mañana | Un script produce el mismo resultado siempre |
| No es auditable: nadie sabe qué opciones marcaste | El script vive en Git, se revisa y se compara |
| No escala: crear 20 recursos iguales es una tarde perdida | Un bucle for lo hace en un minuto |
Es lento para consultas: "dame todas las VM sin etiqueta propietario" no tiene botón |
Una consulta --query lo resuelve en una línea |
Además, la CLI es el puente natural hacia lo que viene después: las tuberías de despliegue del módulo 5 ejecutan comandos az, y los diagnósticos del módulo 7 se apoyan en consultas de línea de comandos.
Regla de oro, repetida a propósito: lo que haces una vez, hazlo en el portal; lo que harás dos veces, escríbelo.
- Instalar Azure CLI y comprobar la versión
Azure CLI es multiplataforma y está escrita en Python, pero se instala como un paquete nativo en cada sistema.
Windows
# Opción recomendada: gestor de paquetes de Windows.
winget install --exact --id Microsoft.AzureCLI
# Alternativa con MSI silencioso, útil en despliegues corporativos.
# Descarga el instalador oficial y ejecútalo con /quiet.Tras instalar, cierra y vuelve a abrir la terminal para que se actualice la variable PATH.
macOS
Linux (Debian/Ubuntu)
# Script oficial de instalación: añade el repositorio de Microsoft e instala el paquete.
# Revisa siempre un script antes de ejecutarlo con privilegios (buena práctica general).
curl -sL https://aka.ms/InstallAzureCLIDeb | sudo bashPara RHEL, Fedora o CentOS se usa dnf; para openSUSE, zypper. La documentación oficial detalla cada caso.
Comprobar la instalación
Salida de ejemplo:
{
"azure-cli": "2.64.0",
"azure-cli-core": "2.64.0",
"azure-cli-telemetry": "1.1.0",
"extensions": {}
}Mantenerla actualizada
# Actualiza la CLI a la última versión estable (funciona en la mayoría de plataformas).
az upgrade
# Desactiva la pregunta de telemetría y confirmaciones interactivas en scripts.
az config set core.collect_telemetry=falseAzure CLI se actualiza cada pocas semanas. Trabajar con una versión muy antigua provoca errores del tipo "unrecognized arguments" cuando sigues documentación reciente: si un parámetro no existe en tu instalación, lo primero que hay que probar es actualizar.
- Iniciar sesión y trabajar con varias suscripciones
# Abre el navegador para autenticarte de forma interactiva.
# Tras iniciar sesión, la CLI guarda un token local y ya no lo pide en cada comando.
az loginVariantes útiles:
# Sin navegador (servidores, SSH): muestra un código para introducir en microsoft.com/devicelogin.
az login --use-device-code
# Especificar el inquilino cuando tu identidad pertenece a varios directorios.
az login --tenant contoso-airlines.onmicrosoft.comPara automatización desatendida (tuberías de CI/CD) no se usa
az logininteractivo, sino una entidad de servicio o una identidad administrada. Se ven en las lecciones 04-02 y 05-03. Nunca metas credenciales de usuario en un script.
Varias suscripciones: el error más caro de todos
Si tu identidad tiene acceso a Contoso Airlines - Producción y a Contoso Airlines - Desarrollo, cada comando az se ejecuta contra la suscripción activa. Confundirse aquí es cómo se borran cosas en producción.
Name CloudName SubscriptionId State IsDefault -------------------------------- ----------- ------------------------------------ ------- --------- Contoso Airlines - Producción AzureCloud 8f4c2b7a-1d3e-4a55-9c11-0a7b6e2d4f90 Enabled True Contoso Airlines - Desarrollo AzureCloud 3b91e5d0-7c42-4f88-a2e6-5d9c1a8b3e77 Enabled False
# Cambiar la suscripción activa (acepta nombre o identificador).
az account set --subscription "Contoso Airlines - Desarrollo"
# Confirmar dónde estás antes de tocar nada. Hazlo un hábito.
az account show --query "{Suscripcion:name, Id:id, Usuario:user.name}" --output tableDos defensas prácticas:
- Empieza todos tus scripts fijando la suscripción explícitamente con
az account set. No confíes en la que esté activa. - Usa el parámetro
--subscriptionen los comandos críticos, para no depender del estado global:
az group delete --name rg-contoso-reservas-dev \
--subscription "Contoso Airlines - Desarrollo" --yes
- Anatomía de un comando
az y ayuda integrada
az y ayuda integradaTodos los comandos de Azure CLI siguen la misma estructura:
Ejemplo desglosado:
az storage account create --name sttarjetascontosodev --resource-group rg-contoso-reservas-dev --location westeurope --sku Standard_LRS| Parte | Valor | Qué es |
|---|---|---|
az |
— | El programa |
storage |
grupo | La familia de servicio |
account |
subgrupo | El objeto concreto dentro de esa familia |
create |
comando | La acción (create, list, show, update, delete) |
--name, --resource-group... |
parámetros | Los datos de la operación |
Los verbos se repiten en toda la CLI, y eso hace que sea predecible: si sabes az vm list, intuyes az storage account list, az webapp list y az sql db list.
Abreviaturas frecuentes: -n para --name, -g para --resource-group, -l para --location, -o para --output.
Ayuda integrada
# Ayuda de un grupo: muestra subgrupos y comandos disponibles.
az storage --help
# Ayuda de un comando concreto: lista TODOS sus parámetros, cuáles son obligatorios y ejemplos.
az storage account create --help
# Búsqueda inteligente por lenguaje natural, con ejemplos reales de uso.
az find "az storage account"
az find "crear una cuenta de almacenamiento"Y el modo interactivo, muy útil mientras aprendes (requiere instalar la extensión):
- Formatos de salida y consultas con
--query
--queryPor defecto, la CLI devuelve JSON, que es completo pero incómodo de leer. El parámetro --output (o -o) cambia el formato:
| Valor | Resultado | Cuándo usarlo |
|---|---|---|
json (por defecto) |
JSON con formato | Ver todos los campos disponibles |
jsonc |
JSON coloreado | Lectura en terminal |
table |
Tabla legible | Uso diario e informes rápidos |
tsv |
Valores separados por tabuladores, sin cabeceras ni comillas | Scripts: alimentar variables |
yaml |
YAML | Configuraciones legibles |
none |
Nada | Cuando solo importa que la operación funcione |
JMESPath: el lenguaje de --query
--query usa JMESPath, un lenguaje de consulta sobre JSON. Vamos con ejemplos progresivos sobre los recursos de Contoso.
Paso 1 — seleccionar una propiedad de un objeto:
# Devuelve solo la ubicación de un grupo de recursos, sin comillas (tsv), lista para una variable.
az group show --name rg-contoso-reservas-dev --query location --output tsvPaso 2 — recorrer una lista y quedarse con un campo:
# Nombres de todos los grupos de recursos. [] recorre la lista.
az group list --query "[].name" --output tsvPaso 3 — construir un objeto con nombres propios:
# Renombra los campos de salida. Las claves de la izquierda son etiquetas tuyas.
az group list \
--query "[].{Nombre:name, Region:location, Estado:properties.provisioningState}" \
--output tableNombre Region Estado ------------------------- ---------- --------- rg-contoso-reservas-dev westeurope Succeeded rg-contoso-reservas-pro westeurope Succeeded
Paso 4 — filtrar con condiciones (?):
# Solo los grupos etiquetados como producción.
az group list \
--query "[?tags.entorno=='produccion'].{Nombre:name, Propietario:tags.propietario}" \
--output table
# Solo las cuentas de almacenamiento de West Europe.
az storage account list \
--query "[?location=='westeurope'].{Cuenta:name, Grupo:resourceGroup, Sku:sku.name}" \
--output tablePaso 5 — detectar lo que falta (auditoría de gobierno):
# Recursos SIN la etiqueta obligatoria "propietario": el informe que pide Marta Ríos.
# == `null` compara con nulo; los acentos graves marcan un literal JSON.
az resource list \
--query "[?tags.propietario == \`null\`].{Recurso:name, Tipo:type, Grupo:resourceGroup}" \
--output tablePaso 6 — combinar con funciones y ordenación:
# Contar cuántos recursos hay en total.
az resource list --query "length(@)" --output tsv
# Los recursos ordenados por nombre, mostrando solo tipo y grupo.
az resource list \
--query "sort_by([].{Nombre:name, Tipo:type, Grupo:resourceGroup}, &Nombre)" \
--output tablePaso 7 — usar el resultado en un script:
# Guardar un valor en una variable de shell. --output tsv evita las comillas del JSON.
CLAVE_REGION=$(az group show --name rg-contoso-reservas-dev --query location --output tsv)
echo "El grupo está en: $CLAVE_REGION"Truco de aprendizaje: ejecuta primero el comando sin
--queryy con--output jsonpara ver la estructura completa, y solo entonces escribe la consulta. Es mucho más rápido que adivinar los nombres de los campos.
- Azure PowerShell y cuándo elegir cada herramienta
Azure PowerShell es el otro cliente oficial, basado en el módulo Az. Hace lo mismo que la CLI, pero con la filosofía de PowerShell: en lugar de texto, devuelve objetos con propiedades sobre los que puedes operar directamente.
Instalación y primeros comandos
# Instala el módulo Az para el usuario actual (no requiere permisos de administrador).
Install-Module -Name Az -Scope CurrentUser -Repository PSGallery -Force
# Inicia sesión (abre el navegador).
Connect-AzAccount
# Ver las suscripciones disponibles y seleccionar una.
Get-AzSubscription
Set-AzContext -Subscription "Contoso Airlines - Desarrollo"
# Crear el grupo de recursos de Contoso con sus etiquetas.
New-AzResourceGroup -Name "rg-contoso-reservas-dev" -Location "westeurope" -Tag @{
entorno = "desarrollo"
proyecto = "contoso-reservas"
"centro-coste" = "CC-1042"
propietario = "[email protected]"
}
# Listar recursos y filtrar por etiqueta, aprovechando los objetos de PowerShell.
Get-AzResource -TagName "proyecto" -TagValue "contoso-reservas" |
Select-Object Name, ResourceType, ResourceGroupName |
Format-TableFíjate en la diferencia de filosofía: en la CLI filtras con --query (JMESPath sobre JSON); en PowerShell filtras con Where-Object y seleccionas con Select-Object, porque ya tienes objetos.
Comparativa
| Aspecto | Azure CLI (az) |
Azure PowerShell (Az) |
|---|---|---|
| Sintaxis | az grupo subgrupo comando |
Verbo-AzSustantivo (New-AzResourceGroup) |
| Salida | JSON (texto) | Objetos de .NET |
| Filtrado | --query con JMESPath |
Where-Object, Select-Object |
| Shell nativo | Bash, Zsh; funciona en cualquier shell | PowerShell (Windows, Linux y macOS) |
| Curva de entrada | Más suave si vienes de Linux | Más suave si vienes de Windows |
| Integración | Excelente en tuberías multiplataforma y contenedores | Excelente con Windows Server, Microsoft 365 y Exchange |
| Documentación de Microsoft | Ejemplos en ambas | Ejemplos en ambas |
Cómo elegir, sin dogmatismos:
- Si tu equipo es de administradores de sistemas Windows y ya automatiza con PowerShell, usa PowerShell.
- Si tu equipo viene de Linux, Docker o desarrollo multiplataforma, usa la CLI.
- Si escribes scripts para tuberías de CI/CD en contenedores Linux, la CLI suele ser más ligera y directa.
- Lo importante es ser coherente dentro de un mismo proyecto. En Contoso, Diego y Marta acuerdan usar Azure CLI, y ese es el criterio del curso a partir de aquí.
- Cloud Shell
Azure Cloud Shell es un terminal alojado en Azure, accesible desde el icono >_ de la barra superior del portal (o en shell.azure.com). Ventajas inmediatas:
- Ya está autenticado con tu identidad: no hay que hacer
az login. - Trae las herramientas instaladas y actualizadas: Azure CLI, Azure PowerShell, Bicep, Terraform, kubectl, Git, Python, Node.js, y editores como
vim,nanoy el editor gráfico integrado (code .). - Funciona desde cualquier navegador, incluido el móvil.
Bash o PowerShell
Puedes elegir el intérprete en el desplegable superior y cambiar en cualquier momento. Los comandos az funcionan en ambos; los Az* de PowerShell, solo en el modo PowerShell.
La cuenta de almacenamiento que crea
La primera vez que abres Cloud Shell, te pide crear (o asociar) una cuenta de almacenamiento. Esto no es un capricho:
- Cloud Shell corre en un contenedor efímero: cuando termina la sesión, el contenedor se destruye.
- Para que tus ficheros sobrevivan, monta un recurso compartido de Azure Files en tu directorio
$HOME, dentro de una imagen de disco llamada normalmenteacc_<usuario>.img. - Lo que guardes en
$HOME(~/clouddrive) persiste entre sesiones; lo que instales fuera de ahí, no.
Aviso de coste: esa cuenta de almacenamiento es un recurso tuyo y se factura, aunque el importe sea muy pequeño (unos céntimos al mes por unos pocos GB). Cloud Shell en sí no cuesta nada; su almacenamiento, sí. Si dejas de usarlo, puedes borrar el grupo de recursos que se crea automáticamente (suele llamarse
cloud-shell-storage-<región>).
Otras características y límites
| Aspecto | Detalle |
|---|---|
| Tiempo de inactividad | La sesión se cierra tras unos 20 minutos sin interacción |
| Persistencia | Solo $HOME / clouddrive; el resto del sistema de ficheros se pierde |
| Carga y descarga de ficheros | Botón de Cargar/Descargar en la barra de Cloud Shell |
| Editor integrado | code . abre un editor gráfico dentro del navegador |
| Sesiones simultáneas | Limitadas; una sesión Bash y una PowerShell a la vez |
| Región del almacenamiento | Se elige al crearlo; conviene ponerlo cerca de ti |
Cuándo usar Cloud Shell: para aprender (no instalas nada), para tareas puntuales desde un equipo ajeno, para emergencias desde el móvil. Cuándo no: para trabajo diario intensivo o scripts largos, donde una CLI local con tu editor y tu repositorio Git es más cómoda.
- Script completo: la base de Contoso Airlines
Ahora el ejercicio central del módulo: un script que crea toda la base de la plataforma de Contoso Airlines. Es parametrizado (todo en variables al principio), idempotente (se puede ejecutar varias veces sin romper nada ni duplicar recursos) y está comentado línea a línea.
Guárdalo como desplegar-base-contoso.sh.
#!/usr/bin/env bash
# =============================================================================
# desplegar-base-contoso.sh
# Crea la base de la plataforma de Contoso Airlines:
# - Grupo de recursos con las etiquetas obligatorias
# - Cuenta de almacenamiento para las tarjetas de embarque en PDF
# - Contenedor privado "tarjetas-embarque"
#
# Es IDEMPOTENTE: ejecutarlo dos veces deja el mismo resultado que ejecutarlo una.
# Uso: ./desplegar-base-contoso.sh [dev|pro]
# =============================================================================
# 'set -e' aborta el script ante el primer error, en lugar de seguir a ciegas.
# 'set -u' aborta si se usa una variable no definida (evita erratas peligrosas).
# 'set -o pipefail' propaga el error de cualquier comando dentro de una tubería.
set -euo pipefail
# ------------------------------------------------------------------
# 1. PARÁMETROS. Todo lo configurable, en un solo sitio y arriba.
# ------------------------------------------------------------------
ENTORNO="${1:-dev}" # Primer argumento; "dev" si no se indica
SUSCRIPCION="Contoso Airlines - Desarrollo"
REGION="westeurope" # Región principal decidida en la lección 01-02
PROYECTO="contoso-reservas"
CENTRO_COSTE="CC-1042"
PROPIETARIO="[email protected]"
# Nombres derivados, siguiendo la convención de nomenclatura de Contoso.
GRUPO="rg-${PROYECTO}-${ENTORNO}" # p. ej. rg-contoso-reservas-dev
# Las cuentas de almacenamiento solo admiten minúsculas y números (3-24 caracteres)
# y su nombre es ÚNICO EN TODO AZURE: añadimos un sufijo aleatorio estable por si acaso.
SUFIJO="$(echo -n "${GRUPO}" | cksum | cut -c1-4)"
CUENTA_ALM="sttarjetascontoso${ENTORNO}${SUFIJO}"
CONTENEDOR="tarjetas-embarque"
# Traducción del entorno corto al valor de etiqueta que exige el esquema de Contoso.
if [ "${ENTORNO}" = "pro" ]; then
ENTORNO_TAG="produccion"
else
ENTORNO_TAG="desarrollo"
fi
echo "=== Despliegue de la base de Contoso Airlines (${ENTORNO_TAG}) ==="
# ------------------------------------------------------------------
# 2. CONTEXTO. Nunca confíes en la suscripción que estuviera activa.
# ------------------------------------------------------------------
az account set --subscription "${SUSCRIPCION}"
echo "Suscripción activa: $(az account show --query name --output tsv)"
# ------------------------------------------------------------------
# 3. PROVEEDORES. Necesarios en suscripciones nuevas; es inocuo repetirlo.
# ------------------------------------------------------------------
az provider register --namespace Microsoft.Storage --wait
# ------------------------------------------------------------------
# 4. GRUPO DE RECURSOS.
# 'az group create' ya es idempotente: si existe, actualiza sus etiquetas.
# ------------------------------------------------------------------
echo "--> Grupo de recursos: ${GRUPO}"
az group create \
--name "${GRUPO}" \
--location "${REGION}" \
--tags entorno="${ENTORNO_TAG}" \
proyecto="${PROYECTO}" \
centro-coste="${CENTRO_COSTE}" \
propietario="${PROPIETARIO}" \
--output none
# ------------------------------------------------------------------
# 5. CUENTA DE ALMACENAMIENTO.
# Comprobamos primero si existe, para que el script sea idempotente
# y para no fallar si el nombre global ya está ocupado por otra persona.
# ------------------------------------------------------------------
echo "--> Cuenta de almacenamiento: ${CUENTA_ALM}"
if az storage account show --name "${CUENTA_ALM}" --resource-group "${GRUPO}" --output none 2>/dev/null; then
echo " Ya existe: no se vuelve a crear."
else
# --sku Standard_LRS : la opción más económica (redundancia local). Módulo 2.
# --kind StorageV2 : tipo de cuenta actual, admite blobs, colas, tablas y archivos.
# --min-tls-version : fuerza TLS 1.2 como mínimo.
# --allow-blob-public-access false : NADIE puede leer los PDF de forma anónima.
# --https-only true : rechaza el tráfico sin cifrar.
az storage account create \
--name "${CUENTA_ALM}" \
--resource-group "${GRUPO}" \
--location "${REGION}" \
--sku Standard_LRS \
--kind StorageV2 \
--min-tls-version TLS1_2 \
--https-only true \
--allow-blob-public-access false \
--tags entorno="${ENTORNO_TAG}" \
proyecto="${PROYECTO}" \
centro-coste="${CENTRO_COSTE}" \
propietario="${PROPIETARIO}" \
--output none
echo " Creada."
fi
# ------------------------------------------------------------------
# 6. CONTENEDOR DE BLOBS.
# --auth-mode login usa TU identidad de Entra ID en lugar de la clave de la
# cuenta: es la forma recomendada y no expone secretos en el script.
# (Requiere tener un rol de datos, p. ej. "Colaborador de datos de Blob".)
# ------------------------------------------------------------------
echo "--> Contenedor: ${CONTENEDOR}"
az storage container create \
--name "${CONTENEDOR}" \
--account-name "${CUENTA_ALM}" \
--auth-mode login \
--public-access off \
--output none
# ------------------------------------------------------------------
# 7. RESUMEN. Comprobación final legible de lo desplegado.
# ------------------------------------------------------------------
echo ""
echo "=== Despliegue completado ==="
az resource list \
--resource-group "${GRUPO}" \
--query "[].{Recurso:name, Tipo:type, Region:location}" \
--output table
echo ""
echo "Para eliminar TODO lo creado y dejar de pagar, ejecuta:"
echo " az group delete --name ${GRUPO} --yes --no-wait"Cómo ejecutarlo
# Dar permisos de ejecución (solo la primera vez).
chmod +x desplegar-base-contoso.sh
# Desplegar el entorno de desarrollo.
./desplegar-base-contoso.sh devQué hace que este script sea idempotente
| Técnica usada | Por qué importa |
|---|---|
az group create sobre un grupo existente |
No falla: actualiza sus etiquetas |
Comprobación previa con az storage account show |
Evita el error de "nombre ya en uso" al reejecutar |
| Nombres derivados de variables, no escritos a mano | El mismo script sirve para dev y para pro |
set -euo pipefail |
Detiene el script ante el primer fallo en lugar de dejar un despliegue a medias |
--output none |
Salida limpia; solo se imprime lo que decidimos |
Si te fijas, este script hace algo muy parecido a una plantilla de infraestructura como código, pero de forma imperativa (paso a paso). El siguiente nivel es hacerlo declarativo con Bicep, y eso es exactamente la lección 05-06.
- Limpieza: borrar sin dejar rastro de gasto
Este apartado es obligatorio, no opcional. El coste de lo que has creado en este módulo es de céntimos, pero el hábito vale dinero real cuando trabajes con máquinas virtuales y bases de datos.
# Borra el grupo y ABSOLUTAMENTE TODO lo que contiene. Es irreversible.
# --yes : no pide confirmación (úsalo solo cuando estés seguro).
# --no-wait : devuelve el control inmediatamente; el borrado sigue en segundo plano.
az group delete --name rg-contoso-reservas-dev --yes --no-waitComprobaciones antes y después:
# Antes: ver exactamente qué se va a destruir.
az resource list --resource-group rg-contoso-reservas-dev --output table
# Después: confirmar que el grupo ya no existe (devuelve "false").
az group exists --name rg-contoso-reservas-devY una comprobación de higiene que conviene hacer periódicamente en toda la suscripción:
# Lista TODOS los grupos de recursos con sus etiquetas: buscando huérfanos y olvidos.
az group list --query "[].{Grupo:name, Region:location, Entorno:tags.entorno, Propietario:tags.propietario}" --output table
# Busca discos que ya no están conectados a ninguna máquina virtual: gasto puro.
az disk list --query "[?diskState=='Unattached'].{Disco:name, Grupo:resourceGroup, GB:diskSizeGb}" --output table
# Busca direcciones IP públicas sin asociar: también se facturan.
az network public-ip list --query "[?ipConfiguration==null].{IP:name, Grupo:resourceGroup}" --output tableEsos tres últimos comandos son, literalmente, tres de las fuentes de gasto inútil más habituales en cuentas de Azure reales. Guárdalos.
Recuerda además: si creaste un bloqueo
CanNotDeleteen la lección anterior, el borrado fallará hasta que lo elimines conaz lock delete. Está diseñado para que sea así.
Errores Comunes y Consejos
- Ejecutar comandos en la suscripción equivocada. Empieza siempre con
az account sety confirma conaz account show. Es el error que más daño hace. - Trabajar con una CLI desactualizada. Si un parámetro "no existe", ejecuta
az upgradeantes de buscar en foros. - Poner mayúsculas o guiones en el nombre de la cuenta de almacenamiento. Solo minúsculas y números, 3-24 caracteres, y único en todo Azure.
- Usar
--output jsondentro de scripts. Para alimentar variables usa--output tsv: evita comillas y saltos de línea inesperados. - Escribir claves de acceso o contraseñas dentro del script. Usa
--auth-mode login, identidades administradas (lección 04-02) o Key Vault (lección 04-03). - Olvidar que Cloud Shell se cierra a los 20 minutos de inactividad y que solo persiste
$HOME. Guarda tu trabajo en~/clouddriveo, mejor, en un repositorio Git. - Olvidar que el almacenamiento de Cloud Shell se factura. Es poco dinero, pero si dejas de usarlo, bórralo.
- Escribir consultas
--querya ciegas. Ejecuta primero el comando en JSON, mira la estructura y luego consulta. - Borrar con
--yessin mirar antes. Ejecutaaz resource list --resource-group ...para ver qué desaparecerá. - Consejo final de coste: adopta la costumbre de terminar cada sesión de prácticas con
az group delete. Un grupo de recursos por práctica, borrado al final: es la disciplina más rentable que puedes adquirir en este curso.
Ejercicios
Ejercicio 1: Consultas de gobierno
Escribe los comandos de Azure CLI que resuelvan estas peticiones de Marta Ríos:
- Mostrar en una tabla el nombre y la región de todos los grupos de recursos de la suscripción activa.
- Listar todos los recursos etiquetados con
proyecto=contoso-reservas, mostrando nombre, tipo y grupo. - Detectar los recursos que no tengan la etiqueta
centro-coste. - Guardar en una variable de shell llamada
REGION_PROla región del gruporg-contoso-reservas-pro.
Ejercicio 2: Adaptar el script
Partiendo del script desplegar-base-contoso.sh del apartado 8:
- Añade una variable
CRITICIDADy aplícala como etiqueta al grupo y a la cuenta de almacenamiento, con valoraltasi el entorno esproybajaen caso contrario. - Añade un paso que, solo si el entorno es
pro, aplique un bloqueoCanNotDeletesobre el grupo. - Explica por qué el paso 3 del script (
az provider register) es seguro aunque se ejecute cada vez.
Ejercicio 3: Comparar herramientas y limpiar
- Escribe el equivalente en Azure PowerShell de estos dos comandos de la CLI:
az group create --name rg-contoso-millas-dev --location westeurope --tags entorno=desarrollo proyecto=contoso-millas
az group delete --name rg-contoso-millas-dev --yes- Justifica en tres líneas qué herramienta elegirías para una tubería de CI/CD que se ejecuta en un contenedor Linux, y por qué.
- Escribe los comandos que auditan una suscripción buscando discos sin conectar y direcciones IP públicas sin asociar, y explica por qué esos dos recursos son fuentes clásicas de gasto inútil.
Soluciones
Solución 1:
# 1. Grupos de recursos con nombre y región.
az group list --query "[].{Grupo:name, Region:location}" --output table
# 2. Recursos del proyecto.
az resource list --tag proyecto=contoso-reservas \
--query "[].{Recurso:name, Tipo:type, Grupo:resourceGroup}" --output table
# 3. Recursos SIN la etiqueta centro-coste.
az resource list \
--query "[?tags.\"centro-coste\" == \`null\`].{Recurso:name, Tipo:type, Grupo:resourceGroup}" \
--output table
# 4. Región del grupo de producción en una variable.
REGION_PRO=$(az group show --name rg-contoso-reservas-pro --query location --output tsv)
echo "$REGION_PRO"Nota sobre el punto 3: como el nombre de la etiqueta lleva un guion, hay que entrecomillarlo dentro de la expresión JMESPath.
Solución 2:
- Variable y etiqueta de criticidad:
# Junto al resto de parámetros:
if [ "${ENTORNO}" = "pro" ]; then
CRITICIDAD="alta"
else
CRITICIDAD="baja"
fi
# Y se añade al bloque de --tags de az group create y de az storage account create:
# criticidad="${CRITICIDAD}"- Bloqueo condicional en producción:
if [ "${ENTORNO}" = "pro" ]; then
echo "--> Aplicando bloqueo CanNotDelete al grupo de producción"
# 'az lock create' falla si ya existe un bloqueo con ese nombre;
# comprobamos primero para mantener la idempotencia del script.
if ! az lock show --name "no-borrar-produccion" --resource-group "${GRUPO}" --output none 2>/dev/null; then
az lock create \
--name "no-borrar-produccion" \
--lock-type CanNotDelete \
--resource-group "${GRUPO}" \
--notes "Plataforma de venta en produccion. Retirar solo con autorizacion." \
--output none
fi
fiaz provider registeres idempotente: si el proveedor ya está registrado, la operación no cambia nada y termina correctamente. Registrarlo no cuesta dinero ni tiene efectos secundarios, por lo que incluirlo garantiza que el script funcione también en una suscripción recién creada.
Solución 3:
- Equivalentes en Azure PowerShell:
New-AzResourceGroup -Name "rg-contoso-millas-dev" -Location "westeurope" -Tag @{
entorno = "desarrollo"
proyecto = "contoso-millas"
}
Remove-AzResourceGroup -Name "rg-contoso-millas-dev" -Force-
Para una tubería en un contenedor Linux elegiría Azure CLI: la imagen es más ligera que instalar el módulo
Azde PowerShell, la sintaxis encaja de forma natural con Bash, la mayoría de tareas de tubería son de una línea, y prácticamente todos los ejemplos de tuberías de Azure DevOps y GitHub Actions están escritos conaz. -
Auditoría de gasto inútil:
az disk list --query "[?diskState=='Unattached'].{Disco:name, Grupo:resourceGroup, GB:diskSizeGb}" --output table
az network public-ip list --query "[?ipConfiguration==null].{IP:name, Grupo:resourceGroup}" --output tableSon fuentes clásicas de gasto porque se facturan por existir, no por usarse. Al borrar una máquina virtual, sus discos gestionados y su IP pública no se eliminan automáticamente si no se marcó la opción correspondiente: quedan huérfanos, invisibles en el día a día y cobrando cada mes. Una revisión mensual con estos dos comandos suele ser la optimización más rentable y más rápida de aplicar.
Conclusión
Con esta lección cierras el módulo 1 y ya tienes la caja de herramientas completa. Sabes por qué automatizar (repetible, auditable, escalable), has instalado Azure CLI y comprobado su versión, sabes iniciar sesión y —muy importante— cambiar y confirmar la suscripción activa antes de tocar nada. Conoces la anatomía de un comando az y su ayuda integrada (--help, az find), y manejas --output table para leer y --query con JMESPath para filtrar, renombrar campos, detectar recursos sin etiquetar y alimentar variables en scripts. Sabes qué aporta Azure PowerShell y con qué criterio elegir entre uno y otro, y cómo funciona Cloud Shell: sus dos intérpretes, la cuenta de almacenamiento que crea y factura, la persistencia limitada a $HOME y el cierre por inactividad. Y has escrito un script real, parametrizado, comentado e idempotente que crea el grupo rg-contoso-reservas-dev, la cuenta de almacenamiento de tarjetas de embarque y su contenedor privado, con las etiquetas obligatorias de Contoso Airlines, además de la rutina de limpieza que evita facturas sorpresa.
Recapitulando el módulo completo: has entendido qué es la nube y qué es Azure y conocido el caso de Contoso Airlines; has distinguido IaaS, PaaS, SaaS y serverless, el modelo de responsabilidad compartida y la geografía de Azure, fijando West Europe como región principal y North Europe como pareja; has creado y protegido tu cuenta con MFA y un presupuesto con alertas; te mueves con soltura por el portal; dominas Azure Resource Manager, la jerarquía de suscripción, grupo de recursos y recurso, los bloqueos y el esquema de etiquetado de Contoso; y ahora automatizas desde la línea de comandos.
Tienes los cimientos: la cuenta, el gobierno, la nomenclatura, los grupos de recursos y la herramienta para desplegar. Lo que falta es la plataforma en sí. En el módulo 2, Servicios principales de Azure, empezamos a construirla de verdad: desplegaremos las máquinas virtuales del motor de disponibilidad heredado, aprenderemos a escalar y dar alta disponibilidad al cómputo, publicaremos Contoso Reservas y la API de Disponibilidad en App Service, guardaremos las tarjetas de embarque en Azure Storage con la redundancia adecuada, y construiremos la red virtual con sus subredes y grupos de seguridad, además de la conectividad híbrida con las oficinas de Barcelona y Palma. Nos vemos allí.
Curso de Azure
Módulo 1: Introducción a Azure
- ¿Qué es Azure?
- Modelos de servicio, regiones y zonas de disponibilidad
- Crear y configurar tu cuenta de Azure
- Recorrido por el portal de Azure
- Azure Resource Manager: suscripciones, grupos de recursos y etiquetas
- Azure CLI, PowerShell y Cloud Shell
Módulo 2: Servicios principales de Azure
- Máquinas virtuales de Azure
- Escalado y alta disponibilidad del cómputo
- Azure App Service
- Azure Storage: blobs, archivos, colas y tablas
- Redes en Azure: redes virtuales, subredes y NSG
- Conectividad híbrida y entrega global
Módulo 3: Bases de datos de Azure
- Elegir el servicio de datos adecuado
- Azure SQL Database
- Azure Cosmos DB
- Azure Database for MySQL
- Azure Database for PostgreSQL
- Analítica de datos: Data Lake, Data Factory y Synapse
Módulo 4: Seguridad en Azure
- Microsoft Entra ID y gestión de identidades
- RBAC e identidades administradas
- Azure Key Vault
- Protección DDoS y firewall de aplicaciones web
- Microsoft Defender for Cloud
- Gobernanza y cumplimiento con Azure Policy
Módulo 5: Azure DevOps
- Introducción a Azure DevOps
- Azure Repos
- Azure Pipelines: integración continua
- Despliegue continuo con entornos y aprobaciones
- Azure Artifacts
- Infraestructura como código con Bicep
Módulo 6: Servicios avanzados de Azure
- Contenedores en Azure: Container Registry y Container Apps
- Azure Kubernetes Service (AKS)
- Azure Functions
- Azure Logic Apps
- Mensajería y eventos: Service Bus, Event Grid y Event Hubs
- Servicios de IA de Azure
Módulo 7: Monitoreo y gestión
- Azure Monitor: métricas, alertas y paneles
- Log Analytics y consultas KQL
- Application Insights
- Azure Automation y runbooks
- Copias de seguridad y recuperación ante desastres
Módulo 8: Gestión y optimización de costos
- Calculadora de precios y estimación de costes
- Azure Cost Management: análisis, presupuestos y alertas
- Reservas, planes de ahorro y Azure Hybrid Benefit
- Azure Advisor
- Estrategias de optimización y cultura FinOps
