Skip to content

Azure Container Registry: Geo-replication y webhook automation

Resumen

Azure Container Registry (ACR) no es solo un registro Docker. Con geo-replication consigues latencia mínima global y con webhooks automatizas despliegues. Aquí el setup avanzado.

¿Cuándo usar ACR vs Docker Hub?

Usa ACR si: - ✅ Necesitas registry privado en Azure - ✅ Quieres integración nativa con AKS, App Service, Container Apps - ✅ Compliance requiere datos en región específica - ✅ Necesitas geo-replication

Usa Docker Hub si: - Imágenes públicas open source - Proyectos personales sin requisitos enterprise

Crear ACR con Premium SKU

# Variables
RG="my-rg"
ACR_NAME="myacr$(date +%s)"
LOCATION="westeurope"

# Crear ACR Premium (requerido para geo-replication)
az acr create \
  --resource-group $RG \
  --name $ACR_NAME \
  --sku Premium \
  --location $LOCATION \
  --admin-enabled false

SKUs disponibles: - Basic: €4.4/mes - Sin geo-replication, webhooks limitados - Standard: €22/mes - Webhooks, mejor throughput - Premium: €44/mes - Geo-replication, Content Trust, Private Link

Geo-replication

Replica tu registry a múltiples regiones para: - Reducir latencia de pull - Alta disponibilidad - Cumplir data residency

# Replicar a East US
az acr replication create \
  --resource-group $RG \
  --registry $ACR_NAME \
  --location eastus

# Replicar a Southeast Asia
az acr replication create \
  --resource-group $RG \
  --registry $ACR_NAME \
  --location southeastasia

# Listar réplicas
az acr replication list \
  --resource-group $RG \
  --registry $ACR_NAME \
  --output table

Ahora tu imagen myacr.azurecr.io/app:v1 está disponible en 3 regiones con un solo push.

Push de imágenes

# Login a ACR
az acr login --name $ACR_NAME

# Tag imagen
docker tag my-app:latest ${ACR_NAME}.azurecr.io/my-app:v1.0

# Push
docker push ${ACR_NAME}.azurecr.io/my-app:v1.0

# Listar imágenes
az acr repository list --name $ACR_NAME --output table

# Ver tags
az acr repository show-tags \
  --name $ACR_NAME \
  --repository my-app \
  --output table

ACR Tasks: Build en Azure

Build imágenes sin Docker local:

# Build desde Dockerfile en repo Git
az acr build \
  --resource-group $RG \
  --registry $ACR_NAME \
  --image my-app:{{.Run.ID}} \
  --image my-app:latest \
  https://github.com/myorg/myapp.git#main

# Build desde directorio local
az acr build \
  --resource-group $RG \
  --registry $ACR_NAME \
  --image my-app:v1.1 \
  .

Webhooks para CI/CD

Trigger despliegue automático cuando hay nuevo push:

# Crear webhook
az acr webhook create \
  --resource-group $RG \
  --registry $ACR_NAME \
  --name deployWebhook \
  --actions push \
  --uri https://my-function-app.azurewebsites.net/api/deploy \
  --scope my-app:*

Payload del webhook:

{
  "id": "unique-id",
  "timestamp": "2025-01-22T10:00:00Z",
  "action": "push",
  "target": {
    "mediaType": "application/vnd.docker.distribution.manifest.v2+json",
    "size": 1234,
    "digest": "sha256:abc123...",
    "repository": "my-app",
    "tag": "v1.2"
  },
  "request": {
    "id": "req-id",
    "host": "myacr.azurecr.io",
    "method": "PUT",
    "useragent": "docker/20.10.12"
  }
}

Azure Function para auto-deploy

import azure.functions as func
import json
import subprocess

def main(req: func.HttpRequest) -> func.HttpResponse:
    # Parse webhook payload
    webhook_data = req.get_json()

    repository = webhook_data['target']['repository']
    tag = webhook_data['target']['tag']
    image = f"myacr.azurecr.io/{repository}:{tag}"

    # Trigger deployment (ejemplo: kubectl)
    subprocess.run([
        'kubectl', 'set', 'image',
        'deployment/my-app',
        f'app={image}',
        '--record'
    ])

    return func.HttpResponse(f"Deployed {image}", status_code=200)

Security: Managed Identity

# Asignar managed identity a AKS
AKS_PRINCIPAL_ID=$(az aks show \
  --resource-group $RG \
  --name my-aks \
  --query identityProfile.kubeletidentity.objectId -o tsv)

# Dar permiso AcrPull
az role assignment create \
  --assignee $AKS_PRINCIPAL_ID \
  --role AcrPull \
  --scope $(az acr show --resource-group $RG --name $ACR_NAME --query id -o tsv)

Ahora AKS puede pullear sin passwords:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-app
spec:
  template:
    spec:
      containers:
      - name: app
        image: myacr.azurecr.io/my-app:v1.0
        # No imagePullSecrets needed!

Content Trust (image signing)

# Habilitar Content Trust
az acr config content-trust update \
  --resource-group $RG \
  --registry $ACR_NAME \
  --status enabled

# Docker content trust
export DOCKER_CONTENT_TRUST=1
export DOCKER_CONTENT_TRUST_SERVER=https://${ACR_NAME}.azurecr.io

# Push firmado
docker push ${ACR_NAME}.azurecr.io/my-app:v1.0-signed

Vulnerability scanning

# Habilitar Microsoft Defender for Container Registries
az security pricing create \
  --name ContainerRegistry \
  --tier Standard

# Ver vulnerabilidades
az acr repository show \
  --name $ACR_NAME \
  --repository my-app \
  --query "metadata.vulnerabilities"

Retention policy (cleanup automático)

# Retener solo últimos 30 días
az acr config retention update \
  --registry $ACR_NAME \
  --status enabled \
  --days 30 \
  --type UntaggedManifests

# Borrar tags viejos manualmente
az acr repository show-tags \
  --name $ACR_NAME \
  --repository my-app \
  --orderby time_asc \
  --output tsv \
  | head -n 10 \
  | xargs -I {} az acr repository delete \
      --name $ACR_NAME \
      --image my-app:{} \
      --yes

Import imágenes desde Docker Hub

# Importar imagen pública
az acr import \
  --name $ACR_NAME \
  --source docker.io/library/nginx:latest \
  --image nginx:latest

# Importar desde otro ACR
az acr import \
  --name $ACR_NAME \
  --source otheracr.azurecr.io/app:v1 \
  --image app:v1 \
  --username <user> \
  --password <password>

Buenas prácticas

  • Tagging strategy: Usa semver (v1.2.3) + latest + commit SHA
  • Multi-arch images: Build para amd64 y arm64
  • Scan antes de deploy: Integra vulnerability scanning en CI
  • Cleanup periódico: Retención de 30-90 días
  • Private endpoint: No expongas ACR a Internet
  • Geo-replication: Mínimo 2 regiones para producción

Costos

  • Storage: €0.08/GB/mes
  • Geo-replication: €44/mes por región
  • Build minutes: €0.0008/segundo

Ejemplo: ACR Premium + 50GB + 2 réplicas = ~€140/mes

Referencias