Partager via


Déployer un projet .NET Aspire sur Azure Container Apps à l’aide du Azure Developer CLI (guide détaillé)

Le Azure Developer CLI (azd) a été étendu pour prendre en charge le déploiement de projets .NET.NET Aspire. Utilisez ce guide pour parcourir le processus de création et de déploiement d’un projet .NET Aspire pour Azure Container Apps à l’aide du Azure Developer CLI. Dans ce tutoriel, vous allez découvrir les concepts suivants :

  • Découvrez comment l’intégration azd fonctionne avec des projets .NET.NET Aspire
  • Approvisionner et déployer des ressources sur Azure pour un projet de .NET Aspire à l’aide de azd
  • Générer l’infrastructure Bicep et d’autres fichiers de modèle à l’aide de azd

Conditions préalables

Pour utiliser .NET.NET Aspire, vous avez besoin de l’installation locale suivante :

Pour plus d’informations, consultez .NET.NET Aspire de configuration et outils, et .NET.NET Aspire SDK.

Vous devrez également installer le Azure Developer CLIlocalement. Les options d’installation courantes sont les suivantes :

winget install microsoft.azd

Comment fonctionne l'intégration Azure Developer CLI

Le flux de travail azd init fournit une prise en charge personnalisée des projets .NET.NET Aspire. Le diagramme suivant illustre le fonctionnement conceptuel de ce flux et la façon dont les azd et les .NET.NET Aspire sont intégrés :

Illustration du traitement interne de « azd » lors du déploiement du projet .NET.NET Aspire.

  1. Lorsque azd cible un projet .NET.NET Aspire, il démarre AppHost avec une commande spéciale (dotnet run --project AppHost.csproj --output-path manifest.json --publisher manifest), qui produit le fichier manifeste Aspire.
  2. Le fichier manifeste est interrogé par la logique de sous-commande azd provision pour générer des fichiers Bicep en mémoire uniquement (par défaut).
  3. Après avoir généré les fichiers Bicep, un déploiement est déclenché à l’aide des API ARM de Azureciblant l’abonnement et le groupe de ressources fournis précédemment.
  4. Une fois les ressources Azure sous-jacentes configurées, la logique de sous-commande azd deploy est exécutée qui utilise le même fichier manifeste Aspire.
  5. Dans le cadre du déploiement, azd effectue un appel à dotnet publish en utilisant la prise en charge intégrée de la publication de conteneurs de .NETpour générer des images de conteneur.
  6. Une fois que azd a généré les images conteneurs, il les pousse vers le registre ACR créé pendant la phase d’approvisionnement.
  7. Enfin, une fois l’image conteneur dans ACR, azd met à jour la ressource à l’aide d’ARM pour commencer à utiliser la nouvelle version de l’image conteneur.

Note

azd vous permet également d'exporter le Bicep généré vers un dossier infra de votre projet, pour en savoir plus dans la section Génération de Bicep à partir de .NET.NET Aspire modèle d’application section.

Approvisionner et déployer une application de démarrage .NET.NET Aspire

Les étapes décrites dans cette section montrent comment créer une application de démarrage .NET Aspire et gérer l’approvisionnement et le déploiement des ressources d’application pour Azure à l’aide de azd.

Créer l’application de démarrage .NET.NET Aspire

Créez un projet .NET.NET Aspire à l’aide de la commande dotnet new. Vous pouvez également créer le projet à l’aide de Visual Studio.

dotnet new aspire-starter --use-redis-cache -o AspireSample
cd AspireSample
dotnet run --project AspireSample.AppHost\AspireSample.AppHost.csproj

Les commandes précédentes créent un nouveau projet .NET.NET Aspire basé sur le modèle aspire-starter, qui inclut une dépendance à le cache Redis. Il exécute le projet .NET.NET Aspire qui vérifie que tout fonctionne correctement.

Initialiser le modèle

  1. Ouvrez une nouvelle fenêtre de terminal et effectuez cd dans le répertoire de projet AppHost de votre solution .NET.NET Aspire.

  2. Exécutez la commande azd init pour initialiser votre projet avec azd, qui inspecte la structure de répertoires local et détermine le type d’application.

    azd init
    

    Pour plus d’informations sur la commande azd init, consultez azd init.

  3. Sélectionnez Utiliser du code dans le répertoire actif lorsque azd vous invite à utiliser deux options d’initialisation d’application.

    ? How do you want to initialize your app?  [Use arrows to move, type to filter]
    > Use code in the current directory
      Select a template
    
  4. Après avoir analysé le répertoire, azd vous invite à confirmer qu’il a trouvé le projet .NET.NET AspireAppHost approprié. Sélectionnez l’option Confirmer et continuer l'initialisation de mon application.

    Detected services:
    
      .NET (Aspire)
      Detected in: D:\source\repos\AspireSample\AspireSample.AppHost\AspireSample.AppHost.csproj
    
    azd will generate the files necessary to host your app on Azure using Azure Container Apps.
    
    ? Select an option  [Use arrows to move, type to filter]
    > Confirm and continue initializing my app
      Cancel and exit
    
  5. Entrez un nom d’environnement, utilisé pour nommer les ressources provisionnée dans Azure et gérer différents environnements tels que dev et prod.

    Generating files to run your app on Azure:
    
      (✓) Done: Generating ./azure.yaml
      (✓) Done: Generating ./next-steps.md
    
    SUCCESS: Your app is ready for the cloud!
    You can provision and deploy your app to Azure by running the azd up command in this directory. For more information on configuring your app, see ./next-steps.md
    

azd génère un certain nombre de fichiers et les place dans le répertoire de travail. Ces fichiers sont les suivants :

  • azure.yaml: décrit les services de l’application, tels que .NET Aspire projet AppHost, et les mappe aux ressources Azure.
  • .azure/config.json: fichier de configuration qui informe azd quel est l’environnement actif actuel.
  • .azure/aspireazddev/.env: contient des remplacements spécifiques à l’environnement.

Le fichier azure.yaml contient le contenu suivant :

# yaml-language-server: $schema=https://raw.githubusercontent.com/Azure/azure-dev/main/schemas/v1.0/azure.yaml.json

name: AspireSample
services:
  app:
    language: dotnet
    project: .\AspireSample.AppHost\AspireSample.AppHost.csproj
    host: containerapp

Nommage des ressources

Lorsque vous créez de nouvelles ressources Azure, il est important de respecter les exigences de nommage. Pour Azure Container Apps, le nom doit contenir 2 à 32 caractères et se composer de lettres minuscules, de chiffres et de traits d’union. Le nom doit commencer par une lettre et se terminer par un caractère alphanumérique.

Pour plus d’informations, consultez règles et restrictions d’affectation de noms pour les ressources Azure.

Déploiement initial

  1. Pour déployer le projet .NET Aspire, authentifiez-vous auprès de Azure AD pour appeler les API de gestion des ressources Azure.

    azd auth login
    

    La commande précédente lance un navigateur pour authentifier la session de ligne de commande.

  2. Une fois authentifié, exécutez la commande suivante à partir du répertoire de projet AppHost pour approvisionner et déployer l’application.

    azd up
    

    Important

    Pour transférer des images de conteneur à l'Azure Container Registry (ACR), vous devez disposer d'un accès à Microsoft.Authorization/roleAssignments/write. Pour ce faire, vous pouvez activer un utilisateur administrateur sur le Registre. Ouvrez le portail Azure, accédez à la ressource ACR/ Paramètres/ Clés d’accès, puis cochez la case 'utilisateur administrateur. Pour plus d’informations, consultez Activer l’utilisateur administrateur.

  3. Lorsque vous y êtes invité, sélectionnez l’abonnement et l’emplacement où les ressources doivent être déployées. Une fois ces options sélectionnées, le projet .NET.NET Aspire sera déployé.

    By default, a service can only be reached from inside the Azure Container Apps environment it is running in. Selecting a service here will also allow it to be reached from the Internet.
    ? Select which services to expose to the Internet webfrontend
    ? Select an Azure Subscription to use:  1. <YOUR SUBSCRIPTION>
    ? Select an Azure location to use: 1. <YOUR LOCATION>
    
    Packaging services (azd package)
    
    
    Provisioning Azure resources (azd provision)
    Provisioning Azure resources can take some time.
    
    Subscription: <YOUR SUBSCRIPTION>
    Location: <YOUR LOCATION>
    
      You can view detailed progress in the Azure Portal:
      <LINK TO DEPLOYMENT>
    
      (✓) Done: Resource group: <YOUR RESOURCE GROUP>
      (✓) Done: Container Registry: <ID>
      (✓) Done: Log Analytics workspace: <ID>
      (✓) Done: Container Apps Environment: <ID>
    
    SUCCESS: Your application was provisioned in Azure in 1 minute 13 seconds.
    You can view the resources created under the resource group <YOUR RESOURCE GROUP> in Azure Portal:
    <LINK TO RESOURCE GROUP OVERVIEW>
    
    Deploying services (azd deploy)
    
      (✓) Done: Deploying service apiservice
      - Endpoint: <YOUR UNIQUE apiservice APP>.azurecontainerapps.io/
    
      (✓) Done: Deploying service webfrontend
      - Endpoint: <YOUR UNIQUE webfrontend APP>.azurecontainerapps.io/
    
    Aspire Dashboard: <LINK TO DEPLOYED .NET ASPIRE DASHBOARD>
    
    SUCCESS: Your up workflow to provision and deploy to Azure completed in 3 minutes 50 seconds.
    

    La dernière ligne de sortie de la commande azd est un lien vers le portail Azure qui affiche toutes les ressources Azure déployées :

    capture d’écran du portail Azure montrant les ressources déployées.

Trois conteneurs sont déployés dans cette application :

  • webfrontend: contient du code à partir du projet web dans le modèle de démarrage.
  • apiservice: contient du code à partir du projet de service d’API dans le modèle de démarrage.
  • cache: image conteneur Redis pour fournir un cache au serveur frontal.

Tout comme dans le développement local, la configuration des chaînes de connexion a été gérée automatiquement. Dans ce cas, azd était responsable de l’interprétation du modèle d’application et de sa traduction en étapes de déploiement appropriées. Par exemple, considérez la chaîne de connexion et les variables de découverte de service qui sont injectées dans le conteneur webfrontend afin qu’elles sachent comment se connecter au cache Redis et apiservice.

Capture d’écran des variables d’environnement dans l’application conteneur webfrontend.

Pour plus d’informations sur la façon dont les projets .NET.NET Aspire gèrent les paramètres de connexion et la découverte des services, consultez l’aperçu de l’orchestration dans .NET.NET Aspire.

Déployer des mises à jour d’application

Lorsque la commande azd up est exécutée, les ressources de Azure sous-jacentes sont approvisionnées et une image conteneur est générée et déployée sur les applications conteneur hébergeant le projet .NET.NET Aspire. En règle générale, une fois le développement en cours et Azure ressources sont déployées, il n’est pas nécessaire de provisionner des ressources Azure chaque fois que le code est mis à jour, ce qui est particulièrement vrai pour la boucle interne du développeur.

Pour accélérer le déploiement des modifications de code, azd prend en charge le déploiement des mises à jour de code dans l’image conteneur. Pour ce faire, utilisez la commande azd deploy :

azd deploy
Deploying services (azd deploy)

  (✓) Done: Deploying service apiservice
  - Endpoint: <YOUR UNIQUE apiservice APP>.azurecontainerapps.io/

  (✓) Done: Deploying service webfrontend
  - Endpoint: <YOUR UNIQUE webfrontend APP>.azurecontainerapps.io/

Aspire Dashboard: <LINK TO DEPLOYED .NET ASPIRE DASHBOARD>

Il n’est pas nécessaire de déployer tous les services à chaque fois. azd comprend le modèle de projet .NET.NET Aspire, il est possible de déployer uniquement l’un des services spécifiés à l’aide de la commande suivante :

azd deploy webfrontend

Pour plus d’informations, consultez la référence Azure Developer CLI : azd deploy.

Déployer des mises à jour d’infrastructure

Chaque fois que la structure de dépendances au sein d’un projet .NET.NET Aspire change, azd devez réapprovisionnement des ressources Azure sous-jacentes. La commande azd provision est utilisée pour appliquer ces modifications à l’infrastructure.

Pour voir cela en action, mettez à jour le fichier Program.cs dans le projet AppHost en procédant comme suit :

var builder = DistributedApplication.CreateBuilder(args);

var cache = builder.AddRedis("cache");

// Add the locations database.
var locationsdb = builder.AddPostgres("db").AddDatabase("locations");

// Add the locations database reference to the API service.
var apiservice = builder.AddProject<Projects.AspireSample_ApiService>("apiservice")
    .WithReference(locationsdb);

builder.AddProject<Projects.AspireSample_Web>("webfrontend")
    .WithReference(cache)
    .WithReference(apiservice);

builder.Build().Run();

Enregistrez le fichier et émettez la commande suivante :

azd provision

La commande azd provision met à jour l’infrastructure en créant une application conteneur pour héberger la base de données Postgres. La commande azd provision n’a pas mis à jour les chaînes de connexion pour le conteneur apiservice. Pour que les chaînes de connexion soient mises à jour pour pointer vers la base de données Postgres nouvellement provisionnée, la commande azd deploy doit être appelée à nouveau. En cas de doute, utilisez azd up pour approvisionner et déployer.

Nettoyer les ressources

N’oubliez pas de nettoyer les ressources Azure que vous avez créées pendant cette procédure pas à pas. Étant donné que « azd » connaît le groupe de ressources dans lequel il a créé les ressources, il peut être utilisé pour arrêter l'environnement à l'aide de la commande suivante :

azd down

La commande précédente peut prendre un certain temps pour s’exécuter, mais une fois le groupe de ressources terminé et toutes ses ressources doivent être supprimées.

Deleting all resources and deployed code on Azure (azd down)
Local application code is not deleted when running 'azd down'.

  Resource group(s) to be deleted:

    • <YOUR RESOURCE GROUP>: <LINK TO RESOURCE GROUP OVERVIEW>

? Total resources to delete: 7, are you sure you want to continue? Yes
Deleting your resources can take some time.

  (✓) Done: Deleting resource group: <YOUR RESOURCE GROUP>

SUCCESS: Your application was removed from Azure in 9 minutes 59 seconds.

Générer Bicep à partir d’un modèle de projet .NET.NET Aspire

Bien que les équipes de développement soient libres d’utiliser des commandes azd up (ou azd provision et azd deploy) pour leurs déploiements à des fins de développement et de production, certaines équipes peuvent choisir de générer des fichiers Bicep qu’ils peuvent examiner et gérer dans le cadre du contrôle de version (cela permet également à ces fichiers Bicep d’être référencés dans le cadre d’un déploiement plus complexe Azure plus volumineux).

azd inclut la possibilité de générer le Bicep qu’il utilise pour l’approvisionnement via la commande suivante :

azd config set alpha.infraSynth on
azd infra synth

Une fois cette commande exécutée dans l’exemple de modèle de démarrage utilisé dans ce guide, les fichiers suivants sont créés dans le répertoire de projet AppHost :

  • infra/main.bicep: représente le point d’entrée principal du déploiement.
  • infra/main.parameters.json: utilisé comme paramètres pour Bicep principal (mappe aux variables d’environnement définies dans .azure dossier).
  • infra/resources.bicep: définit les ressources Azure requises pour prendre en charge le modèle de projet .NET Aspire.
  • AspireSample.Web/manifests/containerApp.tmpl.yaml: définition de l’application conteneur pour webfrontend.
  • AspireSample.ApiService/manifests/containerApp.tmpl.yaml: définition de l’application conteneur pour apiservice.

Le fichier infra\resources.bicep ne contient aucune définition des applications conteneur elles-mêmes (à l’exception des applications conteneur qui sont des dépendances telles que Redis et Postgres) :

@description('The location used for all deployed resources')
param location string = resourceGroup().location

@description('Tags that will be applied to all resources')
param tags object = {}

var resourceToken = uniqueString(resourceGroup().id)

resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2023-01-31' = {
  name: 'mi-${resourceToken}'
  location: location
  tags: tags
}

resource containerRegistry 'Microsoft.ContainerRegistry/registries@2023-07-01' = {
  name: replace('acr-${resourceToken}', '-', '')
  location: location
  sku: {
    name: 'Basic'
  }
  tags: tags
}

resource caeMiRoleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = {
  name: guid(containerRegistry.id, managedIdentity.id, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '7f951dda-4ed3-4680-a7ca-43fe172d538d'))
  scope: containerRegistry
  properties: {
    principalId: managedIdentity.properties.principalId
    principalType: 'ServicePrincipal'
    roleDefinitionId:  subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '7f951dda-4ed3-4680-a7ca-43fe172d538d')
  }
}

resource logAnalyticsWorkspace 'Microsoft.OperationalInsights/workspaces@2022-10-01' = {
  name: 'law-${resourceToken}'
  location: location
  properties: {
    sku: {
      name: 'PerGB2018'
    }
  }
  tags: tags
}

resource containerAppEnvironment 'Microsoft.App/managedEnvironments@2023-05-01' = {
  name: 'cae-${resourceToken}'
  location: location
  properties: {
    appLogsConfiguration: {
      destination: 'log-analytics'
      logAnalyticsConfiguration: {
        customerId: logAnalyticsWorkspace.properties.customerId
        sharedKey: logAnalyticsWorkspace.listKeys().primarySharedKey
      }
    }
  }
  tags: tags
}

resource cache 'Microsoft.App/containerApps@2023-05-02-preview' = {
  name: 'cache'
  location: location
  properties: {
    environmentId: containerAppEnvironment.id
    configuration: {
      service: {
        type: 'redis'
      }
    }
    template: {
      containers: [
        {
          image: 'redis'
          name: 'redis'
        }
      ]
    }
  }
  tags: union(tags, {'aspire-resource-name': 'cache'})
}

resource locations 'Microsoft.App/containerApps@2023-05-02-preview' = {
  name: 'locations'
  location: location
  properties: {
    environmentId: containerAppEnvironment.id
    configuration: {
      service: {
        type: 'postgres'
      }
    }
    template: {
      containers: [
        {
          image: 'postgres'
          name: 'postgres'
        }
      ]
    }
  }
  tags: union(tags, {'aspire-resource-name': 'locations'})
}
output MANAGED_IDENTITY_CLIENT_ID string = managedIdentity.properties.clientId
output AZURE_CONTAINER_REGISTRY_ENDPOINT string = containerRegistry.properties.loginServer
output AZURE_CONTAINER_REGISTRY_MANAGED_IDENTITY_ID string = managedIdentity.id
output AZURE_CONTAINER_APPS_ENVIRONMENT_ID string = containerAppEnvironment.id
output AZURE_CONTAINER_APPS_ENVIRONMENT_DEFAULT_DOMAIN string = containerAppEnvironment.properties.defaultDomain

Pour plus d’informations sur l’utilisation de Bicep pour automatiser les déploiements vers Azure consultez Qu’est-ce que Bicep ?

La définition des applications conteneur à partir des projets de service .NET est contenue dans les fichiers containerApp/tmpl.yaml dans le répertoire manifests de chaque projet respectivement. Voici un exemple du projet webfrontend :

location: {{ .Env.AZURE_LOCATION }}
identity:
  type: UserAssigned
  userAssignedIdentities:
    ? "{{ .Env.AZURE_CONTAINER_REGISTRY_MANAGED_IDENTITY_ID }}"
    : {}
properties:
  environmentId: {{ .Env.AZURE_CONTAINER_APPS_ENVIRONMENT_ID }}
  configuration:
    activeRevisionsMode: single
    ingress:
      external: true
      targetPort: 8080
      transport: http
      allowInsecure: false
    registries:
    - server: {{ .Env.AZURE_CONTAINER_REGISTRY_ENDPOINT }}
      identity: {{ .Env.AZURE_CONTAINER_REGISTRY_MANAGED_IDENTITY_ID }}
  template:
    containers:
    - image: {{ .Env.SERVICE_WEBFRONTEND_IMAGE_NAME }}
      name: webfrontend
      env:
      - name: AZURE_CLIENT_ID
        value: {{ .Env.MANAGED_IDENTITY_CLIENT_ID }}
      - name: ConnectionStrings__cache
        value: {{ connectionString "cache" }}
      - name: OTEL_DOTNET_EXPERIMENTAL_OTLP_EMIT_EVENT_LOG_ATTRIBUTES
        value: "true"
      - name: OTEL_DOTNET_EXPERIMENTAL_OTLP_EMIT_EXCEPTION_LOG_ATTRIBUTES
        value: "true"
      - name: services__apiservice__0
        value: http://apiservice.internal.{{ .Env.AZURE_CONTAINER_APPS_ENVIRONMENT_DEFAULT_DOMAIN }}
      - name: services__apiservice__1
        value: https://apiservice.internal.{{ .Env.AZURE_CONTAINER_APPS_ENVIRONMENT_DEFAULT_DOMAIN }}
tags:
  azd-service-name: webfrontend
  aspire-resource-name: webfrontend

Après avoir exécuté la commande azd infra synth, lorsque azd provision et azd deploy sont appelés, ils utilisent Bicep et prennent en charge les fichiers générés.

Important

Si azd infra synth est appelé à nouveau, il remplace les fichiers modifiés par des fichiers générés à nouveau et vous invite à confirmer avant de le faire.

Environnements isolés pour le débogage

Étant donné que azd facilite l’approvisionnement de nouveaux environnements, il est possible que chaque membre de l’équipe dispose d’un environnement hébergé dans le cloud isolé pour le débogage du code dans un paramètre qui correspond étroitement à la production. Lorsque vous effectuez cette opération, chaque membre de l’équipe doit créer son propre environnement à l’aide de la commande suivante :

azd env new

Cela demandera de nouveau à l'utilisateur les informations concernant l'abonnement et le groupe de ressources, et les appels suivants, azd up, azd provisionet azd deploy, utiliseront par défaut ce nouvel environnement. Le commutateur --environment peut être appliqué à ces commandes pour basculer entre les environnements.

Nettoyer les ressources

Exécutez la commande CLI Azure suivante pour supprimer le groupe de ressources lorsque vous n’avez plus besoin des ressources Azure que vous avez créées. La suppression du groupe de ressources supprime également les ressources contenues à l’intérieur de celui-ci.

az group delete --name <your-resource-group-name>

Pour plus d’informations, consultez Nettoyer les ressources dans Azure.