RO EN

Azure Container Apps (4) — CI/CD cu GitHub Actions

Azure Container Apps (4) — CI/CD cu GitHub Actions ✨ Imagine generată cu AI
Doru Bulubașa
06 iulie 2026
42 vizualizări

Ultima parte din seria despre Azure Container Apps. Am acoperit de ce, configurarea și scaling, și Dapr. Aici legăm totul cu un pipeline complet de deployment automat.


Autentificare fără secrete: OIDC

Consistent cu tot ce am construit în serie, nici pipeline-ul de CI/CD nu trebuie să stocheze secrete. În loc de un service principal cu client secret pus în GitHub Secrets, folosim OIDC (OpenID Connect) cu federated credentials: GitHub Actions primește un token temporar de la Azure la fiecare rulare, fără nicio credențială stocată.

Configurarea federated credential

# Creeaza un app registration (sau foloseste unul existent)
APP_ID=$(az ad app create --display-name "github-actions-my-api" --query appId -o tsv)

az ad sp create --id $APP_ID

# Federated credential legat de repo si branch
az ad app federated-credential create \
  --id $APP_ID \
  --parameters '{
    "name": "github-main",
    "issuer": "https://token.actions.githubusercontent.com",
    "subject": "repo:myorg/my-repo:ref:refs/heads/main",
    "audiences": ["api://AzureADTokenExchange"]
  }'

Câmpul subject restricționează cine poate cere token-uri: doar workflow-uri din branch-ul main al repo-ului tău. Un pull request din alt repo nu poate obține acces.

Roluri pentru service principal

PRINCIPAL_ID=$(az ad sp show --id $APP_ID --query id -o tsv)
ACR_ID=$(az acr show --name myregistry --query id -o tsv)
RG_ID=$(az group show --name my-rg --query id -o tsv)

# Push in Container Registry
az role assignment create --assignee $PRINCIPAL_ID \
  --role "AcrPush" --scope $ACR_ID

# Deploy in Container Apps (Contributor pe resource group sau mai granular)
az role assignment create --assignee $PRINCIPAL_ID \
  --role "Contributor" --scope $RG_ID

Secretele din GitHub

Cu OIDC, în GitHub nu pui niciun secret sensibil — doar identificatori publici:

# Nu sunt secrete reale, doar identificatori
AZURE_CLIENT_ID       = 
AZURE_TENANT_ID       = 
AZURE_SUBSCRIPTION_ID = 

Workflow-ul complet

# .github/workflows/deploy.yml
name: Build and Deploy to Container Apps

on:
  push:
    branches: [ main ]

permissions:
  id-token: write   # necesar pentru OIDC
  contents: read

env:
  REGISTRY: myregistry.azurecr.io
  IMAGE_NAME: my-api
  CONTAINER_APP: my-api
  RESOURCE_GROUP: my-rg

jobs:
  build-and-deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      # Login Azure prin OIDC -- fara secrete
      - name: Azure Login
        uses: azure/login@v2
        with:
          client-id: ${{ secrets.AZURE_CLIENT_ID }}
          tenant-id: ${{ secrets.AZURE_TENANT_ID }}
          subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}

      # Login la ACR folosind token-ul Azure
      - name: ACR Login
        run: az acr login --name ${{ env.REGISTRY }}

      # Build si push imagine, tag-uita cu SHA-ul commit-ului
      - name: Build and push
        run: |
          IMAGE_TAG=${{ github.sha }}
          docker build -t ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:$IMAGE_TAG .
          docker push ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:$IMAGE_TAG

      # Deploy noua imagine in Container Apps
      - name: Deploy to Container Apps
        run: |
          az containerapp update \
            --name ${{ env.CONTAINER_APP }} \
            --resource-group ${{ env.RESOURCE_GROUP }} \
            --image ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.sha }}

Punctul-cheie: imaginea e tag-uită cu github.sha (SHA-ul commit-ului), nu cu latest. Fiecare deploy e trasabil la commit-ul exact, iar rollback-ul înseamnă doar redeploy cu un SHA anterior.


Revizii și traffic splitting

Fiecare containerapp update creează o revizie nouă. În mod implicit, ACA rutează 100% din trafic către ultima revizie. Dar poți face canary releases reale, împărțind traficul între revizii.

Activarea modului multiple revisions

az containerapp revision set-mode \
  --name my-api --resource-group my-rg \
  --mode multiple

Traffic split: 90% stabil, 10% canary

# Trimite 10% din trafic catre noua revizie, 90% catre cea stabila
az containerapp ingress traffic set \
  --name my-api --resource-group my-rg \
  --revision-weight \
    my-api--stable-rev=90 \
    my-api--new-rev=10

Monitorizezi noua revizie în Application Insights câteva ore. Dacă metrici de eroare și latență sunt OK, muți traficul la 100%. Dacă nu, revii la 0% instant — fără redeploy, doar o schimbare de rutare.

# Promoveaza noua revizie la 100%
az containerapp ingress traffic set \
  --name my-api --resource-group my-rg \
  --revision-weight my-api--new-rev=100

Checklist pipeline Container Apps

  • OIDC în loc de client secret — federated credentials, zero secrete în GitHub
  • subject restricționat — doar branch-ul și repo-ul tău pot cere token-uri
  • Managed Identity pentru pull — Container App trage imaginea din ACR fără credențiale
  • Imagini tag-uite cu SHA — trasabilitate la commit, rollback simplu
  • Health probes configurate — ACA nu rutează trafic către revizii nesănătoase
  • Traffic splitting pentru canary — validare graduală înainte de 100%

Încheierea seriei Container Apps

Cu asta, mini-seria despre Azure Container Apps e completă: am stabilit când merită migrarea, am configurat scaling elastic cu KEDA, am integrat Dapr pentru microservicii și am automatizat deployment-ul cu GitHub Actions — totul construit pe fundația de securitate fără secrete din articolele anterioare.

În continuarea seriei Cloud-native cu Azure și .NET urmează observabilitatea cu Application Insights: distributed tracing, custom metrics și alerts.

Dacă ai întrebări sau vrei să discuți cum structurezi pipeline-ul pentru proiectul tău, scrie-mi la contact@ludoprogramming.com.