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:
- .NET 8.0 ou .NET 9.0
- Um runtime de contêiner compatível com OCI, como:
- Docker computador de mesa ou Podman. Para obter mais informações, consulte contêiner runtime.
- Um IDE (Ambiente de Desenvolvedor Integrado) ou um 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 plug-in (opcional)
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:
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:
- 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. - O arquivo de manifesto é interrogado pela lógica do subcomando
azd provision
para gerar arquivos Bicep apenas em memória (por padrão). - Depois de gerar os arquivos Bicep, uma implantação é disparada usando as APIs ARM de Azuredirecionadas à assinatura e ao grupo de recursos fornecidos anteriormente.
- 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. - Como parte da implantação
azd
, faz uma chamada paradotnet publish
usando o suporte embutido de publicação de contêineres de .NETpara gerar imagens de contêineres. - 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. - 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
Abra uma nova janela de terminal e
cd
no diretório de projeto do AppHost de sua solução de .NET.NET Aspire.Execute o comando
azd init
para inicializar seu projeto comazd
, 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.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
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
Insira um nome de ambiente, que é usado para nomear recursos provisionados em 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 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
# 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
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.
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.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:
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
.
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
@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 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 provision
e 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.