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:
- .NET 8,0 ou .NET 9,0
- Um tempo de execução de contêiner compatível com OCI, como:
- Docker Ambiente de Trabalho ou Podman. Para obter mais informações, consulte Container runtime.
- Um ambiente de desenvolvedor integrado (IDE) ou editor de código, como:
- Visual Studio 2022 versão 17.9 ou superior (opcional)
-
Visual Studio Code (Opcional)
- C# Dev Kit: Extensão (Opcional)
- JetBrains Rider com .NET.NET Aspire plugin (Opcional)
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:
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:
- 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. - O arquivo de manifesto é interrogado pela lógica de subcomando
azd provision
para gerar arquivos Bicep somente na memória (por padrão). - 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.
- 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. - Como parte da implantação,
azd
faz uma chamada paradotnet publish
usando o suporte de publicação de contêiner interno do .NETpara gerar imagens de contêiner. - 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. - 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
Abra uma nova janela de terminal e
cd
no diretório AppHost do projeto de sua solução .NET.NET Aspire.Execute o comando
azd init
para inicializar seu projeto comazd
, 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.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
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
Insira um nome de ambiente, que é usado para nomear recursos provisionados no Azure e gerenciar ambientes diferentes, como
dev
eprod
.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
# 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
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.
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.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:
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
.
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
@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 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 provision
e 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.