Partilhar via


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

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

  • Explore como funciona a integração azd com projetos .NET.NET Aspire
  • Provisionar e implantar recursos no Azure para um projeto .NET Aspire usando azd
  • Gere a infraestrutura do Bicep e outros ficheiros 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 configuração e ferramentas e .NET.NET Aspire SDK.

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

winget install microsoft.azd

Como funciona a integração Azure Developer CLI

O fluxo de trabalho azd init oferece 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 de 'azd' ao implantar .NET.NET Aspire projeto.

  1. Quando azd tem como alvo um projeto .NET.NET Aspire, 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 de subcomando azd provision para gerar arquivos Bicep somente na memória (por padrão).
  3. Depois de gerar os ficheiros Bicep, uma implementação é iniciada utilizando as APIs ARM do Azuredirecionadas à subscrição e ao grupo de recursos fornecidos anteriormente.
  4. Uma vez que os recursos de Azure subjacentes são configurados, a lógica de subcomando azd deploy é executada que usa o mesmo arquivo de manifesto Aspire.
  5. Como parte da implantação, azd faz uma chamada para dotnet publish usando o suporte de publicação de contêiner interno do .NETpara gerar imagens de contêiner.
  6. Depois que azd cria as imagens de contêiner, ele as envia por push para o registro ACR que foi criado durante a fase de provisionamento.
  7. Finalmente, quando a imagem do contêiner estiver no ACR, o azd atualiza o recurso usando o ARM para começar a usar a nova versão da imagem do contêiner.

Observação

azd também permite exportar o Bicep gerado para uma pasta infra no seu projeto, sobre o qual você pode ler mais na secção , Gerando Bicep a partir do modelo de aplicação .NET.NET Aspire.

Fornecer e implantar uma aplicação inicial .NET.NET Aspire

As etapas nesta seção demonstram como criar uma aplicação de início .NET Aspire e gerir o provisionamento e a implantação dos recursos da aplicação para Azure utilizando azd.

Criar o aplicativo inicial .NET.NET Aspire

Crie um novo projeto .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 .NET.NET Aspire com base no modelo aspire-starter que inclui uma dependência Redis cache. 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 AppHost do projeto de sua solução .NET.NET Aspire.

  2. Execute o comando azd init para inicializar seu projeto com azd, que inspecionará a estrutura de diretórios 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 do 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, solicita-lhe que confirme se encontrou o projeto 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 no 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 ficheiros são:

  • azure.yaml: Descreve os serviços da aplicação, como o projeto AppHost .NET Aspire, e mapeia-os para os recursos Azure.
  • .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 de .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

Ao criar novos recursos de 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 hífenes. O nome deve começar com uma letra e terminar com um caractere alfanumérico.

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

Implantação inicial

  1. Para implantar o projeto .NET Aspire, autentique-se no Azure AD 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. Uma vez autenticado, execute o seguinte comando a partir do diretório AppHost do projeto para provisionar e implantar o aplicativo.

    azd up
    

    Importante

    Para enviar imagens de contêiner para o Azure Container Registry (ACR), você precisa ter acesso Microsoft.Authorization/roleAssignments/write. Isso pode ser conseguido habilitando um usuário Admin no registro. Abra o Azure Portal, navegue até ao recurso ACR / Configurações / Chaves de acesso e marque a caixa de seleção Utilizador administrador. Para obter mais informações, consulte Habilitar o usuário administrador.

  3. Quando solicitado, selecione a assinatura e o local para o qual os recursos devem ser implantados. Uma vez selecionadas essas opções, 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 Azure mostrando os recursos implantados.

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

  • webfrontend: Contém o 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 fornecer um cache para o front-end.

Assim como no desenvolvimento local, a configuração de 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. Como exemplo, considere a cadeia de conexão e as variáveis de descoberta de serviço que são injetadas no contêiner webfrontend para que ele saiba como se conectar ao cache Redis e apiservice.

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

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

Implantar atualizações de aplicativos

Quando o comando azd up é executado, os recursos de Azure subjacentes são provisionados e uma imagem de contêiner é criada e implantada nos aplicativos de contêiner que hospedam o projeto .NET.NET Aspire. Normalmente, quando o desenvolvimento já estiver em andamento e recursos Azure forem implantados, não será necessário provisionar recursos Azure toda vez que o código for atualizado — isso é especialmente verdadeiro para o ciclo interno do desenvolvedor.

Para acelerar a implantação de alterações de código, o azd oferece suporte à implantação de atualizações de código na imagem do 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 de cada 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 mudar, azd deve reatribuir os recursos subjacentes de Azure. 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 execute 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 para o contêiner 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. Em caso de dúvida, use azd up para provisionar e implantar.

Limpar recursos

Lembre-se de limpar os recursos Azure que você criou durante este passo a passo. Como o `azd` conhece o grupo de recursos no qual os recursos foram criados, pode ser usado para desativar 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, tanto para fins de desenvolvimento quanto de produção, algumas equipes podem optar por gerar arquivos Bicep que podem revisar 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 maior e mais complexa).

azd inclui a capacidade de produzir 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 principal ponto de entrada para a implantação.
  • infra/main.parameters.json: Usado como parâmetros para o Bicep principal (que se correlacionam com as variáveis de ambiente definidas na pasta azure).
  • infra/resources.bicep: Define os recursos Azure necessários para suportar o modelo de projeto .NET Aspire.
  • AspireSample.Web/manifests/containerApp.tmpl.yaml: A definição de aplicativo de contêiner para webfrontend.
  • AspireSample.ApiService/manifests/containerApp.tmpl.yaml: A definição de aplicativo de contêiner para apiservice.

O arquivo esources.bicep infra\rnão contém qualquer definição das aplicações de contentor propriamente ditas (exceto para as aplicações de contentor 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 é Bicep?

A definição dos aplicativos de contêiner dos projetos de serviço está contida nos arquivos de 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, passam a usar o Bicep e os arquivos gerados de suporte.

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 fazê-lo.

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 depuração de código em uma configuração que corresponda à 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 azd up, azd provisione azd deploy invocações subsequentes 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 não precisar mais dos recursos Azure criados. A exclusão do grupo de recursos também exclui os recursos contidos nele.

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

Para obter mais informações, consulte Limpeza de recursos no Azure.