Skip to content

Azure Services

Autenticación Python en Máquinas Azure Arc: Guía Práctica

Resumen

Los servidores enrolados en Azure Arc pueden autenticarse contra recursos Azure usando managed identity sin almacenar credenciales. Python + Azure SDK (azure-identity) simplifica esto con DefaultAzureCredential o ManagedIdentityCredential, accediendo al endpoint IMDS local (http://localhost:40342) que expone el agente Azure Connected Machine.

¿Qué es Azure Arc-enabled servers?

Azure Arc extiende el plano de control de Azure a servidores físicos y VMs fuera de Azure (on-premises, otras clouds, edge). Una vez enrolado, el servidor obtiene:

  • Representación como recurso Azure (Microsoft.HybridCompute/machines)
  • System-assigned managed identity automática
  • Acceso a servicios Azure (Key Vault, Storage, Log Analytics, etc.) sin credenciales hard-coded
  • Gestión unificada (Policy, Update Management, extensiones VM)

Cómo funciona la autenticación en Azure Arc

Cuando el agente azcmagent se instala y conecta, ocurre:

  1. Azure Resource Manager crea un service principal en Microsoft Entra ID para la identidad del servidor.
  2. El agente configura un endpoint IMDS local en http://localhost:40342 (no enrutable, solo accesible desde localhost).
  3. Variables de entorno se establecen automáticamente:
  4. IMDS_ENDPOINT=http://localhost:40342
  5. IDENTITY_ENDPOINT=http://localhost:40342/metadata/identity/oauth2/token
  6. Las aplicaciones solicitan tokens a este endpoint, sin exponer secretos.

Diferencia con Azure VMs

Azure VMs usan http://169.254.169.254 (Azure IMDS), mientras que Arc usa localhost:40342. El SDK de Azure detecta automáticamente el entorno correcto.

Métodos de autenticación en Python

Opción 1: DefaultAzureCredential (recomendada)

Cadena de credenciales que prueba múltiples métodos en orden (variables de entorno, managed identity, Azure CLI, etc.). Funciona tanto en desarrollo local como en producción Arc sin cambios de código.

from azure.identity import DefaultAzureCredential
from azure.keyvault.secrets import SecretClient

# Credential chain automática (detecta Arc managed identity)
credential = DefaultAzureCredential()

# Cliente Key Vault sin credenciales explícitas
vault_url = "https://my-vault.vault.azure.net"
client = SecretClient(vault_url=vault_url, credential=credential)

# Obtener secreto
secret = client.get_secret("database-password")
print(f"Secret value: {secret.value}")

Opción 2: ManagedIdentityCredential (explícita)

Fuerza el uso de managed identity exclusivamente, útil cuando no quieres la cadena de fallback.

from azure.identity import ManagedIdentityCredential
from azure.storage.blob import BlobServiceClient

# System-assigned managed identity
credential = ManagedIdentityCredential()

# Cliente Blob Storage
account_url = "https://mystorageaccount.blob.core.windows.net"
blob_service = BlobServiceClient(account_url=account_url, credential=credential)

# Listar containers
for container in blob_service.list_containers():
    print(f"Container: {container.name}")

Opción 3: User-assigned managed identity

Si el servidor tiene múltiples identities user-assigned, especifica el client_id:

from azure.identity import ManagedIdentityCredential

# User-assigned identity con client_id específico
client_id = "12345678-abcd-1234-abcd-1234567890ab"
credential = ManagedIdentityCredential(client_id=client_id)

# Usa este credential con cualquier SDK Azure

Opción 4: MSAL Python (bajo nivel)

Para casos avanzados, msal 1.29.0+ soporta managed identity directamente:

import msal
import requests

# System-assigned managed identity
managed_identity = msal.SystemAssignedManagedIdentity()
app = msal.ManagedIdentityClient(managed_identity, http_client=requests.Session())

# Obtener token para Key Vault
result = app.acquire_token_for_client(resource="https://vault.azure.net")

if "access_token" in result:
    token = result["access_token"]
    print(f"Token adquirido: {token[:20]}...")
else:
    print(f"Error: {result.get('error_description')}")

Ejemplo completo: Leer secreto de Key Vault

Escenario: Script Python en servidor Arc que obtiene credenciales DB desde Key Vault.

#!/usr/bin/env python3
"""
Script: get_db_credentials.py
Descripción: Obtiene credenciales de base de datos desde Azure Key Vault
             usando managed identity del servidor Azure Arc
Requisitos: pip install azure-identity azure-keyvault-secrets
"""

from azure.identity import DefaultAzureCredential
from azure.keyvault.secrets import SecretClient
import sys

def get_secret(vault_name: str, secret_name: str) -> str:
    """
    Obtiene un secreto de Azure Key Vault usando managed identity.

    Args:
        vault_name: Nombre del Key Vault (sin .vault.azure.net)
        secret_name: Nombre del secreto

    Returns:
        Valor del secreto
    """
    try:
        # DefaultAzureCredential detecta automáticamente el entorno Arc
        credential = DefaultAzureCredential()

        vault_url = f"https://{vault_name}.vault.azure.net"
        client = SecretClient(vault_url=vault_url, credential=credential)

        # Obtener secreto
        secret = client.get_secret(secret_name)
        return secret.value

    except Exception as e:
        print(f"Error obteniendo secreto: {e}", file=sys.stderr)
        sys.exit(1)

if __name__ == "__main__":
    # Configuración
    VAULT_NAME = "my-production-vault"
    DB_PASSWORD_SECRET = "db-password"

    # Obtener credencial
    password = get_secret(VAULT_NAME, DB_PASSWORD_SECRET)
    print(f"Credencial obtenida exitosamente (longitud: {len(password)} caracteres)")

    # Usar password para conectar a DB (no imprimir en logs reales)
    # connection_string = f"Server=myserver;Database=mydb;User=admin;Password={password}"

Requisitos previos:

  1. Servidor enrolado en Azure Arc con managed identity habilitada (por defecto).
  2. Identity del servidor con RBAC apropiado en Key Vault:
# Variables
RESOURCE_GROUP="my-rg"
SERVER_NAME="my-arc-server"
VAULT_NAME="my-production-vault"

# Obtener el principal ID de la managed identity
PRINCIPAL_ID=$(az connectedmachine show \
    --resource-group $RESOURCE_GROUP \
    --name $SERVER_NAME \
    --query identity.principalId -o tsv)

# Asignar rol "Key Vault Secrets User" (RBAC)
az role assignment create \
    --assignee $PRINCIPAL_ID \
    --role "Key Vault Secrets User" \
    --scope /subscriptions/$(az account show --query id -o tsv)/resourceGroups/$RESOURCE_GROUP/providers/Microsoft.KeyVault/vaults/$VAULT_NAME

Validar managed identity en el servidor

Antes de ejecutar código Python, verifica que el endpoint IMDS responde:

# Variables de entorno expuestas por el agente Arc
echo $IMDS_ENDPOINT
# Salida esperada: http://localhost:40342

echo $IDENTITY_ENDPOINT
# Salida esperada: http://localhost:40342/metadata/identity/oauth2/token

# Test manual del endpoint (requiere header Metadata:true)
curl -H "Metadata:true" \
    "http://localhost:40342/metadata/identity/oauth2/token?api-version=2020-06-01&resource=https://vault.azure.net"

Respuesta exitosa (JSON con access_token, expires_on, etc.):

{
  "access_token": "eyJ0eXAiOiJKV1QiLCJhbGc...",
  "expires_on": "1700000000",
  "resource": "https://vault.azure.net",
  "token_type": "Bearer"
}

Troubleshooting común

Error: "No managed identity endpoint found"

Causa: El agente Arc no está instalado o no ha configurado el endpoint IMDS.

Solución:

# Verificar estado del agente
sudo azcmagent show

# Si está desconectado, reconectar
sudo azcmagent connect \
    --resource-group "my-rg" \
    --tenant-id "tenant-id" \
    --location "westeurope" \
    --subscription-id "sub-id"

Error: "AADSTS700016: Application not found"

Causa: La managed identity no tiene permisos RBAC sobre el recurso destino.

Solución: Asignar rol apropiado (ver ejemplo de Key Vault arriba). Roles comunes:

  • Key Vault: Key Vault Secrets User (lectura secretos)
  • Storage: Storage Blob Data Reader (lectura blobs)
  • Log Analytics: Log Analytics Reader (consultas)

Error: "CredentialUnavailableError: ManagedIdentityCredential authentication unavailable"

Causa: Ejecutando código fuera de un entorno con managed identity (ej: laptop local).

Solución: DefaultAzureCredential caerá en otros métodos (Azure CLI, variables de entorno). Para testing local:

# Autenticarse con Azure CLI (DefaultAzureCredential lo detectará)
az login

# O usar service principal con variables de entorno
export AZURE_CLIENT_ID="app-id"
export AZURE_CLIENT_SECRET="secret"
export AZURE_TENANT_ID="tenant-id"

Permisos y seguridad

Principio de mínimo privilegio

Asigna solo los permisos necesarios:

# ❌ MAL: Owner en toda la suscripción
az role assignment create --assignee $PRINCIPAL_ID --role "Owner" --subscription $SUB_ID

# ✅ BIEN: Lectura específica en un Key Vault
az role assignment create --assignee $PRINCIPAL_ID --role "Key Vault Secrets User" --scope $VAULT_ID

Control de acceso local

Solo usuarios con privilegios elevados pueden obtener tokens managed identity:

  • Windows: Miembros de Administrators o grupo Hybrid Agent Extension Applications
  • Linux: Miembros del grupo himds
# Linux: Añadir usuario al grupo himds (con precaución)
sudo usermod -aG himds myappuser

# Verificar membership
groups myappuser

Buenas prácticas

  1. Usa DefaultAzureCredential por defecto: Funciona en dev y producción sin cambios.
  2. No almacenes tokens: Deja que el SDK los renueve automáticamente.
  3. Logging seguro: No imprimas tokens o secretos en logs (print(token) ❌).
  4. Auditoría: Habilita diagnostic logs en Key Vault/Storage para rastrear accesos:
az monitor diagnostic-settings create \
    --resource $VAULT_ID \
    --name "audit-logs" \
    --logs '[{"category":"AuditEvent","enabled":true}]' \
    --workspace $LOG_ANALYTICS_WORKSPACE_ID
  1. Timeout y reintentos: El SDK maneja reintentos, pero para scripts long-running:
from azure.core.exceptions import AzureError
import time

def get_secret_with_retry(client, secret_name, max_retries=3):
    for attempt in range(max_retries):
        try:
            return client.get_secret(secret_name).value
        except AzureError as e:
            if attempt < max_retries - 1:
                time.sleep(2 ** attempt)  # Exponential backoff
                continue
            raise

Instalación de dependencias

# Instalar Azure SDK para identidad y servicios específicos
pip install azure-identity azure-keyvault-secrets azure-storage-blob

# Para desarrollo, incluye azure-cli para testing local
pip install azure-cli

Archivo requirements.txt recomendado:

azure-identity>=1.15.0
azure-keyvault-secrets>=4.7.0
azure-storage-blob>=12.19.0

Referencias

Documentación oficial validada:

Azure Storage Priority Replication: Replicación acelerada con SLA

Resumen

Priority Replication acelera la replicación de datos en Azure Storage con SLA de 15 minutos para cumplir requisitos estrictos de RPO (Recovery Point Objective). Disponible para geo-redundancia (GRS/GZRS) y Object Replication entre cuentas.

¿Qué es Priority Replication?

Priority Replication es una capacidad de Azure Storage que prioriza el tráfico de replicación y proporciona garantías SLA para sincronización de datos entre regiones. Diseñada para escenarios donde el tiempo de replicación es crítico para cumplimiento y continuidad de negocio.

Dos variantes disponibles:

  1. Geo Priority Replication: Para cuentas con GRS/GZRS (redundancia entre regiones)
  2. Object Replication Priority: Para políticas de Object Replication entre cuentas

SLA clave: 99.0% del mes de facturación con Last Sync Time (LST) ≤ 15 minutos

Geo Priority Replication

Acelera la replicación entre región primaria y secundaria para cuentas con GRS (Geo-Redundant Storage) o GZRS (Geo-Zone-Redundant Storage).

Disponibilidad y limitaciones

Regiones soportadas: Todas las regiones públicas con GRS/GZRS excepto:

  • West India
  • Switzerland West

Requisitos para GZRS:

  • Región debe soportar Availability Zones
  • Región debe tener paired region

Beneficios principales

  1. RPO garantizado: Confianza en tiempo de sincronización para cumplimiento
  2. Failover sin sorpresas: LST predecible si ocurre failover no planificado
  3. Monitoreo mejorado: Telemetría detallada vía Azure Monitor
  4. SLA respaldado: Garantía de 99.0% del mes con lag ≤ 15 minutos

Exclusiones del SLA

El SLA NO aplica en estos casos:

Por tipo de blob:

  • Page blobs y append blobs (SLA solo para Block Blobs)
  • Cuentas con llamadas API de Page/Append Blob en últimos 30 días
  • Cuentas con features que crean estos blobs (Change Feed, Object Replication, logs en Azure Monitor)

Por condición de cuenta:

  • LST > 15 minutos durante habilitación de la feature
  • Transfer rate > 1 Gbps con backlog pendiente
  • 100 CopyBlob requests/segundo con backlog pendiente

Por eventos operacionales:

  • Unplanned failover (desactiva automáticamente la feature)
  • Durante conversión GRS ↔ GZRS (no afecta si se mantiene dentro de guardrails)

Habilitar Geo Priority Replication

Durante creación de cuenta nueva

Azure CLI:

# Variables
RESOURCE_GROUP="rg-storage-prod"
STORAGE_ACCOUNT="stgeopriorityprod"
LOCATION="westeurope"

# Crear cuenta con Geo Priority Replication
az storage account create \
  --name $STORAGE_ACCOUNT \
  --resource-group $RESOURCE_GROUP \
  --location $LOCATION \
  --sku Standard_GRS \
  --enable-blob-geo-priority-replication true

Azure PowerShell:

# Variables
$rgName = "rg-storage-prod"
$storageAccountName = "stgeopriorityprod"
$location = "westeurope"

# Crear cuenta con Geo Priority Replication
$account = New-AzStorageAccount `
  -ResourceGroupName $rgName `
  -StorageAccountName $storageAccountName `
  -SkuName Standard_GRS `
  -Location $location `
  -EnableBlobGeoPriorityReplication $true
En cuentas existentes

Habilitar:

# Azure CLI
az storage account update \
  --name $STORAGE_ACCOUNT \
  --resource-group $RESOURCE_GROUP \
  --enable-blob-geo-priority-replication true
# PowerShell
Set-AzStorageAccount `
  -ResourceGroupName $rgName `
  -StorageAccountName $storageAccountName `
  -EnableBlobGeoPriorityReplication $true

Deshabilitar:

# Azure CLI
az storage account update \
  --name $STORAGE_ACCOUNT \
  --resource-group $RESOURCE_GROUP \
  --enable-blob-geo-priority-replication false
# PowerShell
Set-AzStorageAccount `
  -ResourceGroupName $rgName `
  -StorageAccountName $storageAccountName `
  -EnableBlobGeoPriorityReplication $false

Monitorear cumplimiento con Geo Blob Lag

Métrica nueva (Preview): Geo Blob Lag - segundos desde última copia completa entre regiones.

Habilitar preview:

  1. Azure Portal → Subscriptions → Preview features
  2. Feature: AllowGeoPriorityReplicationMetricsInPortal
  3. Provider: Microsoft.Storage

Acceder a métricas:

  • Portal: Storage Account → Redundancy o Metrics
  • Métrica: Geo Blob Lag metric (preview)

Tiempo de activación

Las métricas pueden tardar hasta 24 horas en aparecer tras registrar la feature.

Uso para validar SLA:

Monitorear que el lag se mantiene ≤ 15 minutos durante el 99% del mes. Si excede, ese período se excluye del SLA.

Object Replication Priority

Acelera la replicación entre cuentas de storage usando Object Replication policies. Garantiza que 99.0% de objetos se replican en ≤ 15 minutos cuando origen y destino están en el mismo continente.

Disponibilidad

Regiones soportadas: Todas las regiones públicas excepto:

  • West India
  • Switzerland West

Portal experience (Preview):

  • Feature: AllowPriorityObjectReplicationInPortal
  • Provider: Microsoft.Storage

Beneficios principales

  1. SLA de rendimiento: 99% de objetos en ≤ 15 minutos (mismo continente)
  2. Métricas automáticas: Activación automática de OR metrics
  3. Visibilidad mejorada: Time buckets (0-5 min, 5-10 min, >24h)
  4. DR garantizado: Confianza en tiempos para disaster recovery

Exclusiones del SLA

El SLA NO aplica a:

Por características del objeto:

  • Objetos > 5 GB
  • Objetos modificados > 10 veces/segundo

Por geografía:

  • Origen y destino en continentes diferentes

Por tamaño de cuenta:

  • Cuentas > 5 PB
  • Cuentas con > 10 mil millones de blobs

Por condiciones operativas:

  • Transfer rate > 1 Gbps con backlog pendiente
  • 1,000 PUT/DELETE ops/segundo con backlog pendiente

  • Durante replicación de blobs existentes tras crear/actualizar policy

Limitación de políticas

Solo 1 policy por cuenta origen puede tener Priority Replication habilitado (aunque la cuenta soporte hasta 2 policies).

Habilitar Object Replication Priority

Durante creación de nueva policy

Azure CLI:

# Variables
SRC_ACCOUNT="stgsourceprod"
DST_ACCOUNT="stgdestinationdr"
SRC_CONTAINER="data"
DST_CONTAINER="data-replica"

# Crear policy con Priority Replication
az storage account or-policy create \
  --account-name $DST_ACCOUNT \
  --source-account $SRC_ACCOUNT \
  --destination-container $DST_CONTAINER \
  --source-container $SRC_CONTAINER \
  --min-creation-time "2025-11-11T00:00:00Z" \
  --enable-metrics true \
  --priority-replication true

Azure PowerShell:

# Variables
$rgName = "rg-storage-prod"
$srcAccountName = "stgsourceprod"
$dstAccountName = "stgdestinationdr"
$srcAccountResourceID = "/subscriptions/{sub-id}/resourceGroups/{rg}/providers/Microsoft.Storage/storageAccounts/$srcAccountName"
$srcContainer = "data"
$dstContainer = "data-replica"

# Crear regla y policy con Priority Replication
$rule = New-AzStorageObjectReplicationPolicyRule `
  -SourceContainer $srcContainer `
  -DestinationContainer $dstContainer

$dstPolicy = Set-AzStorageObjectReplicationPolicy `
  -ResourceGroupName $rgName `
  -StorageAccountName $dstAccountName `
  -PolicyId default `
  -SourceAccount $srcAccountResourceID `
  -Rule $rule `
  -EnableMetric $true `
  -EnablePriorityReplication $true

# Aplicar policy en cuenta origen
$srcPolicy = Set-AzStorageObjectReplicationPolicy `
  -ResourceGroupName $rgName `
  -StorageAccountName $srcAccountName `
  -InputObject $dstPolicy

# Verificar habilitación
$srcPolicy.PriorityReplication.Enabled
En policies existentes

Habilitar:

# Azure CLI
az storage account or-policy update \
  --account-name $DST_ACCOUNT \
  --source-account $SRC_ACCOUNT \
  --destination-container $DST_CONTAINER \
  --source-container $SRC_CONTAINER \
  --min-creation-time "2025-11-11T00:00:00Z" \
  --enable-metrics true \
  --priority-replication true
# PowerShell
$dstPolicy = Set-AzStorageObjectReplicationPolicy `
  -ResourceGroupName $rgName `
  -StorageAccountName $dstAccountName `
  -PolicyId default `
  -SourceAccount $srcAccountResourceID `
  -Rule $rule `
  -EnableMetric $true `
  -EnablePriorityReplication $true

$srcPolicy = Set-AzStorageObjectReplicationPolicy `
  -ResourceGroupName $rgName `
  -StorageAccountName $srcAccountName `
  -InputObject $dstPolicy

# Confirmar
$srcPolicy.PriorityReplication.Enabled

Deshabilitar:

# Azure CLI
az storage account or-policy update \
  --account-name $DST_ACCOUNT \
  --source-account $SRC_ACCOUNT \
  --destination-container $DST_CONTAINER \
  --source-container $SRC_CONTAINER \
  --min-creation-time "2025-11-11T00:00:00Z" \
  --enable-metrics true \
  --priority-replication false
# PowerShell - cambiar a $false
$dstPolicy = Set-AzStorageObjectReplicationPolicy `
  -ResourceGroupName $rgName `
  -StorageAccountName $dstAccountName `
  -PolicyId default `
  -SourceAccount $srcAccountResourceID `
  -Rule $rule `
  -EnableMetric $true `
  -EnablePriorityReplication $false

Monitorear SLA de Object Replication

Cuando OR Priority Replication está habilitada, OR metrics se activan automáticamente.

Métricas disponibles:

Métrica Descripción Dimensiones
Operations pending for replication Total de operaciones pendientes Time buckets
Bytes pending for replication Bytes pendientes de replicar Time buckets

Time buckets:

  • 0-5 minutos
  • 5-10 minutos
  • 10-15 minutos
  • 15-30 minutos
  • 30 minutos - 2 horas
  • 2-8 horas
  • 8-24 horas
  • 24 horas

Validar SLA:

Monitorear que buckets grandes (>15 min) estén en cero o cerca de cero durante el mes.

Verificar replicación de blob individual:

# Comprobar estado de replicación
az storage blob show \
  --account-name $SRC_ACCOUNT \
  --container-name $SRC_CONTAINER \
  --name myblob.txt \
  --query 'objectReplicationSourceProperties[].rules[].status' \
  --output tsv \
  --auth-mode login

Estado Completed = blob disponible en destino garantizado.

Precios

Geo Priority Replication

Inicio de facturación: 1 de enero de 2026

  • Cuentas existentes con feature habilitada
  • Cuentas nuevas que habiliten la feature

Coste: Por GB (consultar Azure Storage Pricing)

Object Replication Priority

Coste: Por GB de nuevo ingress

Costes adicionales estándar (igual que OR normal):

  • Transacciones de lectura (origen)
  • Transacciones de escritura (destino)
  • Network egress

Facturación post-desactivación

Ambas features facturan durante 30 días adicionales tras deshabilitarlas.

Casos de uso

Cumplimiento normativo estricto

Escenario: Sector financiero/salud con regulaciones de RPO < 15 minutos.

# Storage account para datos regulados
az storage account create \
  --name stgcomplianceprod \
  --resource-group rg-compliance \
  --location westeurope \
  --sku Standard_GZRS \
  --enable-blob-geo-priority-replication true \
  --tags "Compliance=Financial" "RPO=15min"

Validación:

  • Monitorear Geo Blob Lag diariamente
  • Alertas si lag > 10 minutos
  • Reportes mensuales de LST para auditorías

Disaster Recovery con RTO/RPO garantizados

Escenario: Aplicación crítica con SLA de DR < 1 hora.

# Source: Producción (North Europe)
SRC_ACCOUNT="stgappprodneu"
# Destination: DR (West Europe)
DST_ACCOUNT="stgappdrweu"

# Policy OR con Priority Replication
az storage account or-policy create \
  --account-name $DST_ACCOUNT \
  --source-account $SRC_ACCOUNT \
  --destination-container app-data \
  --source-container app-data \
  --min-creation-time "2025-11-11T00:00:00Z" \
  --enable-metrics true \
  --priority-replication true

Beneficio: Confianza en que datos están en DR site en ≤ 15 minutos.

Arquitectura multi-región con HA

Escenario: Servicio global con réplicas en múltiples continentes.

graph LR
    A[Primary
West Europe
GRS+Priority] --> B[Secondary
North Europe
Paired region] A --> C[OR Priority
East US
Read replica] A --> D[OR Priority
Southeast Asia
Read replica] style A fill:#0078d4,color:#fff style B fill:#50e6ff,color:#000 style C fill:#50e6ff,color:#000 style D fill:#50e6ff,color:#000

Configuración:

  1. Primary (West Europe): GRS + Geo Priority Replication
  2. Secondary paired (North Europe): Automático con GRS
  3. US replica: Object Replication Priority (mismo continente que origen - garantiza SLA)
  4. Asia replica: Object Replication normal (diferente continente - sin SLA)

Sincronización de entornos Dev/Test

Escenario: Copiar producción a staging con datos frescos.

# Policy OR Priority: Prod → Staging
$rule = New-AzStorageObjectReplicationPolicyRule `
  -SourceContainer "production-data" `
  -DestinationContainer "staging-data"

$policy = Set-AzStorageObjectReplicationPolicy `
  -ResourceGroupName "rg-prod" `
  -StorageAccountName "stgstaging" `
  -PolicyId default `
  -SourceAccount "/subscriptions/{id}/resourceGroups/rg-prod/providers/Microsoft.Storage/storageAccounts/stgprod" `
  -Rule $rule `
  -EnableMetric $true `
  -EnablePriorityReplication $true

Beneficio: Staging siempre con datos < 15 minutos antiguos.

Arquitectura recomendada

Patrón Geo-Redundant + Object Replication

graph TB
    subgraph "Región Primaria: West Europe"
        A[Storage Account
GRS + Geo Priority] A1[Block Blobs
Producción] A --> A1 end subgraph "Paired Region: North Europe" B[Secondary Storage
Automático GRS] B1[Block Blobs
Replica GRS] B --> B1 end subgraph "Región DR: East US" C[Storage Account
OR Destination] C1[Replica
OR Priority] C --> C1 end subgraph "Región Analítica: West US" D[Storage Account
OR Destination] D1[Replica
OR Normal] D --> D1 end A1 -->|Geo Replication
LST ≤ 15min SLA| B1 A1 -->|OR Priority
99% ≤ 15min| C1 A1 -->|OR Standard
Async| D1 style A fill:#0078d4,color:#fff style B fill:#50e6ff,color:#000 style C fill:#50e6ff,color:#000 style D fill:#e6e6e6,color:#000

Capas de protección:

  1. Local redundancy: ZRS/LRS en región primaria
  2. Geo redundancy con SLA: Geo Priority Replication a paired region
  3. DR cross-region con SLA: OR Priority a región DR (mismo continente)
  4. Analítica/archive: OR estándar a región de análisis

Buenas prácticas

Diseño de cuenta

  1. Segregar por SLA:
  2. Cuentas con Priority Replication: Solo Block Blobs
  3. Cuentas con Page/Append Blobs: Sin Priority Replication

  4. Evitar exclusiones del SLA:

  5. No habilitar Change Feed si no es necesario
  6. No activar diagnostic logs a storage en cuenta con Priority Replication
  7. Usar cuentas dedicadas para logs (sin Priority)

  8. Tagging para governance:

az storage account create \
  --name $STORAGE_ACCOUNT \
  --resource-group $RESOURCE_GROUP \
  --tags \
    "PriorityReplication=Enabled" \
    "SLA-RPO=15min" \
    "CostCenter=IT-Production" \
    "Compliance=Required"

Monitoreo proactivo

Alertas recomendadas:

# Alert si Geo Blob Lag > 10 minutos (margen de seguridad)
az monitor metrics alert create \
  --name "High-Geo-Lag-Alert" \
  --resource $STORAGE_ACCOUNT_ID \
  --condition "avg GeoBlobLag > 600" \
  --window-size 5m \
  --evaluation-frequency 1m \
  --action-group-id $ACTION_GROUP_ID

Dashboard de cumplimiento:

  • Geo Blob Lag (hourly average)
  • OR pending operations por time bucket
  • Throughput vs 1 Gbps threshold
  • CopyBlob operations vs 100 ops/sec threshold

Optimización de costes

  1. Evaluar necesidad real de SLA:
  2. Priority Replication: Workloads críticos con RPO estricto
  3. GRS/OR estándar: Workloads tolerantes a lag > 15 min

  4. Lifecycle management:

{
  "rules": [
    {
      "name": "tierToCool",
      "type": "Lifecycle",
      "definition": {
        "filters": {
          "blobTypes": ["blockBlob"]
        },
        "actions": {
          "baseBlob": {
            "tierToCool": {
              "daysAfterModificationGreaterThan": 30
            }
          }
        }
      }
    }
  ]
}

Datos en Cool tier siguen replicándose con Priority pero con menor coste de storage.

  1. Revisar policies OR:
  2. Una sola policy con Priority Replication por cuenta origen
  3. Otras policies: OR estándar

Seguridad

  1. Network security:
# Restringir acceso a VNETs
az storage account update \
  --name $STORAGE_ACCOUNT \
  --resource-group $RESOURCE_GROUP \
  --default-action Deny

az storage account network-rule add \
  --account-name $STORAGE_ACCOUNT \
  --resource-group $RESOURCE_GROUP \
  --vnet-name my-vnet \
  --subnet app-subnet
  1. Encryption:
  2. Customer-managed keys (CMK) para datos en reposo
  3. HTTPS obligatorio para datos en tránsito

  4. RBAC granular:

  5. Storage Blob Data Contributor: Apps que escriben
  6. Storage Blob Data Reader: Apps DR que solo leen
  7. Storage Account Contributor: Operadores que gestionan replicación

Troubleshooting

Geo Blob Lag > 15 minutos

Diagnóstico:

# Ver LST actual
az storage account show \
  --name $STORAGE_ACCOUNT \
  --resource-group $RESOURCE_GROUP \
  --query "geoReplicationStats.lastSyncTime" \
  --output tsv

# Comprobar throughput
az monitor metrics list \
  --resource $STORAGE_ACCOUNT_ID \
  --metric "Egress" \
  --start-time $(date -u -d '1 hour ago' +%Y-%m-%dT%H:%M:%SZ) \
  --interval PT5M \
  --aggregation Average

Causas comunes:

  1. Throughput > 1 Gbps: Reducir ingress o escalar a múltiples cuentas
  2. CopyBlob > 100 ops/sec: Distribuir copies en el tiempo
  3. Page/Append blobs: Revisar si hay features creando estos blobs inadvertidamente

OR metrics no aparecen

Validaciones:

# Comprobar que metrics están habilitadas
$policy = Get-AzStorageObjectReplicationPolicy `
  -ResourceGroupName $rgName `
  -StorageAccountName $srcAccountName `
  -PolicyId $policyId

$policy.EnableMetrics
$policy.PriorityReplication.Enabled

Solución:

  • Esperar 24 horas tras habilitar
  • Verificar que hay tráfico de replicación activo
  • Comprobar que policy está en estado Enabled

SLA no se cumple

Checklist de elegibilidad:

  • Solo Block Blobs (no Page/Append)
  • Sin llamadas API Page/Append en últimos 30 días
  • Throughput < 1 Gbps
  • CopyBlob < 100 ops/sec
  • LST ≤ 15 min al habilitar feature
  • OR: Origen y destino en mismo continente
  • OR: Objetos < 5 GB
  • OR: No más de 10 modificaciones/segundo por objeto

Validar con Azure Support:

Abrir caso incluyendo:

  • Storage Account ID
  • Período de incumplimiento (fechas/horas)
  • Métricas de Geo Blob Lag o OR pending operations
  • Confirmación de elegibilidad (checklist anterior)

Referencias

Azure Deployment Environments: Self-service para desarrolladores

Resumen

Azure Deployment Environments es el reemplazo de DevTest Labs, diseñado para que equipos de desarrollo creen entornos completos (App Service + Cosmos + Key Vault + Storage) desde un catálogo de plantillas IaC sin esperar a Platform Engineering. Dev Centers centralizan la gobernanza, Projects definen permisos, y developers despliegan con CLI/Portal. Zero acceso a subscriptions de producción.

Azure AI Foundry: tu hub unificado para IA generativa en Azure

Resumen

Azure AI Foundry (antes Azure AI Studio) es la plataforma unificada de Microsoft para desarrollar, desplegar y gestionar aplicaciones de IA generativa. Con acceso a 1900+ modelos (GPT-4o, o1, DeepSeek, Llama...), un entorno colaborativo tipo MLOps, y herramientas para RAG, evaluación y monitorización, todo en un portal integrado.

Si trabajas con Azure OpenAI, LangChain, o quieres construir copilots/agents, este es tu punto de partida.

Azure Container Apps en 2025: La Evolución del Serverless para Contenedores

Resumen

Azure Container Apps ha evolucionado significativamente desde su lanzamiento en 2022. Este artículo actualizado explora las capacidades actuales del servicio, las novedades incorporadas en 2024-2025, y cómo se posiciona como la solución ideal para ejecutar aplicaciones nativas de la nube sin la complejidad de gestionar Kubernetes directamente.

TL;DR

  • Azure Container Apps es un servicio serverless que ejecuta contenedores sin gestionar infraestructura, construido sobre Kubernetes, KEDA, Dapr y Envoy
  • Novedades 2024-2025: GPUs serverless, Dynamic Sessions, Azure Functions integradas, workload profiles dedicados con GPUs A100/T4
  • Casos de uso: microservicios, APIs, procesamiento de eventos, cargas AI/ML, aplicaciones con IA generativa
  • Escalado automático (incluso a cero), revisiones, traffic splitting, integración nativa con servicios Azure

El Problema que Resuelve

«Necesito ejecutar aplicaciones Cloud Native en contenedores, pero no quiero la complejidad operativa de Kubernetes, OpenShift, etc.»

Esta es una necesidad recurrente en equipos de desarrollo que quieren aprovechar las ventajas de los contenedores y arquitecturas de microservicios sin dedicar recursos a:

  • Configurar y mantener clusters de Kubernetes
  • Gestionar nodos, redes, almacenamiento
  • Administrar actualizaciones y parches del orquestador
  • Implementar observabilidad y monitorización avanzada desde cero

Azure Container Apps: La Solución Serverless

Azure Container Apps es un servicio gestionado serverless que permite ejecutar contenedores sin preocuparse por la infraestructura subyacente. Lanzado inicialmente en 2022 y con mejoras continuas, se ha convertido en una opción madura para desplegar aplicaciones modernas.

Arquitectura Subyacente

Aunque no gestionas directamente Kubernetes, bajo el telón Azure Container Apps funciona sobre:

  • Azure Kubernetes Service (AKS): proporciona el orquestador
  • KEDA (Kubernetes Event Driven Autoscaling): escalado basado en eventos
  • Dapr (Distributed Application Runtime): integración nativa para microservicios
  • Envoy: proxy para enrutamiento y observabilidad
flowchart TB
  subgraph Internet["Internet / Usuarios"]
    USER["Cliente HTTP/API"]
  end

  subgraph ACA["Azure Container Apps Environment"]
    INGRESS["Ingress (Envoy)"]
    APP1["Container App 1"]
    APP2["Container App 2"]
    APP3["Container App 3"]
    DAPR["Dapr Sidecar"]
    KEDA["KEDA Scaler"]
  end

  subgraph Backend["Servicios Backend"]
    STORAGE["Azure Storage"]
    COSMOSDB["Cosmos DB"]
    SERVICEBUS["Service Bus"]
  end

  USER --> INGRESS
  INGRESS --> APP1
  INGRESS --> APP2
  INGRESS --> APP3
  APP1 --> DAPR
  APP2 --> DAPR
  DAPR --> STORAGE
  DAPR --> COSMOSDB
  SERVICEBUS --> KEDA
  KEDA --> APP3

Características Distintivas

Azure Container Apps se diferencia de otras soluciones de contenedores en Azure por:

  1. Optimización para microservicios: diseñado específicamente para aplicaciones que abarcan múltiples contenedores desplegados como servicios independientes

  2. Tecnologías open-source integradas:

  3. Dapr: service-to-service invocation, pub/sub, state management
  4. KEDA: escalado basado en eventos y métricas
  5. Envoy: balanceo de carga y observabilidad

  6. Arquitecturas event-driven: escalado basado en:

  7. Tráfico HTTP
  8. Mensajes en colas (Service Bus, Storage Queues, Event Hubs)
  9. Métricas personalizadas
  10. Escalado a cero para reducir costes

  11. Soporte para cargas de larga duración: procesos background, jobs y tareas programadas

Novedades 2024-2025: Lo que ha Cambiado

Desde el post original de 2022, Azure Container Apps ha incorporado capacidades empresariales significativas:

1. GPUs Serverless y Dedicadas (2024)

Serverless GPUs disponibles en regiones West US 3, Australia East y Sweden Central:

  • NVIDIA T4: coste-efectivas para inferencia de modelos pequeños (<10GB)
  • NVIDIA A100: para modelos grandes (>10GB), training, y cargas computacionales intensivas

Dedicated GPU workload profiles:

  • Perfiles NC24-A100, NC48-A100, NC96-A100
  • Aislamiento garantizado con hardware dedicado
  • Ideal para cargas de IA/ML continuas con baja latencia
# Ejemplo: Crear environment con GPU serverless
az containerapp env create \
  --name my-gpu-environment \
  --resource-group my-rg \
  --location westus3 \
  --enable-workload-profiles

# Desplegar app con GPU T4
az containerapp create \
  --name my-ai-app \
  --resource-group my-rg \
  --environment my-gpu-environment \
  --image myregistry.azurecr.io/ml-inference:latest \
  --cpu 8 --memory 56Gi \
  --workload-profile-name Consumption-GPU-NC8as-T4 \
  --target-port 8080 \
  --ingress external

2. Dynamic Sessions (Preview - 2024)

Ejecución segura y aislada de código generado por IA, ideal para:

  • Sandboxing de código no confiable
  • Evaluación de código generado por LLMs
  • Agentes de IA que ejecutan código dinámicamente

Características:

  • Aislamiento completo mediante Hyper-V
  • Contenedores gestionados (Python, Node.js) o personalizados
  • Escalado rápido y efímero

3. Azure Functions en Container Apps (GA - 2024)

Despliegue de Azure Functions como contenedores dentro de Container Apps:

  • Todos los triggers de Functions disponibles
  • Escalado basado en KEDA
  • Compartir infraestructura con microservicios y APIs
  • Soporte para GPUs en funciones compute-intensive
# Crear Function App optimizada para Container Apps
az containerapp create \
  --name my-function-app \
  --resource-group my-rg \
  --environment my-environment \
  --image myregistry.azurecr.io/my-functions:latest \
  --kind functionapp \
  --ingress external \
  --target-port 80

4. Workload Profiles Mejorados

Consumption Profile (por defecto):

  • Escalado automático
  • Pago solo por uso activo
  • Hasta 4 vCPU / 8 GiB memoria por réplica

Dedicated Profiles (opcionales):

  • General purpose (D4, D8, D16, D32)
  • Memory optimized (E4, E8, E16, E32)
  • GPU enabled (NC24-A100, NC48-A100, NC96-A100)

5. Networking y Seguridad Avanzada

  • Private Endpoints: acceso privado sin exposición pública
  • User Defined Routes (UDR): control total del tráfico de salida
  • NAT Gateway integration: simplifica conectividad saliente
  • Azure Front Door integration: CDN y WAF con Private Link
  • Client certificate authentication (mTLS): autenticación mutua TLS

6. Certificados Gestionados y Key Vault (GA - 2024)

  • Certificados TLS gratuitos gestionados automáticamente
  • Integración con Azure Key Vault para certificados personalizados
  • Renovación automática

7. Componentes Java Gestionados (Preview - 2024)

Para aplicaciones Spring:

  • Eureka Server: service discovery gestionado
  • Config Server: configuración centralizada
  • Tomcat support: despliegue directo desde código
  • JVM memory fit: configuración automática de memoria JVM

8. Observabilidad Mejorada

  • OpenTelemetry Agent (Preview): exportación de métricas, logs y traces sin configurar colector
  • Aspire Dashboard (Preview): dashboard interactivo para aplicaciones .NET
  • Java metrics: métricas de garbage collection, memoria, threads
  • Integración completa con Azure Monitor y Application Insights

Comparativa: ¿Cuándo Usar Container Apps?

Servicio Caso de Uso Ideal
Azure Container Apps Microservicios, APIs, event-driven apps, cargas AI/ML serverless, aplicaciones con escalado a cero
Azure Kubernetes Service (AKS) Control total de Kubernetes API, workloads complejos con requisitos específicos de K8s
Azure Red Hat OpenShift Despliegue OpenShift gestionado, migración desde on-premises OpenShift
Azure Functions Funciones FaaS puras, integraciones rápidas con triggers Azure, sin contenedores
Web App for Containers Aplicaciones web en contenedores Windows/Linux, migración lift-and-shift
Container Instances Contenedores de corta duración, batch jobs simples, aislamiento por hipervisor
Service Fabric Aplicaciones distribuidas legacy, necesidad de reliable services/actors
Container Registry Almacenamiento, gestión y replicación de imágenes de contenedor

Diagrama de Decisión Simplificado

flowchart TD
  START["¿Necesitas ejecutar contenedores?"]
  START --> K8S_API{"¿Necesitas acceso directo a Kubernetes API?"}

  K8S_API -->|Sí| AKS["Azure Kubernetes Service (AKS)"]
  K8S_API -->|No| SERVERLESS{"¿Prefieres serverless con escalado a cero?"}

  SERVERLESS -->|Sí| MICROSERVICES{"¿Es una arquitectura de microservicios / API?"}
  SERVERLESS -->|No| DEDICATED{"¿Necesitas hardware dedicado/GPU?"}

  MICROSERVICES -->|Sí| ACA["✅ Azure Container Apps"]
  MICROSERVICES -->|No| FUNCTIONS{"¿Solo funciones event-driven?"}

  FUNCTIONS -->|Sí| AZFUNC["Azure Functions"]
  FUNCTIONS -->|No| ACA2["✅ Azure Container Apps"]

  DEDICATED -->|Sí| ACA_DEDICATED["✅ Azure Container Apps
(Dedicated Workload Profiles)"] DEDICATED -->|No| WEBAPP["Web App for Containers"]

Casos de Uso Prácticos

1. Aplicación de IA Generativa con RAG

Implementar un chatbot con Retrieval Augmented Generation:

  • Frontend: contenedor React/Vue en Container App con ingress externo
  • API Gateway: contenedor .NET/Java con autenticación Entra ID
  • RAG Service: contenedor Python con GPU T4 para embeddings y inference
  • Vector Store: Cosmos DB con búsqueda vectorial
  • Escalado basado en peticiones HTTP, escala a cero en inactividad

2. Procesamiento de Eventos IoT

Pipeline de procesamiento de telemetría:

  • Ingestion: Container App escalando con Event Hubs (KEDA scaler)
  • Processing: múltiples Container Apps para transformación, enriquecimiento
  • Storage: escritura en Azure Storage / Cosmos DB mediante Dapr
  • Escalado automático según volumen de mensajes

3. Microservicios con Dapr

Arquitectura de e-commerce:

  • Catalog Service: gestión de productos
  • Order Service: procesamiento de pedidos
  • Inventory Service: control de stock
  • Payment Service: integración con pasarelas de pago

Comunicación via Dapr service invocation, state management en Redis/Cosmos DB, pub/sub con Service Bus.

4. Jobs Programados y Batch Processing

  • Jobs en Container Apps para tareas programadas (cron)
  • Procesamiento de archivos cargados en Storage
  • Generación de informes nocturnos
  • Limpieza de datos y mantenimiento

Despliegue: Ejemplos Prácticos

Despliegue Rápido con Azure CLI

# Variables
RESOURCE_GROUP="my-container-apps-rg"
LOCATION="westeurope"
ENVIRONMENT="my-environment"
APP_NAME="my-api"

# Crear resource group
az group create --name $RESOURCE_GROUP --location $LOCATION

# Crear environment
az containerapp env create \
  --name $ENVIRONMENT \
  --resource-group $RESOURCE_GROUP \
  --location $LOCATION

# Desplegar desde imagen pública
az containerapp create \
  --name $APP_NAME \
  --resource-group $RESOURCE_GROUP \
  --environment $ENVIRONMENT \
  --image mcr.microsoft.com/k8se/quickstart:latest \
  --target-port 80 \
  --ingress external \
  --min-replicas 0 \
  --max-replicas 10

Despliegue con Bicep

param location string = resourceGroup().location
param environmentName string = 'my-environment'
param containerAppName string = 'my-api'
param containerImage string = 'mcr.microsoft.com/k8se/quickstart:latest'

resource environment 'Microsoft.App/managedEnvironments@2023-05-01' = {
  name: environmentName
  location: location
  properties: {
    appLogsConfiguration: {
      destination: 'log-analytics'
      logAnalyticsConfiguration: {
        customerId: logAnalytics.properties.customerId
        sharedKey: logAnalytics.listKeys().primarySharedKey
      }
    }
  }
}

resource containerApp 'Microsoft.App/containerApps@2023-05-01' = {
  name: containerAppName
  location: location
  properties: {
    managedEnvironmentId: environment.id
    configuration: {
      ingress: {
        external: true
        targetPort: 80
        transport: 'auto'
      }
    }
    template: {
      containers: [
        {
          name: 'main'
          image: containerImage
          resources: {
            cpu: json('0.5')
            memory: '1Gi'
          }
        }
      ]
      scale: {
        minReplicas: 0
        maxReplicas: 10
        rules: [
          {
            name: 'http-rule'
            http: {
              metadata: {
                concurrentRequests: '100'
              }
            }
          }
        ]
      }
    }
  }
}

resource logAnalytics 'Microsoft.OperationalInsights/workspaces@2022-10-01' = {
  name: '${environmentName}-logs'
  location: location
  properties: {
    sku: {
      name: 'PerGB2018'
    }
  }
}

Despliegue con Dapr Habilitado

# Crear app con Dapr
az containerapp create \
  --name order-service \
  --resource-group $RESOURCE_GROUP \
  --environment $ENVIRONMENT \
  --image myregistry.azurecr.io/order-service:v1 \
  --target-port 3000 \
  --ingress internal \
  --min-replicas 1 \
  --enable-dapr \
  --dapr-app-id order-service \
  --dapr-app-port 3000 \
  --dapr-app-protocol http

# Invocar otro servicio via Dapr
# Desde código: http://localhost:3500/v1.0/invoke/inventory-service/method/check-stock

Administración del Ciclo de Vida: Revisiones

Una de las características más potentes de Container Apps son las revisiones (revisions):

  • Cada cambio en la configuración o imagen crea una nueva revisión
  • Múltiples revisiones activas simultáneamente
  • Traffic splitting: distribuir tráfico entre revisiones (A/B testing, blue/green)
  • Labels: asignar etiquetas (blue, green, canary) para URLs estables

Ejemplo: Blue/Green Deployment

# Desplegar revisión "blue" (producción actual)
az containerapp create \
  --name $APP_NAME \
  --resource-group $RESOURCE_GROUP \
  --environment $ENVIRONMENT \
  --image myregistry.azurecr.io/myapp:v1.0 \
  --revision-suffix blue \
  --ingress external \
  --target-port 80 \
  --revisions-mode multiple

# Fijar 100% tráfico a blue
az containerapp ingress traffic set \
  --name $APP_NAME \
  --resource-group $RESOURCE_GROUP \
  --revision-weight $APP_NAME--blue=100

# Asignar label "blue"
az containerapp revision label add \
  --name $APP_NAME \
  --resource-group $RESOURCE_GROUP \
  --label blue \
  --revision $APP_NAME--blue

# Desplegar revisión "green" (nueva versión)
az containerapp update \
  --name $APP_NAME \
  --resource-group $RESOURCE_GROUP \
  --image myregistry.azurecr.io/myapp:v2.0 \
  --revision-suffix green

# Probar green en URL específica: https://my-app---green.<environment-domain>

# Traffic splitting progresivo: 80% blue, 20% green
az containerapp ingress traffic set \
  --name $APP_NAME \
  --resource-group $RESOURCE_GROUP \
  --revision-weight $APP_NAME--blue=80 $APP_NAME--green=20

# Si green funciona bien, cambiar 100% a green
az containerapp ingress traffic set \
  --name $APP_NAME \
  --resource-group $RESOURCE_GROUP \
  --revision-weight $APP_NAME--green=100

# Desactivar revisión blue
az containerapp revision deactivate \
  --name $APP_NAME \
  --resource-group $RESOURCE_GROUP \
  --revision $APP_NAME--blue

Networking: Opciones y Escenarios

Niveles de Accesibilidad

  1. External ingress: aplicación accesible desde Internet
  2. Internal ingress: solo accesible dentro del environment o VNet
  3. No ingress: para background workers o jobs

Integración con VNet

# Crear environment con VNet personalizada
az containerapp env create \
  --name $ENVIRONMENT \
  --resource-group $RESOURCE_GROUP \
  --location $LOCATION \
  --infrastructure-subnet-resource-id /subscriptions/.../subnets/aca-subnet \
  --internal-only false

# Subnet mínimo: /27 (para workload profiles)
# Subnet mínimo: /23 (para consumption only)

Private Endpoints

# Crear environment con private endpoint
az containerapp env create \
  --name $ENVIRONMENT \
  --resource-group $RESOURCE_GROUP \
  --location $LOCATION \
  --enable-workload-profiles \
  --public-network-access Disabled

# Crear private endpoint
az network private-endpoint create \
  --name my-private-endpoint \
  --resource-group $RESOURCE_GROUP \
  --vnet-name my-vnet \
  --subnet my-subnet \
  --private-connection-resource-id /subscriptions/.../managedEnvironments/$ENVIRONMENT \
  --group-id managedEnvironment \
  --connection-name my-connection

Observabilidad y Monitorización

Integración con Azure Monitor

Container Apps se integra automáticamente con:

  • Log Analytics: logs de contenedor, system logs
  • Application Insights: telemetría de aplicaciones, distributed tracing
  • Metrics: CPU, memoria, peticiones HTTP, réplicas activas
# Habilitar Application Insights
az containerapp env create \
  --name $ENVIRONMENT \
  --resource-group $RESOURCE_GROUP \
  --location $LOCATION \
  --logs-workspace-id <LOG_ANALYTICS_WORKSPACE_ID> \
  --logs-workspace-key <LOG_ANALYTICS_WORKSPACE_KEY>

Consultas Útiles en Log Analytics

// Logs de aplicación
ContainerAppConsoleLogs_CL
| where ContainerAppName_s == "my-api"
| where TimeGenerated > ago(1h)
| project TimeGenerated, Log_s
| order by TimeGenerated desc

// Métricas de réplicas
ContainerAppSystemLogs_CL
| where Category == "ContainerAppScaling"
| where ContainerAppName_s == "my-api"
| project TimeGenerated, ReplicaCount_d
| render timechart

OpenTelemetry (Preview)

# Habilitar agente OpenTelemetry
az containerapp env telemetry app-insights set \
  --name $ENVIRONMENT \
  --resource-group $RESOURCE_GROUP \
  --connection-string "InstrumentationKey=...;IngestionEndpoint=..."

# Las apps envían automáticamente traces, metrics y logs a App Insights

Costes y Optimización

Modelo de Facturación

Consumption Plan:

  • Consumo activo: vCPU-segundos y GiB-segundos consumidos
  • Consumo idle: tarifa reducida cuando réplicas están idle (no procesando, <0.01 vCPU, <1KB/s red)
  • Requests: primeros 2 millones gratis/mes, luego por millón adicional
  • GPUs serverless: sin cargo por idle, solo por uso activo

Dedicated Plan (workload profiles):

  • Cargo fijo por gestión del plan si usas perfiles dedicados
  • Cargo por instancia de perfil (D4, E8, NC24-A100, etc.)
  • Escalado in/out ajusta coste según demanda

Estrategias de Optimización

  1. Escala a cero: configura minReplicas: 0 para apps con tráfico intermitente
  2. Right-sizing: ajusta CPU/memoria a necesidades reales
  3. Workload profiles: agrupa apps similares en el mismo perfil dedicado
  4. Savings Plans: Azure Container Apps elegible para planes de ahorro
  5. GPUs serverless: para cargas AI/ML variables, usa serverless en lugar de dedicado
# Configurar escalado a cero
az containerapp update \
  --name $APP_NAME \
  --resource-group $RESOURCE_GROUP \
  --min-replicas 0 \
  --max-replicas 10 \
  --scale-rule-name http-rule \
  --scale-rule-type http \
  --scale-rule-metadata concurrentRequests=50

Seguridad: Mejores Prácticas

1. Managed Identities

# Habilitar system-assigned identity
az containerapp identity assign \
  --name $APP_NAME \
  --resource-group $RESOURCE_GROUP \
  --system-assigned

# Asignar rol para acceder a Key Vault
IDENTITY_ID=$(az containerapp identity show \
  --name $APP_NAME \
  --resource-group $RESOURCE_GROUP \
  --query principalId -o tsv)

az keyvault set-policy \
  --name my-keyvault \
  --object-id $IDENTITY_ID \
  --secret-permissions get list

2. Secretos

# Añadir secreto
az containerapp secret set \
  --name $APP_NAME \
  --resource-group $RESOURCE_GROUP \
  --secrets db-connection="Server=...;Password=..."

# Referenciar en variable de entorno
az containerapp update \
  --name $APP_NAME \
  --resource-group $RESOURCE_GROUP \
  --set-env-vars "DB_CONNECTION=secretref:db-connection"

3. Autenticación Built-in (EasyAuth)

# Habilitar autenticación con Entra ID
az containerapp auth update \
  --name $APP_NAME \
  --resource-group $RESOURCE_GROUP \
  --enable \
  --action RequireAuthentication \
  --aad-tenant-id <TENANT_ID> \
  --aad-client-id <CLIENT_ID> \
  --aad-client-secret <CLIENT_SECRET>

4. Restricciones de IP

# Limitar acceso por IP
az containerapp ingress access-restriction set \
  --name $APP_NAME \
  --resource-group $RESOURCE_GROUP \
  --rule-name office-network \
  --ip-address 203.0.113.0/24 \
  --action Allow

Conclusión

Azure Container Apps en 2025 es una plataforma madura y completa para ejecutar aplicaciones Cloud Native sin la complejidad de gestionar Kubernetes directamente. Con las incorporaciones de 2024-2025, se ha convertido en una opción viable para:

  • Microservicios y APIs: escalado automático, revisiones, traffic splitting
  • Event-driven architectures: integración con KEDA y múltiples event sources
  • Cargas AI/ML: GPUs serverless y dedicadas, Dynamic Sessions
  • Aplicaciones empresariales: networking avanzado, private endpoints, integración con Azure Functions

¿Cuándo Elegir Container Apps?

, si:

  • Quieres serverless con escalado a cero
  • Necesitas desplegar microservicios o APIs rápidamente
  • Prefieres no gestionar Kubernetes directamente
  • Quieres integración nativa con Dapr, KEDA, Envoy
  • Necesitas GPUs para cargas AI/ML con tráfico variable

No, si:

  • Necesitas acceso completo a Kubernetes API y CRDs
  • Tienes requisitos muy específicos de configuración de K8s
  • Ya tienes inversión significativa en operadores y herramientas K8s personalizadas

En resumen: si no necesitas acceso directo a Kubernetes API y trabajas con aplicaciones Cloud Native, Azure Container Apps es tu servicio en Azure.

Referencias y Recursos


Artículo actualizado en octubre de 2025. Para la versión original de 2022, ver Introducción a Azure Container Apps (Keepler Blog).

20251020 azure service bus mensajeria

Resumen

Azure Service Bus es el servicio de mensajería empresarial de Azure. Permite desacoplar aplicaciones y servicios mediante colas y topics, ideal para arquitecturas distribuidas y microservicios. Este post va directo a admins y DevOps que necesitan integrar sistemas de forma fiable y segura.

¿Qué es Azure Service Bus?

Azure Service Bus es un servicio PaaS de mensajería que ofrece:

  • Colas (Queues) para comunicación punto a punto
  • Topics y subscriptions para pub/sub
  • Entrega garantizada y ordenada
  • Soporte para mensajes transaccionales y sesiones
  • Integración con RBAC y Managed Identities

Arquitectura / Cómo funciona

flowchart LR
  App1[Productor] -- Envia mensaje --> SB[Service Bus Queue]
  SB -- Recibe mensaje --> App2[Consumidor]
  SB -. Dead-letter .-> DLQ[Dead Letter Queue]
  • El productor envía mensajes a la cola
  • El consumidor los procesa de forma asíncrona
  • Mensajes fallidos van a la Dead Letter Queue

Uso práctico: crear y usar una cola

1. Crear un Service Bus Namespace y una cola

# Variables
RESOURCE_GROUP="my-rg"
LOCATION="westeurope"
SB_NAMESPACE="my-sb-namespace"
QUEUE="myqueue"

# Crear namespace
az servicebus namespace create \
  --resource-group $RESOURCE_GROUP \
  --name $SB_NAMESPACE \
  --location $LOCATION

# Crear cola
az servicebus queue create \
  --resource-group $RESOURCE_GROUP \
  --namespace-name $SB_NAMESPACE \
  --name $QUEUE

2. Enviar y recibir mensajes (Python, passwordless recomendado)

import asyncio
from azure.servicebus.aio import ServiceBusClient
from azure.servicebus import ServiceBusMessage
from azure.identity.aio import DefaultAzureCredential

FULLY_QUALIFIED_NAMESPACE = "<namespace>.servicebus.windows.net"
QUEUE_NAME = "myqueue"

async def send_message():
  credential = DefaultAzureCredential()
  async with ServiceBusClient(FULLY_QUALIFIED_NAMESPACE, credential) as client:
    sender = client.get_queue_sender(QUEUE_NAME)
    async with sender:
      msg = ServiceBusMessage("Hola Azure Service Bus!")
      await sender.send_messages(msg)
    await credential.close()

async def receive_message():
  credential = DefaultAzureCredential()
  async with ServiceBusClient(FULLY_QUALIFIED_NAMESPACE, credential) as client:
    receiver = client.get_queue_receiver(QUEUE_NAME)
    async with receiver:
      async for msg in receiver:
        print("Mensaje recibido:", str(msg))
        await receiver.complete_message(msg)
    await credential.close()

# Ejecutar
asyncio.run(send_message())
asyncio.run(receive_message())

Más detalles y ejemplos oficiales:

Buenas prácticas / Seguridad

  • Usa Managed Identities en vez de connection strings
  • Activa el cifrado con claves gestionadas por el cliente (CMK) si es necesario
  • Configura reglas de red y firewall
  • Usa colas de dead-letter para mensajes no procesables
  • Monitoriza con Azure Monitor y alertas

Referencias