Implementación de un proyecto de .NET Aspire en Azure Container Apps mediante el Azure Developer CLI (guía detallada)
El Azure Developer CLI (azd
) se ha ampliado para admitir la implementación de proyectos de .NET.NET Aspire. Use esta guía para recorrer el proceso de creación e implementación de un proyecto de .NET Aspire para Azure Container Apps mediante el Azure Developer CLI. En este tutorial, aprenderá los conceptos siguientes:
- Explorar cómo funciona la integración de
azd
con proyectos de .NET.NET Aspire - Provisión e implementación de recursos en Azure para un proyecto de .NET Aspire mediante
azd
- Generar infraestructura Bicep y otros archivos de plantilla con
azd
Prerrequisitos
Para trabajar con .NET.NET Aspire, necesita lo siguiente instalado localmente:
- .NET 8.0 o .NET 9.0
- Un entorno de ejecución de contenedor compatible con OCI, como:
- Docker escritorio o Podman. Para obtener más información, consulte container runtime.
- Un entorno para desarrolladores integrado (IDE) o un editor de código, como:
- Visual Studio 2022 versión 17.9 o posterior (opcional)
-
Visual Studio Code (opcional)
- C# Dev Kit: extensión (opcional)
- JetBrains Rider con .NET.NET Aspire plugin (opcional)
Para obtener más información, consulte configuración y herramientas de .NET.NET Aspirey sdk de .NET.NET Aspire.
También deberá tener instalado el Azure Developer CLIlocalmente. Entre las opciones de instalación comunes se incluyen las siguientes:
¿Cómo funciona la integración de Azure Developer CLI?
El flujo de trabajo de azd init
proporciona compatibilidad personalizada con proyectos de .NET.NET Aspire. En el diagrama siguiente se muestra cómo funciona conceptualmente este flujo y cómo se integran azd
y .NET.NET Aspire:
- Cuando
azd
tiene como destino un proyecto de .NET.NET Aspire, inicia AppHost con un comando especial (dotnet run --project AppHost.csproj --output-path manifest.json --publisher manifest
), que genera el archivo de manifiesto Aspire. - El archivo de manifiesto es interrogado por la lógica del subcomando
azd provision
para generar archivos Bicep solo en memoria, de forma predeterminada. - Después de generar los archivos de Bicep, se inicia una implementación utilizando las API de ARM de Azure, que tienen como objetivo la suscripción y el grupo de recursos proporcionados anteriormente.
- Una vez configurados los recursos de Azure subyacentes, se ejecuta la lógica de sub command
azd deploy
que usa el mismo archivo de manifiesto Aspire. - Como parte del despliegue,
azd
realiza una llamada adotnet publish
utilizando el soporte integrado de publicación de contenedores de .NETpara generar imágenes de contenedores. - Una vez que
azd
ha creado las imágenes de contenedor, las inserta en el registro de ACR que se creó durante la fase de aprovisionamiento. - Por último, una vez que la imagen de contenedor está en ACR,
azd
actualiza el recurso mediante ARM para empezar a usar la nueva versión de la imagen de contenedor.
Nota
azd
también le permite generar Bicep en una carpeta infra
del proyecto, que puede obtener más información en la sección Generación de Bicep desde .NET.NET Aspire modelo de aplicación.
Aprovisionamiento e implementación de una aplicación inicial para .NET.NET Aspire
Los pasos de esta sección muestran cómo crear una aplicación de inicio de .NET Aspire y controlar el aprovisionamiento e implementar los recursos de la aplicación en Azure mediante azd
.
Crear la aplicación inicial .NET.NET Aspire
Cree un nuevo proyecto de .NET.NET Aspire mediante el comando dotnet new
. También puede crear el proyecto mediante Visual Studio.
dotnet new aspire-starter --use-redis-cache -o AspireSample
cd AspireSample
dotnet run --project AspireSample.AppHost\AspireSample.AppHost.csproj
Los comandos anteriores crean un nuevo proyecto de .NET.NET Aspire basado en la plantilla de aspire-starter
que incluye una dependencia en caché de Redis. Ejecuta el proyecto .NET.NET Aspire que comprueba que todo funciona correctamente.
Inicialización de la plantilla
Abra una nueva ventana de terminal y
cd
en el directorio del proyecto AppHost de la solución de .NET.NET Aspire.Ejecute el comando
azd init
para inicializar el proyecto conazd
, que inspeccionará la estructura del directorio local y determinará el tipo de aplicación.azd init
Para obtener más información sobre el comando
azd init
, vea azd init.Seleccione Usar código en el directorio actual cuando
azd
le pida dos opciones de inicialización de la aplicación.? How do you want to initialize your app? [Use arrows to move, type to filter] > Use code in the current directory Select a template
Después de examinar el directorio,
le pedirá que confirme que encontró el proyecto de AppHost correcto . Seleccione la opción Confirmar y continuar con la inicialización de mi app. 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
Escriba un nombre de entorno, que se usa para asignar un nombre a los recursos aprovisionados en Azure y administrar entornos diferentes, como
dev
yprod
.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
genera una serie de archivos y los coloca en el directorio de trabajo. Estos archivos son:
- azure .yaml: describe los servicios de la aplicación, como .NET Aspire proyecto AppHost, y los asigna a Azure recursos.
-
.azure/config.json: archivo de configuración que informa
azd
cuál es el entorno activo actual. - .azure/aspireazddev/.env: contiene invalidaciones específicas del entorno.
El archivo .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
Al crear nuevos recursos Azure, es importante seguir los requisitos de nomenclatura. Para Azure Container Apps, el nombre debe tener entre 2 y 32 caracteres y consistir en letras minúsculas, números y guiones. El nombre debe comenzar con una letra y terminar con un carácter alfanumérico.
Para obtener más información, consulte Reglas y restricciones de nomenclatura para Azure recursos.
Implementación inicial
Para implementar el proyecto de .NET Aspire, autentíquese en Azure AD para llamar a las API de administración de recursos de Azure.
azd auth login
El comando anterior iniciará un explorador para autenticar la sesión de línea de comandos.
Una vez autenticado, ejecute el siguiente comando desde el directorio del proyecto AppHost para aprovisionar e implementar la aplicación.
azd up
Importante
Para insertar imágenes de contenedor en la Azure Container Registry (ACR), debe tener acceso
Microsoft.Authorization/roleAssignments/write
. Esto se puede lograr habilitando un usuario administrador de en el registro. Abra el portal de, vaya al recurso de ACR/ Configuración /Claves de acceso y, a continuación, active la casilla usuario administrador de . Para obtener más información, consulte Habilitar usuario administrador. Cuando se le solicite, seleccione la suscripción y la ubicación en la que se deben implementar los recursos. Una vez seleccionadas estas opciones, se implementará el proyecto de .NET.NET Aspire.
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 línea final de salida del comando
azd
es un vínculo al portal de Azure que muestra todos los recursos de Azure implementados:
En esta aplicación se implementan tres contenedores:
-
webfrontend
: contiene código del proyecto web en la plantilla de inicio. -
apiservice
: contiene código del proyecto de servicio de API en la plantilla de inicio. -
cache
: una imagen de contenedor de Redis para proporcionar una memoria caché al front-end.
Al igual que en el desarrollo local, la configuración de cadenas de conexión se ha controlado automáticamente. En este caso, azd
era responsable de interpretar el modelo de aplicación y traducirlo a los pasos de implementación adecuados. Por ejemplo, considere las variables de detección de servicio y cadena de conexión que se insertan en el contenedor de webfrontend
para que sepa cómo conectarse a la memoria caché de Redis y apiservice
.
Para obtener más información sobre cómo los proyectos .NET.NET Aspire manejan las cadenas de conexión y el descubrimiento de servicios, véase la introducción a la orquestación .NET.NET Aspire.
Implementación de actualizaciones de aplicaciones
Cuando se ejecuta el comando azd up
, los recursos de Azure subyacentes se aprovisionan y se compila una imagen de contenedor y se implementan en las aplicaciones contenedoras que hospedan el proyecto de .NET.NET Aspire. Normalmente, una vez que el desarrollo está en curso y se implementan los recursos Azure, no será necesario aprovisionar recursos Azure cada vez que se actualice el código; esto es especialmente cierto para el ciclo de desarrollo del programador.
Para acelerar la implementación de cambios de código, azd
admite la implementación de actualizaciones de código en la imagen de contenedor. Esto se hace mediante el 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>
No es necesario implementar todos los servicios cada vez.
azd
entiende el modelo de proyecto de .NET.NET Aspire, es posible implementar solo uno de los servicios especificados mediante el siguiente comando:
azd deploy webfrontend
Para obtener más información, consulte la referencia Azure Developer CLI: azd deploy.
Implementación de actualizaciones de infraestructura
Siempre que cambie la estructura de dependencias de un proyecto de .NET.NET Aspire, azd
debe volver a aprovisionar los recursos de Azure subyacentes. El comando azd provision
se usa para aplicar estos cambios a la infraestructura.
Para ver esto en acción, actualice el archivo Program.cs en el proyecto AppHost a lo siguiente:
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();
Guarde el archivo y emita el siguiente comando:
azd provision
El comando azd provision
actualiza la infraestructura mediante la creación de una aplicación contenedora para hospedar la base de datos de Postgres. El comando azd provision
no actualizó las cadenas de conexión del contenedor de apiservice
. Para que las cadenas de conexión se actualicen para que apunten a la base de datos Postgres recién aprovisionada, el comando azd deploy
debe invocarse de nuevo. En caso de duda, use azd up
para aprovisionar y desplegar.
Limpieza de recursos
Recuerde limpiar los recursos de Azure que ha creado durante este tutorial. Dado que 'azd' conoce el grupo de recursos en el que creó los recursos, se puede utilizar para desactivar el entorno utilizando el siguiente comando:
azd down
El comando anterior puede tardar algún tiempo en ejecutarse, pero cuando se complete el grupo de recursos y se deben eliminar todos sus recursos.
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.
Generar Bicep a partir del modelo de proyecto .NET.NET Aspire
Aunque los equipos de desarrollo pueden usar comandos de azd up
(o azd provision
y azd deploy
) para sus implementaciones con fines de desarrollo y producción, algunos equipos pueden optar por generar archivos de Bicep que pueden revisar y administrar como parte del control de versiones (esto también permite que se haga referencia a estos archivos de Bicep como parte de una implementación de Azure más compleja).
azd
incluye la capacidad de generar el Bicep que utiliza para el aprovisionamiento mediante el siguiente comando:
azd config set alpha.infraSynth on
azd infra synth
Después de ejecutar este comando en el ejemplo de plantilla de inicio que se usa en esta guía, se crean los siguientes archivos en el directorio del proyecto AppHost:
- infra/main.bicep: Representa el punto de entrada principal de la implementación.
- infra/main.parameters.json: se usa como los parámetros para el principal Bicep (se asigna a las variables de entorno definidas en la carpeta .azure).
- infra/resources.bicep: Define los recursos de Azure necesarios para apoyar el modelo de proyecto de .NET Aspire.
-
AspireSample.Web/manifests/containerApp.tmpl.yaml: la definición de la aplicación contenedora para
webfrontend
. -
AspireSample.ApiService/manifests/containerApp.tmpl.yaml: la definición de la aplicación contenedora para
apiservice
.
El archivo infra\resources.bicep no contiene ninguna definición de las aplicaciones de contenedor en sí mismas (con la excepción de las aplicaciones de contenedor que son dependencias, como Redis y 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
Para obtener más información sobre el uso de Bicep para automatizar las implementaciones en Azure consulte ¿Qué es Bicep?
La definición de las aplicaciones de contenedor de los proyectos de servicio de .NET se incluye en los archivos containerApp/tmpl.yaml en el directorio manifests
de cada proyecto, respectivamente. Este es un ejemplo del proyecto de 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
Después de ejecutar el comando azd infra synth
, cuando se llama azd provision
y azd deploy
usan Bicep y admiten archivos generados.
Importante
Si se vuelve a llamar a azd infra synth
, reemplaza los archivos modificados por los generados recientemente y le pide confirmación antes de hacerlo.
Entornos aislados para la depuración
Dado que azd
facilita el aprovisionamiento de nuevos entornos, es posible que cada miembro del equipo tenga un entorno aislado hospedado en la nube para depurar código en una configuración que coincida estrechamente con la producción. Al hacer esto, cada miembro del equipo debe crear su propio entorno mediante el siguiente comando:
azd env new
Esto le pedirá al usuario información de suscripción y grupo de recursos de nuevo y las siguientes azd up
, azd provision
y azd deploy
invocaciones usarán este nuevo entorno de forma predeterminada. El modificador --environment
se puede aplicar a estos comandos para cambiar entre entornos.
Limpieza de recursos
Ejecute el siguiente comando Azure CLI para eliminar el grupo de recursos cuando ya no necesite los recursos de Azure que creó. Al eliminar el grupo de recursos también se eliminan los recursos contenidos en él.
az group delete --name <your-resource-group-name>
Para obtener más información, consulte Limpieza de recursos en Azure.