Déploiement de Orleans sur Azure Container Apps

Dans ce tutoriel, vous allez découvrir comment déployer un exemple d’application de panier Orleans sur Azure Container Apps. Ce tutoriel étend les fonctionnalités de l’exemple d’application de panier Orleans, introduit dans Déploiement de Orleans sur Azure App Service. L’exemple d’application ajoute l’authentification B2C (entreprise-client) Azure Active Directory (AAD), et est déployé sur Azure Container Apps.

Vous allez découvrir comment effectuer un déploiement en utilisant GitHub Actions, les interfaces .NET CLI et Azure CLI ainsi qu’Azure Bicep. De plus, vous allez apprendre à configurer l’entrée HTTP de Container Apps.

Dans ce tutoriel, vous allez apprendre à :

  • Déploiement d’une application Orleans sur Azure Container Apps
  • Automatiser le déploiement à l’aide de GitHub Actions et d’Azure Bicep
  • Configurer l’entrée HTTP

Prérequis

Exécutez l’application localement.

Pour exécuter l’application localement, dupliquez (fork) le référentiel Exemples Azure : panier Orleans sur Azure Container Apps, puis clonez-le sur votre ordinateur local. Une fois le clonage effectué, ouvrez la solution dans l’IDE de votre choix. Si vous utilisez Visual Studio, cliquez avec le bouton droit sur le projet Orleans.ShoppingCart.Silo, sélectionnez Définir en tant que projet de démarrage, puis exécutez l’application. Sinon, vous pouvez exécuter l’application à l’aide de la commande .NET CLI suivante :

dotnet run --project Silo\Orleans.ShoppingCart.Silo.csproj

Pour plus d’informations, consultez dotnet run. Une fois l’application en cours d’exécution, une page de destination décrivant les fonctionnalités de l’application s’affiche. Dans le coin supérieur droit, vous pouvez voir un bouton de connexion. Vous pouvez vous inscrire pour obtenir un compte, ou vous connecter si vous disposez déjà d’un compte. Une fois connecté, vous pouvez naviguer et tester librement ses fonctionnalités. Toutes les fonctionnalités de l’application, quand elle s’exécute localement, reposent sur la persistance en mémoire et le clustering local. De plus, l’application utilise le package NuGet Bogus pour générer des produits fictifs. Arrêtez l’application en sélectionnant l’option Arrêter le débogage dans Visual Studio, ou en appuyant sur Ctrl+C dans l’interface .NET CLI.

AAD B2C

Bien que l’enseignement des concepts liés à l’authentification dépasse le cadre de ce tutoriel, vous pouvez apprendre à créer un locataire Azure Active Directory B2C, et inscrire une application web pour le consommer. Dans le cas de cet exemple d’application de panier, l’URL résultante de l’application déployée sur Container Apps doit être inscrite auprès du locataire B2C. Pour plus d’informations, consultez Authentification et autorisation ASP.NET Core Blazor.

Important

Une fois votre application déployée sur Container Apps, vous devez inscrire son URL auprès du locataire B2C. Dans la plupart des scénarios de production, vous n’avez besoin d’inscrire l’URL de l’application qu’une seule fois, car elle ne doit pas changer.

Pour mieux visualiser la façon dont l’application est isolée dans l’environnement Azure Container Apps, consultez le diagramme suivant :

Entrée HTTP dans Azure Container Apps.

Dans le diagramme précédent, tout le trafic entrant vers l’application est dirigé via une entrée HTTP sécurisée. L’environnement Azure Container Apps contient une instance d’application dont l’hôte ASP.NET Core expose les fonctionnalités d’application Blazor Server et Orleans.

Déployer sur Azure Container Apps

Pour déployer l’application sur Azure Container Apps, le dépôt utilise GitHub Actions. Pour que ce déploiement puisse avoir lieu, vous avez besoin de quelques ressources Azure, et vous devez configurer correctement le dépôt GitHub.

Avant de déployer l’application, vous devez créer un groupe de ressources Azure, ou choisir d’utiliser un groupe existant. Pour créer un groupe de ressources Azure, utilisez l’un des articles suivants :

Notez le nom du groupe de ressources que vous choisissez. Vous en aurez besoin plus tard pour déployer l’application.

Créer un principal du service

Pour automatiser le déploiement de l’application, vous devez créer un principal de service. Il s’agit d’un compte Microsoft qui dispose de l’autorisation nécessaire pour gérer les ressources Azure en votre nom.

az ad sp create-for-rbac --sdk-auth --role Contributor \
  --name "<display-name>"  --scopes /subscriptions/<your-subscription-id>

Les informations d’identification JSON créées ressemblent à ce qui suit, mais avec des valeurs réelles pour votre client, votre abonnement et votre locataire :

{
  "clientId": "<your client id>",
  "clientSecret": "<your client secret>",
  "subscriptionId": "<your subscription id>",
  "tenantId": "<your tenant id>",
  "activeDirectoryEndpointUrl": "https://login.microsoftonline.com/",
  "resourceManagerEndpointUrl": "https://brazilus.management.azure.com",
  "activeDirectoryGraphResourceId": "https://graph.windows.net/",
  "sqlManagementEndpointUrl": "https://management.core.windows.net:8443/",
  "galleryEndpointUrl": "https://gallery.azure.com",
  "managementEndpointUrl": "https://management.core.windows.net"
}

Copiez la sortie de la commande dans votre Presse-papiers, puis passez à l’étape suivante.

Créer un secret GitHub

GitHub fournit un mécanisme de création de secrets chiffrés. Les secrets que vous créez peuvent être utilisés dans les workflows GitHub Actions. Vous allez voir comment GitHub Actions peut être utilisé pour automatiser le déploiement de l’application, conjointement avec Azure Bicep. Bicep est un langage dédié (DSL), qui utilise une syntaxe déclarative pour déployer les ressources Azure. Pour plus d’informations, consultez Qu’est-ce que Bicep. À l’aide de la sortie de l’étape Créer un principal de service, vous devez créer un secret GitHub nommé AZURE_CREDENTIALS avec les informations d’identification au format JSON.

Dans le dépôt GitHub, sélectionnez Paramètres>Secrets>Créer un secret. Entrez le nom AZURE_CREDENTIALS et collez les informations d’identification au format JSON de l’étape précédente dans le champ Valeur.

Dépôt GitHub : Paramètres > Secrets

Pour plus d’informations, consultez GitHub : Secrets chiffrés.

Préparer le déploiement Azure

L’application doit être packagée pour le déploiement. Dans le projet Orleans.ShoppingCart.Silos, nous définissons un élément Target qui s’exécute après l’étape Publish. Cela entraîne la compression du répertoire de publication dans un fichier silo.zip :

<Target Name="ZipPublishOutput" AfterTargets="Publish">
    <Delete Files="$(ProjectDir)\..\silo.zip" />
    <ZipDirectory SourceDirectory="$(PublishDir)" DestinationFile="$(ProjectDir)\..\silo.zip" />
</Target>

Il existe de nombreuses façons de déployer une application .NET sur Azure Container Apps. Dans ce tutoriel, vous allez utiliser GitHub Actions, Azure Bicep ainsi que les interfaces .NET CLI et Azure CLI. Prenons l’exemple du fichier ./github/workflows/deploy.yml situé à la racine du dépôt GitHub :

name: Deploy to Azure Container Apps

on:
  push:
    branches:
    - main

env:
  UNIQUE_APP_NAME: orleanscart
  SILO_IMAGE_NAME: orleanscart-silo
  AZURE_RESOURCE_GROUP_NAME: orleans-resourcegroup
  AZURE_RESOURCE_GROUP_LOCATION: eastus

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

    - name: Setup .NET 6.0
      uses: actions/setup-dotnet@v3
      with:
        dotnet-version: 6.0.x

    - name: .NET publish shopping cart app
      run: dotnet publish ./Silo/Orleans.ShoppingCart.Silo.csproj --configuration Release

    - name: Login to Azure
      uses: azure/login@v1
      with:
        creds: ${{ secrets.AZURE_CREDENTIALS }}

    - name: Flex ACR Bicep
      run: |
        az deployment group create \
          --resource-group ${{ env.AZURE_RESOURCE_GROUP_NAME }} \
          --template-file '.github/workflows/flex/acr.bicep' \
          --parameters location=${{ env.AZURE_RESOURCE_GROUP_LOCATION }}

    - name: Get ACR Login Server
      run: |
        ACR_NAME=$(az deployment group show -g ${{ env.AZURE_RESOURCE_GROUP_NAME }} -n acr \
        --query properties.outputs.acrName.value | tr -d '"')
        echo "ACR_NAME=$ACR_NAME" >> $GITHUB_ENV
        ACR_LOGIN_SERVER=$(az deployment group show -g ${{ env.AZURE_RESOURCE_GROUP_NAME }} -n acr \
        --query properties.outputs.acrLoginServer.value | tr -d '"')
        echo "ACR_LOGIN_SERVER=$ACR_LOGIN_SERVER" >> $GITHUB_ENV

    - name: Prepare Docker buildx
      uses: docker/setup-buildx-action@v1

    - name: Login to ACR
      run: |
        access_token=$(az account get-access-token --query accessToken -o tsv)
        refresh_token=$(curl https://${{ env.ACR_LOGIN_SERVER }}/oauth2/exchange -v \
        -d "grant_type=access_token&service=${{ env.ACR_LOGIN_SERVER }}&access_token=$access_token" | jq -r .refresh_token)
        # The null GUID 0000... tells the container registry that this is an ACR refresh token during the login flow
        docker login -u 00000000-0000-0000-0000-000000000000 \
        --password-stdin ${{ env.ACR_LOGIN_SERVER }} <<< "$refresh_token"

    - name: Build and push Silo image to registry
      uses: docker/build-push-action@v2
      with:
        push: true
        tags: ${{ env.ACR_LOGIN_SERVER }}/${{ env.SILO_IMAGE_NAME }}:${{ github.sha }}
        file: Silo/Dockerfile

    - name: Flex ACA Bicep
      run: |
        az deployment group create \
          --resource-group ${{ env.AZURE_RESOURCE_GROUP_NAME }} \
          --template-file '.github/workflows/flex/main.bicep' \
          --parameters location=${{ env.AZURE_RESOURCE_GROUP_LOCATION }} \
            appName=${{ env.UNIQUE_APP_NAME }} \
            acrName=${{ env.ACR_NAME }} \
            repositoryImage=${{ env.ACR_LOGIN_SERVER }}/${{ env.SILO_IMAGE_NAME }}:${{ github.sha }} \
          --debug

    - name: Get Container App URL
      run: |
        ACA_URL=$(az deployment group show -g ${{ env.AZURE_RESOURCE_GROUP_NAME }} \
        -n main --query properties.outputs.acaUrl.value | tr -d '"')
        echo $ACA_URL

    - name: Logout of Azure
      run: az logout

Le workflow GitHub précédent va :

  • Publier l’application de panier sous forme de fichier zip, à l’aide de la commande dotnet publish.
  • Connectez-vous à Azure à l’aide des informations d’identification de l’étape Créer un principal de service.
  • Évaluer le fichier acr.bicep et démarrer un groupe de déploiement à l’aide de la commande az deployment group create.
  • Obtenir le serveur de connexion ACR (Azure Container Registry) à partir du groupe de déploiement.
  • Se connecter à ACR à l’aide du secret AZURE_CREDENTIALS des dépôts.
  • Générer et publier l’image de silo sur l’ACR.
  • Évaluer le fichier main.bicep et démarrer un groupe de déploiement à l’aide de la commande az deployment group create.
  • Déployer le silo
  • Se déconnecter d’Azure.

Le workflow est déclenché par une poussée vers la branche main. Pour plus d’informations, consultez GitHub Actions et .NET.

Conseil

Si vous rencontrez des problèmes au moment de l’exécution du workflow, vous devrez peut-être vérifier que tous les espaces de noms de fournisseurs nécessaires sont inscrits pour le principal de service. Les espaces de noms de fournisseurs suivants sont obligatoires :

  • Microsoft.App
  • Microsoft.ContainerRegistry
  • Microsoft.Insights
  • Microsoft.OperationalInsights
  • Microsoft.Storage

Pour plus d’informations, consultez Résoudre les erreurs d’inscription du fournisseur de ressources.

Azure impose des restrictions et des conventions de nommage pour les ressources. Vous devez mettre à jour les valeurs du fichier deploy.yml pour ce qui suit :

  • UNIQUE_APP_NAME
  • SILO_IMAGE_NAME
  • AZURE_RESOURCE_GROUP_NAME
  • AZURE_RESOURCE_GROUP_LOCATION

Affectez à ces valeurs le nom unique de votre application ainsi que le nom et l’emplacement de votre groupe de ressources Azure.

Pour plus d’informations, consultez les règles de nommage et les restrictions.

Explorer les modèles Bicep

Quand la commande az deployment group create est exécutée, elle évalue une référence de fichier .bicep donnée. Ce fichier contient des informations déclaratives qui détaillent les ressources Azure à déployer. Vous pouvez vous représenter cette étape comme le provisionnement de toutes les ressources du déploiement.

Important

Si vous utilisez Visual Studio Code, l’expérience de création Bicep est améliorée quand vous utilisez l’extension Bicep.

Le premier fichier Bicep évalué est le fichier acr.bicep. Ce fichier contient les détails des ressources du serveur de connexion ACR (Azure Container Registry) :

param location string = resourceGroup().location

resource acr 'Microsoft.ContainerRegistry/registries@2021-09-01' = {
  name: toLower('${uniqueString(resourceGroup().id)}acr')
  location: location
  sku: {
    name: 'Basic'
  }
  properties: {
    adminUserEnabled: true
  }
}

output acrLoginServer string = acr.properties.loginServer
output acrName string = acr.name

Ce fichier Bicep génère en sortie le serveur de connexion ACR et le nom correspondant. Le prochain fichier Bicep rencontré contient plusieurs resource. Prenons l’exemple du fichier main.bicep, constitué principalement de délégations de définitions de module :

param appName string
param acrName string
param repositoryImage string
param location string = resourceGroup().location

resource acr 'Microsoft.ContainerRegistry/registries@2021-09-01' existing = {
  name: acrName
}

module env 'environment.bicep' = {
  name: 'containerAppEnvironment'
  params: {
    location: location
    operationalInsightsName: '${appName}-logs'
    appInsightsName: '${appName}-insights'
  }
}

var envVars = [
  {
    name: 'APPINSIGHTS_INSTRUMENTATIONKEY'
    value: env.outputs.appInsightsInstrumentationKey
  }
  {
    name: 'APPLICATIONINSIGHTS_CONNECTION_STRING'
    value: env.outputs.appInsightsConnectionString
  }
  {
    name: 'ORLEANS_AZURE_STORAGE_CONNECTION_STRING'
    value: storageModule.outputs.connectionString
  }
  {
    name: 'ASPNETCORE_FORWARDEDHEADERS_ENABLED'
    value: 'true'
  }
]

module storageModule 'storage.bicep' = {
  name: 'orleansStorageModule'
  params: {
    name: '${appName}storage'
    location: location
  }
}

module siloModule 'container-app.bicep' = {
  name: 'orleansSiloModule'
  params: {
    appName: appName
    location: location
    containerAppEnvironmentId: env.outputs.id
    repositoryImage: repositoryImage
    registry: acr.properties.loginServer
    registryPassword: acr.listCredentials().passwords[0].value
    registryUsername: acr.listCredentials().username
    envVars: envVars
  }
}

output acaUrl string = siloModule.outputs.acaUrl

Fichier Bicep précédent :

  • Référence une ressource ACR existing. Pour plus d’informations, consultez Azure Bicep : Ressources existantes.
  • Définit un module env, qui effectue une délégation au fichier de définition environment.bicep.
  • Définit un module storageModule, qui effectue une délégation au fichier de définition storage.bicep.
  • Déclare plusieurs envVars partagés utilisés par le module silo.
  • Définit un module siloModule, qui effectue une délégation au fichier de définition container-app.bicep.
  • Génère l’URL ACA (qui peut éventuellement être utilisée pour mettre à jour l’URI de redirection d’une inscription d’application AAD B2C).

Le fichier main.bicep effectue une délégation à plusieurs autres fichiers Bicep. Le premier est le fichier environment.bicep :

param operationalInsightsName string
param appInsightsName string
param location string

resource appInsights 'Microsoft.Insights/components@2020-02-02' = {
  name: appInsightsName
  location: location
  kind: 'web'
  properties: {
    Application_Type: 'web'
    WorkspaceResourceId: logs.id
  }
}

resource logs 'Microsoft.OperationalInsights/workspaces@2021-06-01' = {
  name: operationalInsightsName
  location: location
  properties: {
    retentionInDays: 30
    features: {
      searchVersion: 1
    }
    sku: {
      name: 'PerGB2018'
    }
  }
}

resource env 'Microsoft.App/managedEnvironments@2022-03-01' = {
  name: '${resourceGroup().name}env'
  location: location
  properties: {
    appLogsConfiguration: {
      destination: 'log-analytics'
      logAnalyticsConfiguration: {
        customerId: logs.properties.customerId
        sharedKey: logs.listKeys().primarySharedKey
      }
    }
  }
}

output id string = env.id
output appInsightsInstrumentationKey string = appInsights.properties.InstrumentationKey
output appInsightsConnectionString string = appInsights.properties.ConnectionString

Ce fichier Bicep définit les ressources Azure Log Analytics et Application Insights. La ressource appInsights est de type web et la ressource logs est de type PerGB2018. La ressource appInsights et la ressource logs sont toutes deux provisionnées à l’emplacement du groupe de ressources. La ressource appInsights est liée à la ressource logs via la propriété WorkspaceResourceId. Il existe trois sorties définies dans ce fichier Bicep, utilisées plus tard par le module de Container Apps. Examinons ensuite le fichier storage.bicep :

param name string
param location string

resource storage 'Microsoft.Storage/storageAccounts@2021-08-01' = {
  name: name
  location: location
  kind: 'StorageV2'
  sku: {
    name: 'Standard_LRS'
  }
}

var key = listKeys(storage.name, storage.apiVersion).keys[0].value
var protocol = 'DefaultEndpointsProtocol=https'
var accountBits = 'AccountName=${storage.name};AccountKey=${key}'
var endpointSuffix = 'EndpointSuffix=${environment().suffixes.storage}'

output connectionString string = '${protocol};${accountBits};${endpointSuffix}'

Le fichier Bicep précédent définit ceci :

  • Deux paramètres pour le nom du groupe de ressources et le nom de l’application.
  • La définition resource storage pour le compte de stockage.
  • Un seul output, qui construit la chaîne de connexion pour le compte de stockage.

Le dernier fichier Bicep est le fichier container-app.bicep :

param appName string
param location string
param containerAppEnvironmentId string
param repositoryImage string = 'mcr.microsoft.com/azuredocs/containerapps-helloworld:latest'
param envVars array = []
param registry string
param registryUsername string
@secure()
param registryPassword string

resource containerApp 'Microsoft.App/containerApps@2022-03-01' = {
  name: appName
  location: location
  properties: {
    managedEnvironmentId: containerAppEnvironmentId
    configuration: {
      activeRevisionsMode: 'multiple'
      secrets: [
        {
          name: 'container-registry-password'
          value: registryPassword
        }
      ]
      registries: [
        {
          server: registry
          username: registryUsername
          passwordSecretRef: 'container-registry-password'
        }
      ]
      ingress: {
        external: true
        targetPort: 80
      }
    }
    template: {
      revisionSuffix: uniqueString(repositoryImage, appName)
      containers: [
        {
          image: repositoryImage
          name: appName
          env: envVars
        }
      ]
      scale: {
        minReplicas: 1
        maxReplicas: 1
      }
    }
  }
}

output acaUrl string = containerApp.properties.configuration.ingress.fqdn

L’extension Visual Studio Code pour Bicep mentionnée ci-dessus comprend un visualiseur. Tous ces fichiers Bicep sont visualisés de la façon suivante :

Orleans : rendu du visualiseur d’approvisionnement Bicep dans l’exemple d’application de panier.

Résumé

Quand vous mettez à jour le code source et que vous effectuez un push des changements apportés à la branche main du dépôt, le workflow deploy.yml s’exécute. Il provisionne les ressources Azure définies dans les fichiers Bicep et déploie l’application. Les révisions sont automatiquement inscrites dans votre registre de conteneurs Azure Container Registry.

En plus du visualiseur de l’extension Bicep, la page du groupe de ressources du portail Azure ressemble à l’exemple suivant après le provisionnement et le déploiement de l’application :

Portail Azure : ressources de l’exemple d’application de panier Orleans pour Azure Container Apps.

Voir aussi