Compartilhar via


Implantar um projeto de .NET Aspire para Azure Container Apps usando o Azure Developer CLI (guia detalhado)

O Azure Developer CLI (azd) foi estendido para dar suporte à implantação de projetos .NET.NET Aspire. Use este guia para percorrer o processo de criação e implantação de um projeto de .NET Aspire para Azure Container Apps usando o Azure Developer CLI. Neste tutorial, você aprenderá os seguintes conceitos:

  • Explore como a integração azd funciona com os projetos .NET.NET Aspire.
  • Provisionar e implantar recursos em Azure para um projeto do tipo .NET Aspire usando azd
  • Gerar a infraestrutura do Bicep e outros arquivos de modelo usando azd

Pré-requisitos

Para trabalhar com .NET.NET Aspire, você precisa do seguinte instalado localmente:

Para obter mais informações, consulte .NET.NET Aspirede instalação e ferramentas e .NET.NET Aspiredo SDK.

Você também precisará ter o Azure Developer CLIinstalado localmente. As opções comuns de instalação incluem o seguinte:

winget install microsoft.azd

Como funciona Azure Developer CLI integração

O fluxo de trabalho azd init fornece suporte personalizado para projetos .NET.NET Aspire. O diagrama a seguir ilustra como esse fluxo funciona conceitualmente e como azd e .NET.NET Aspire são integrados:

Ilustração do processamento interno do

  1. Quando azd direciona um projeto .NET.NET Aspire, ele inicia o AppHost com um comando especial (dotnet run --project AppHost.csproj --output-path manifest.json --publisher manifest), que produz o arquivo de manifesto Aspire.
  2. O arquivo de manifesto é interrogado pela lógica do subcomando azd provision para gerar arquivos Bicep apenas em memória (por padrão).
  3. Depois de gerar os arquivos Bicep, uma implantação é disparada usando as APIs ARM de Azuredirecionadas à assinatura e ao grupo de recursos fornecidos anteriormente.
  4. Depois que os recursos subjacentes de Azure são configurados, a lógica do subcomando azd deploy é executada, usando o mesmo arquivo de manifesto Aspire.
  5. Como parte da implantação azd, faz uma chamada para dotnet publish usando o suporte embutido de publicação de contêineres de .NETpara gerar imagens de contêineres.
  6. Depois que azd tiver criado as imagens de contêiner, ele as envia para o registro do ACR que foi criado durante a fase de provisionamento.
  7. Por fim, depois que a imagem de contêiner estiver no ACR, azd atualizará o recurso usando o ARM para começar a usar a nova versão da imagem de contêiner.

Nota

azd também permite que você exporte o Bicep gerado para uma pasta infra em seu projeto, e você pode saber mais na seção Gerando Bicep do modelo de aplicativo .NET.NET Aspire.

Provisionar e implantar um aplicativo inicial .NET.NET Aspire

As etapas nesta seção demonstram como criar um aplicativo de início .NET Aspire e gerenciar o provisionamento e a implantação dos recursos do aplicativo para Azure usando azd.

Criar o aplicativo inicial .NET.NET Aspire

Crie um novo projeto de .NET.NET Aspire usando o comando dotnet new. Você também pode criar o projeto usando Visual Studio.

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

Os comandos anteriores criam um novo projeto de .NET.NET Aspire com base no modelo de aspire-starter que inclui uma dependência no cache Redis. Ele executa o projeto .NET.NET Aspire que verifica se tudo está funcionando corretamente.

Inicializar o modelo

  1. Abra uma nova janela de terminal e cd no diretório de projeto do AppHost de sua solução de .NET.NET Aspire.

  2. Execute o comando azd init para inicializar seu projeto com azd, que inspecionará a estrutura do diretório local e determinará o tipo de aplicativo.

    azd init
    

    Para obter mais informações sobre o comando azd init, consulte azd init.

  3. Selecione Usar código no diretório atual quando azd solicitar duas opções de inicialização de aplicativo.

    ? 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. Depois de verificar o diretório, solicitará que você confirme que ele encontrou o projeto de AppHost correto. Selecione a opção Confirmar e continuar inicializando meu aplicativo.

    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. Insira um nome de ambiente, que é usado para nomear recursos provisionados em Azure e gerenciar ambientes diferentes, como dev e 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 gera vários arquivos e os coloca no diretório de trabalho. Estes arquivos são:

  • azure .yaml: descreve os serviços do aplicativo, como .NET Aspire projeto AppHost, e os mapeia para Azure recursos.
  • .azure/config.json: arquivo de configuração que informa azd qual é o ambiente ativo atual.
  • .azure/aspireazddev/.env: contém substituições específicas do ambiente.

O arquivo .yaml tem o seguinte conteúdo:

# 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

Nomenclatura de recursos

Quando você cria novos recursos Azure, é importante seguir os requisitos de nomenclatura. Para Azure Container Apps, o nome deve ter de 2 a 32 caracteres e consistir em letras minúsculas, números e hifens. O nome deve começar com uma letra e terminar com um caractere alfanumérico.

Para obter mais informações, consulte regras de nomenclatura e restrições para recursos Azure.

Implantação inicial

  1. Para implantar o projeto de .NET Aspire, autentique-se no AD Azure para chamar as APIs de gerenciamento de recursos Azure.

    azd auth login
    

    O comando anterior iniciará um navegador para autenticar a sessão de linha de comando.

  2. Depois de autenticado, execute o comando a seguir no diretório de projeto do AppHost para provisionar e implantar o aplicativo.

    azd up
    

    Importante

    Para enviar imagens de contêiner para o Registro de Contêiner do Azure (ACR), você precisa ter acesso Microsoft.Authorization/roleAssignments/write. Isso pode ser feito habilitando um usuário administrador no registro. Abra o Portal do Azure, navegue até o recurso do ACR/Configurações/Chaves de acesso e, em seguida, selecione a caixa de seleção usuário Admin. Para obter mais informações, consulte Ativarusuário administrador.

  3. Quando solicitado, selecione a assinatura e o local em que os recursos devem ser implantados. Depois que essas opções forem selecionadas, o projeto .NET.NET Aspire será implantado.

    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.
    

    A linha final de saída do comando azd é um link para o Portal do Azure que mostra todos os recursos de Azure que foram implantados:

    Captura de tela do Portal do Azure mostrando recursos implantados.

Três contêineres são implantados neste aplicativo:

  • webfrontend: contém código do projeto Web no modelo inicial.
  • apiservice: contém código do projeto de serviço de API no modelo inicial.
  • cache: uma imagem de contêiner Redis para disponibilizar um cache para o front-end.

Assim como no desenvolvimento local, a configuração das cadeias de conexão foi tratada automaticamente. Nesse caso, azd foi responsável por interpretar o modelo de aplicativo e traduzi-lo para as etapas de implantação apropriadas. Por exemplo, considere a cadeia de conexão e as variáveis de descoberta de serviço que são injetadas no contêiner de webfrontend para que ele saiba como se conectar ao cache Redis e apiservice.

Uma captura de tela das variáveis de ambiente no aplicativo de contêiner de webfrontend.

Para obter mais informações sobre como os projetos .NET.NET Aspire lidam com cadeias de conexão e descoberta de serviço, consulte a visão geral da orquestração de .NET.NET Aspire.

Implantar atualizações de aplicativo

Quando o comando azd up é executado, os recursos de Azure subjacentes são provisionados e uma imagem de contêiner é criada e implantada para os aplicativos de contêiner que hospedam o projeto .NET.NET Aspire. Normalmente, quando o desenvolvimento está em andamento e os recursos Azure são implantados, não é necessário provisionar recursos Azure sempre que o código é atualizado. Isso é particularmente válido para o ciclo interno do desenvolvedor.

Para acelerar a implantação de alterações de código, azd dá suporte à implantação de atualizações de código na imagem de contêiner. Isso é feito usando o comando 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>

Não é necessário implantar todos os serviços toda vez. azd entende o modelo de projeto .NET.NET Aspire, é possível implantar apenas um dos serviços especificados usando o seguinte comando:

azd deploy webfrontend

Para obter mais informações, consulte a referência Azure Developer CLI: azd deploy.

Implantar atualizações de infraestrutura

Sempre que a estrutura de dependência dentro de um projeto .NET.NET Aspire for alterada, azd deverá provisionar novamente os recursos de Azure subjacentes. O comando azd provision é usado para aplicar essas alterações à infraestrutura.

Para ver isso em ação, atualize o arquivo Program.cs no projeto AppHost para o seguinte:

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();

Salve o arquivo e emita o seguinte comando:

azd provision

O comando azd provision atualiza a infraestrutura criando um aplicativo de contêiner para hospedar o banco de dados Postgres. O comando azd provision não atualizou as cadeias de conexão do contêiner de apiservice. Para que as cadeias de conexão sejam atualizadas para apontar para o banco de dados Postgres recém-provisionado, o comando azd deploy precisa ser invocado novamente. Quando estiver em dúvida, use azd up para provisionar e implantar.

Limpar recursos

Lembre-se de limpar os recursos de Azure que você criou durante este tutorial. Como o azd conhece o grupo de recursos no qual criou os recursos, ele pode ser usado para encerrar o ambiente usando o seguinte comando:

azd down

O comando anterior pode levar algum tempo para ser executado, mas quando concluído o grupo de recursos e todos os seus recursos devem ser excluídos.

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.

Gerar Bicep a partir do modelo de projeto .NET.NET Aspire

Embora as equipes de desenvolvimento sejam livres para usar comandos azd up (ou azd provision e azd deploy) para suas implantações para fins de desenvolvimento e produção, algumas equipes podem optar por gerar arquivos Bicep que podem examinar e gerenciar como parte do controle de versão (isso também permite que esses arquivos Bicep sejam referenciados como parte de uma implantação de Azure mais complexa).

azd inclui a capacidade de gerar o Bicep que ele usa para provisionamento por meio do seguinte comando:

azd config set alpha.infraSynth on
azd infra synth

Depois que esse comando é executado no exemplo de modelo inicial usado neste guia, os seguintes arquivos são criados no diretório do projeto AppHost:

  • infra/main.bicep: representa o ponto de entrada principal para a implantação.
  • infra/main.parameters.json: usado como parâmetros para o Bicep principal (mapeia para variáveis de ambiente definidas na pasta .azure).
  • infra/resources.bicep: define os recursos de Azure necessários para dar suporte ao modelo de projeto .NET Aspire.
  • AspireSample.Web/manifests/containerApp.tmpl.yaml: a definição do aplicativo de contêiner para webfrontend.
  • AspireSample.ApiService/manifests/containerApp.tmpl.yaml: a definição de aplicativo de contêiner para apiservice.

O arquivo infra\rinfra esources.bicep não contém nenhuma definição dos próprios aplicativos de contêiner (com exceção de aplicativos de contêiner que são dependências como e ):

@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

Para obter mais informações sobre como usar o Bicep para automatizar implantações para Azure, consulte O que é o Bicep?

A definição dos aplicativos de contêiner dos projetos de serviço está contida nos arquivos containerApp/tmpl.yaml no diretório em cada projeto, respectivamente. Aqui está um exemplo do projeto 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

Depois de executar o comando azd infra synth, quando azd provision e azd deploy são chamados, eles usam o Bicep e dão suporte aos arquivos gerados.

Importante

Se azd infra synth for chamado novamente, ele substituirá todos os arquivos modificados por arquivos recém-gerados e solicitará a confirmação antes de fazer isso.

Ambientes isolados para depuração

Como azd facilita o provisionamento de novos ambientes, é possível que cada membro da equipe tenha um ambiente isolado hospedado na nuvem para depurar código em uma configuração que corresponda de perto à produção. Ao fazer isso, cada membro da equipe deve criar seu próprio ambiente usando o seguinte comando:

azd env new

Isso solicitará ao usuário informações de assinatura e grupo de recursos novamente, e as invocações subsequentes azd up, azd provisione azd deploy usarão esse novo ambiente por padrão. A opção --environment pode ser aplicada a esses comandos para alternar entre ambientes.

Limpar recursos

Execute o seguinte comando Azure CLI para excluir o grupo de recursos quando você não precisar mais dos recursos de Azure que você criou. Excluir o grupo de recursos também exclui os recursos contidos nele.

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

Mais informações, consulte Limpeza de recursos em Azure.