Skip to content

2025/10

Resumen

Voy al grano: Azure Cosmos DB for MongoDB vCore es MongoDB real en Azure, con arquitectura vCore (CPU + RAM) que escala vertical y horizontalmente sin downtime. Soporte nativo para vector search (DiskANN), sharding automático y 99.99% SLA con HA activado. Ideal para lift & shift de aplicaciones MongoDB existentes o nuevas apps que necesiten queries complejas, aggregations y transacciones distribuidas.

Azure Virtual Network Manager: Gestión centralizada de redes

Resumen

Voy al grano: Azure Virtual Network Manager (AVNM) centraliza la gestión de conectividad y seguridad de cientos o miles de VNets desde un solo panel. Creas topologías hub-spoke o mesh con clicks, defines security admin rules que se evalúan antes que los NSGs, y despliegas cambios por regiones de forma controlada. Sin scripts custom, sin gestionar peerings manualmente.

Azure Deployment Environments: Self-service para desarrolladores

Resumen

Voy al grano: 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).

Cómo Resolver Divergencias en Git: Sincronizando Ramas Local y Remota

El Problema

Al intentar hacer git pull, te encuentras con el siguiente error:

hint: You have divergent branches and need to specify how to reconcile them.
hint: You can do so by running one of the following commands sometime before
hint: your next pull:
hint: 
hint:   git config pull.rebase false  # merge
hint:   git config pull.rebase true   # rebase
hint:   git config pull.ff only       # fast-forward only

Este mensaje indica que tu rama local y la rama remota han divergido: ambas tienen commits únicos que la otra no tiene. Git necesita que decidas cómo combinar estos cambios.

¿Por Qué Ocurre?

La divergencia sucede cuando:

  1. Trabajas localmente y realizas commits en tu rama main
  2. Mientras tanto, cambios se fusionan en el remoto (por ejemplo, a través de Pull Requests)
  3. Ambas ramas tienen commits exclusivos que la otra no posee

Ejemplo visual:

Local:   A---B---C---L1
                      ^(tu commit local)
Remote:  A---B---C---R1---R2---R3
                      ^(commits del remoto vía PR)

Análisis: Identificar la Divergencia

Antes de resolver, es crucial entender qué ha divergido.

Paso 1: Sincronizar con el Remoto

git fetch origin main --tags

Este comando descarga los cambios del remoto sin fusionarlos.

Paso 2: Comparar Commits

Verifica qué commits están únicamente en cada lado:

# Commits que tienes localmente pero no están en el remoto
git log origin/main..main --oneline

# Commits que están en el remoto pero no tienes localmente
git log main..origin/main --oneline

Paso 3: Revisar los HEADs

# Ver el commit actual local
git rev-parse HEAD

# Ver el commit actual remoto
git rev-parse origin/main

Ejemplo Real

En nuestro caso, obtuvimos:

--- Commits en local, no en remoto ---
81e3b93 feat: add new feature for data processing

--- Commits en remoto, no en local ---
9d3e3e9 Merge pull request #42 from team/feature/update-docs
285a538 Complete documentation review - all documents validated
000b9cb Fix configuration and add new parameters
a7694d3 Initial implementation plan

Interpretación: El remoto tiene un PR fusionado con 4 commits que no tenemos localmente, y nosotros tenemos 1 commit local que el remoto no tiene.

Estrategias de Resolución

Existen tres estrategias principales:

1. Merge (Recomendado para Trabajo Colaborativo)

Cuándo usarlo: Cuando trabajas con un equipo y quieres preservar toda la historia, incluyendo los merge commits de PRs.

Ventajas: - ✅ Preserva la historia completa (incluidos merge commits) - ✅ Muestra claramente cuándo se integraron features - ✅ Más seguro: no reescribe historia

Desventajas: - ⚠️ Crea un commit de merge adicional - ⚠️ Historia no completamente lineal

Comando:

git merge origin/main --no-edit

Si prefieres revisar/editar el mensaje de merge:

git merge origin/main

2. Rebase (Para Historia Lineal)

Cuándo usarlo: Cuando trabajas solo o en una feature branch que aún no has compartido públicamente.

Ventajas: - ✅ Historia completamente lineal - ✅ Más limpia para revisar con git log

Desventajas: - ⚠️ Reescribe commits locales (cambian sus SHAs) - ⚠️ Puede causar problemas si ya compartiste estos commits - ⚠️ Pierdes el contexto de cuándo se integró el PR remoto

Comando:

git rebase origin/main

3. Fast-Forward Only (Restrictivo)

Cuándo usarlo: Cuando quieres asegurarte de que solo hagas pull si no hay divergencia.

Comando:

git config pull.ff only
git pull

Si hay divergencia, fallará y tendrás que decidir merge o rebase manualmente.

Solución Paso a Paso (Merge)

1. Analizar la Situación

# Sincronizar con remoto
git fetch origin main --tags

# Ver divergencias
echo "--- Commits locales únicos ---"
git log origin/main..main --oneline

echo "--- Commits remotos únicos ---"
git log main..origin/main --oneline

2. Decidir Estrategia

Para equipos colaborativos con PRs, merge es la opción más segura:

git merge origin/main --no-edit

3. Resolver Conflictos (Si Ocurren)

Si hay conflictos, Git te lo indicará:

Auto-merging some-file.md
CONFLICT (content): Merge conflict in some-file.md
Automatic merge failed; fix conflicts and then commit the result.

Pasos para resolver:

a) Abre el archivo con conflictos:

<<<<<<< HEAD
Tu versión local
=======
Versión del remoto
>>>>>>> origin/main

b) Edita manualmente para quedarte con el contenido correcto

c) Marca como resuelto:

git add some-file.md

d) Completa el merge:

git commit -m "Merge origin/main into main"

4. Verificar el Resultado

# Ver el log reciente
git log --oneline --graph -10

Deberías ver algo como:

*   3e1ed57 (HEAD -> main) Merge remote-tracking branch 'origin/main' into main
|\  
| * 9d3e3e9 (origin/main) Merge pull request #42
| * 285a538 Complete documentation review
| * 000b9cb Fix configuration parameters
| * a7694d3 Initial implementation plan
* | 81e3b93 feat: add new feature for data processing
|/  
* d140dce feat: improved monthly workflow

5. Empujar los Cambios

git push origin main

Salida esperada:

Enumerating objects: 15, done.
Counting objects: 100% (12/12), done.
Delta compression using up to 8 threads
Compressing objects: 100% (7/7), done.
Writing objects: 100% (7/7), 1.08 KiB | 1.08 MiB/s, done.
Total 7 (delta 5), reused 0 (delta 0)
remote: Resolving deltas: 100% (5/5), completed with 4 local objects.
To https://github.com/tu-usuario/tu-repositorio.git
   9d3e3e9..3e1ed57  main -> main

Verificación Post-Merge

Comprobar Archivos Críticos

Si tienes workflows de CI/CD u otros archivos críticos, verifica su integridad:

# Buscar un patrón específico en un archivo
grep -n "specific_pattern" .github/workflows/deploy.yml

# O leer el archivo completo
cat .github/workflows/deploy.yml

Confirmar Sincronización

# Ambos deberían apuntar al mismo commit ahora
git rev-parse HEAD
git rev-parse origin/main

Configuración Permanente

Si quieres establecer una estrategia por defecto para futuros git pull:

Para Merge (Recomendado)

git config pull.rebase false

Para Rebase

git config pull.rebase true

Global (Todos tus Repos)

Añade --global:

git config --global pull.rebase false

Mejores Prácticas

✅ Hacer Fetch Frecuentemente

# Ejecutar cada mañana o antes de empezar a trabajar
git fetch origin

Esto te mantiene informado de cambios remotos sin afectar tu trabajo local.

✅ Trabajar en Feature Branches

En lugar de trabajar directamente en main:

git checkout -b feature/my-feature
# ... hacer commits ...
git push origin feature/my-feature
# Abrir PR en GitHub

Esto evita divergencias en main.

✅ Pull Antes de Push

git fetch origin
git status
# Si hay cambios remotos, decide merge o rebase
git pull
# Ahora puedes pushear
git push

⚠️ Evitar Force Push en Ramas Compartidas

# ❌ NUNCA en main compartido
git push --force origin main

# ✅ OK solo en tus feature branches
git push --force origin feature/my-feature

Casos Especiales

Si Hiciste Rebase por Error y Quieres Revertir

# Ver el reflog (historial de cambios de HEAD)
git reflog

# Volver a un estado anterior
git reset --hard HEAD@{2}

Si Quieres Descartar Tus Commits Locales

# ⚠️ CUIDADO: Esto descarta tus commits locales permanentemente
git reset --hard origin/main

Si Quieres Preservar Cambios Locales Sin Commit

# Guardar cambios temporalmente
git stash

# Sincronizar con remoto
git pull

# Recuperar tus cambios
git stash pop

Resumen: Checklist Rápido

  • Fetch: git fetch origin main --tags
  • Analizar: git log origin/main..main --oneline y git log main..origin/main --oneline
  • Decidir: Merge (preservar historia) vs Rebase (lineal)
  • Ejecutar: git merge origin/main o git rebase origin/main
  • Resolver: Conflictos si los hay
  • Verificar: git log --graph --oneline -10
  • Push: git push origin main
  • Confirmar: Archivos críticos intactos

Conclusión

La divergencia de ramas es un escenario común en equipos colaborativos. La clave está en:

  1. Entender qué ha divergido (análisis con git log)
  2. Elegir la estrategia correcta (merge para equipos, rebase para trabajo local)
  3. Verificar el resultado antes de hacer push

En entornos colaborativos con Pull Requests, merge es generalmente la opción más segura ya que preserva la historia completa y evita reescribir commits que otros pueden estar usando como base.


Referencias

Power BI On-Premises Data Gateway: guía práctica (instalación estándar)

Resumen

Esta entrada explica de forma práctica qué es el Power BI On-Premises Data Gateway Standard, su arquitectura básica, y cómo realizar una instalación estándar y configurarlo para refrescos y conexiones seguras desde el servicio de Power BI. Está orientada a administradores y responsables de plataforma que necesiten conectar fuentes de datos locales a Power BI sin usar soluciones de red avanzadas (no cubre la instalación en Virtual Network Data Gateway ni escenarios sovereign).

¿Qué es el On-Premises Data Gateway?

El On-Premises Data Gateway es un componente que actúa como puente entre los servicios cloud de Microsoft (por ejemplo, Power BI, Power Automate, Power Apps) y tus datos que residen en la red local o en entornos no accesibles públicamente. Proporciona un canal saliente seguro (TLS) para permitir conexiones desde la nube hacia los orígenes de datos on‑premises sin abrir puertos entrantes en tu red.

Principales funciones: - Habilitar refrescos programados de datasets de Power BI. - Soportar consultas en vivo (DirectQuery/Live Connection) hacia orígenes compatibles. - Permitir que flujos y aplicaciones en cloud accedan a bases de datos y servicios internos.

Arquitectura básica

  • Gateway instalado en uno o varios servidores dentro de la red local.
  • El servicio gateway establece conexiones salientes a los endpoints de Microsoft (no requiere inbound).
  • En producción, se recomienda desplegar gateways en modo cluster (alta disponibilidad) y definir data sources centralizados en el panel de administración de Power BI.

Diagrama (simplificado)

flowchart LR
  PB["Power BI Service"]
  AZ["Azure Relay / Service Bus"]
  GW["On-Premises Gateway"]
  DB["Origen de datos"]  
  DB --> GW
  GW --> | TLS saliente | AZ 
  AZ --> PB

Arquitectura: Gateway en cluster (alta disponibilidad)

flowchart LR
  subgraph Cloud["Servicio Cloud"]
    PB["Power BI Service"]
  end

  subgraph Cluster["Cluster de Gateways (HA)"]
    GW1["Gateway - Nodo 1"]
    GW2["Gateway - Nodo 2"]
    GW3["Gateway - Nodo N"]
  end

  subgraph OnPrem["Red On-Premises"]
    DB["(Origen de datos)"]
  end
  AZ["Azure Relay / Service Bus"]


  GW1 --- GW2
  GW2 --- GW3
  AZ --> PB
  Cluster --> | TLS saliente | AZ
  DB --> Cluster


Note

Físicamente el Gateway establece conexiones salientes TLS hacia los servicios de Azure (Azure Service Bus / Azure Relay). Las solicitudes brokered se mantienen gracias a las conexiones salientes iniciadas por el gateway.

Instalación (instalación estándar)

Los pasos siguientes describen una instalación típica y segura de un Gateway estándar:

  1. Descargar el instalador oficial
  2. Descargar el instalador del gateway desde el sitio oficial de Microsoft.

  3. Ejecutar el instalador en el servidor destinado

  4. Ejecuta el instalador con privilegios de administrador.
  5. Acepta los términos y elige la instalación estándar cuando se solicite.

  6. Iniciar sesión y registrar el gateway

  7. Al finalizar la instalación se abrirá un asistente que solicita iniciar sesión con una cuenta organizativa (Entra ID).
  8. Registra el gateway en tu tenant y proporciona un nombre descriptivo para el gateway.

  9. Definir la clave de recuperación

  10. El asistente pedirá que crees una "recovery key". Guárdala en un lugar seguro: es necesaria para migrar o restaurar el gateway.

  11. Elegir cuenta de servicio (opcional)

  12. Puedes ejecutar el servicio con la cuenta de sistema local por defecto o configurar una cuenta de dominio/service account con los permisos mínimos necesarios para acceder a los orígenes de datos.

  13. Verificar conectividad

  14. Asegúrate de que el servidor puede establecer conexiones TLS salientes a los endpoints de Microsoft (comprobar reglas de firewall/proxy si existen).

  15. (Opcional) Agregar nodos al cluster

  16. Para alta disponibilidad, instala el gateway en otro servidor y en lugar de registrar un nuevo gateway selecciona unirte al cluster existente.

Configuración en el servicio Power BI

  1. Abrir el portal de Power BI y acceder a "Manage gateways" (Administrar gateways).
  2. Crear y/o revisar Data Sources dentro del gateway: especifica el tipo de origen (SQL Server, Analysis Services, etc.), cadena de conexión, y credenciales.
  3. En los datasets de Power BI: configurar el dataset para usar el gateway correspondiente y programar refrescos.
  4. Para DirectQuery/Live connection: asegúrate de que el data source esté correctamente configurado y que el usuario tenga permisos adecuados.

Consejos prácticos: - Centraliza la definición de data sources para facilitar el mantenimiento. - Usa credenciales de tipo "service principal" o cuentas administradas cuando el origen lo permita y por seguridad.

Buenas prácticas y seguridad

  • Alta disponibilidad: despliega gateways en cluster para evitar puntos únicos de fallo.
  • Mínimos privilegios: la cuenta que use el gateway solo debería tener los permisos necesarios en los orígenes de datos.
  • Key management: guarda la recovery key en un almacén seguro y documenta el proceso de recuperación.
  • Parches y mantenimiento: aplica actualizaciones del sistema operativo y del gateway según las políticas de tu organización.
  • Monitorización: habilita logs y métricas para detectar problemas de rendimiento y errores en los refrescos.
  • Red y firewall: permite únicamente el tráfico saliente necesario hacia los endpoints de Microsoft y evita abrir puertos entrantes.

Monitorización y diagnóstico

  • Revisa el panel de estado del gateway en Power BI Service para incidentes y estado de los nodos.
  • Examina los registros locales del gateway (ubicación estándar indicada por el instalador) para errores detallados.
  • Utiliza contadores de rendimiento (CPU, memoria, latencia de red) en el servidor para diagnosticar cuellos de botella.
  • Para problemas de refresco: revisa el historial de refrescos del dataset en Power BI y los detalles del error proporcionados por el servicio.

Referencias y lecturas recomendadas

  • Documentación oficial de Microsoft (Power BI - On-premises data gateway): https://learn.microsoft.com/power-bi/connect-data/service-gateway-onprem

Documentar con EPAC

EPAC tiene una opción muy útil llamada "Document All Assignments" que genera Markdown y CSV con todas las asignaciones de policy. Pero hay dos detalles importantes que conviene saber:

1) Antes no se podían excluir tipos enteros de scope (por ejemplo: todas las subscriptions o resourceGroups) desde la configuración.

2) He subido una PR para solucionarlo: https://github.com/Azure/enterprise-azure-policy-as-code/pull/1056

Aquí lo que cambia, rápido y claro.

Problema

Si usas documentAllAssignments y quieres evitar documentar todo lo que hay a nivel de suscripción o de resource groups, la versión anterior obligaba a listar cada id con skipPolicyAssignments o a procesar el CSV resultante. En entornos grandes eso resulta muy tedioso y genera mucho ruido en los informes.

Qué hace la PR #1056

  • Añade excludeScopeTypes en la configuración de documentAllAssignments. Con esto se puede indicar que no se documenten assignments que estén en subscriptions o en resourceGroups.
  • Añade StrictMode (switch) en los scripts. Por defecto está activado. Si lo desactivas (-StrictMode:$false) el script no aborta cuando falta alguna definición; registra avisos y continúa. Útil en pipelines de prueba.
  • Mejora el parsing y el manejo de skipPolicyAssignments/skipPolicyDefinitions (funcionan mejor con arrays u objetos) y corrige bugs menores (p. ej. convertir markdownMaxParameterLength a entero).

PR: https://github.com/Azure/enterprise-azure-policy-as-code/pull/1056

Antes / Después (ejemplo práctico)

Antes tenías que usar algo así:

{
  "documentAssignments": {
    "documentAllAssignments": [
      {
        "pacEnvironment": "EPAC-Prod",
        "skipPolicyAssignments": [],
        "skipPolicyDefinitions": ["/providers/.../policySetDefinitions/..."]
      }
    ]
  }
}

Después basta con añadir excludeScopeTypes:

{
  "documentAssignments": {
    "documentAllAssignments": [
      {
        "pacEnvironment": "EPAC-Prod",
        "excludeScopeTypes": ["subscriptions", "resourceGroups"],
        "skipPolicyAssignments": [],
        "skipPolicyDefinitions": ["/providers/.../policySetDefinitions/..."]
      }
    ]
  }
}

Y si quieres pruebas rápidas sin que el pipeline falle por referencias rotas:

./Build-PolicyDocumentation.ps1 -StrictMode:$false

Recomendaciones prácticas

  • Usa excludeScopeTypes para reducir ruido cuando necesites una vista global.
  • No confundas excludeScopeTypes con exemptions: esto solo evita que se documente; no evita que la policy se aplique. Para eso usa exemptions.
  • Mantén StrictMode activado en producción (ayuda a detectar referencias rotas).
  • Usa skipPolicyAssignments para exclusiones puntuales que conozcas por id.

Cierre

La mejora es pequeña pero práctica: menos limpieza manual, informes más útiles. Si quieres puedo:

  • Añadir un ejemplo real con IDs/outputs.
  • Hacer build local del sitio y comprobar cómo queda el Markdown final.

PR de referencia: https://github.com/Azure/enterprise-azure-policy-as-code/pull/1056