Nota
O acesso a esta página requer autorização. Pode tentar iniciar sessão ou alterar os diretórios.
O acesso a esta página requer autorização. Pode tentar alterar os diretórios.
O Aspire é uma cadeia de ferramentas para construir, executar, depurar e implementar aplicações distribuídas. A integração do Aspire Funções do Azure permite-lhe desenvolver, depurar e orquestrar um projeto Funções do Azure como parte de um Aspire AppHost. Os exemplos de .NET neste artigo utilizam o modelo de trabalhador isolado.
Pré-requisitos
Configure seu ambiente de desenvolvimento para usar o Funções do Azure com o Aspire:
Instala os pré-requisitos do Aspire, incluindo o SDK .NET exigido pelo teu AppHost.
Instale a integração de alojamento do Aspire Funções do Azure a partir do diretório AppHost.
aspire add Aspire.Hosting.Azure.FunctionsInstale as ferramentas principais do Funções do Azure.
Se usar Visual Studio, instale as últimas atualizações de ferramentas do Visual Studio e Funções do Azure:
- Vá paraOpções de ferramentas>.
- Em Projetos e Soluções, selecione Funções do Azure.
- Selecione Verificar se há atualizações e instale as atualizações conforme solicitado.
Para mais informações sobre o pacote de integração e as APIs AppHost suportadas, consulte Configurar Funções do Azure no AppHost.
Estrutura da solução
Uma solução que utiliza Funções do Azure e Aspire tem vários projetos, incluindo um AppHost e um ou mais projetos Functions.
O AppHost é o ponto de entrada para a sua candidatura. Ele orquestra a configuração dos componentes do seu aplicativo, incluindo o projeto Functions.
A solução normalmente também inclui um projeto de padrões de serviço . Este projeto fornece um conjunto de serviços e configurações padrão para serem usados em projetos em seu aplicativo.
Projeto AppHost
Para configurar com sucesso a integração, certifique-se de que o projeto AppHost cumpre os seguintes requisitos:
- O AppHost faz referência ao Aspire.Hosting.Azure. Functions. Este pacote define a integração.
- Um AppHost C# faz referência a um projeto de Funções e chama
AddAzureFunctionsProject<TProject>(), ou chamaAddAzureFunctionsProject(name, projectPath)com o caminho para o ficheiro do projeto. Os AppHosts de TypeScript utilizam o formato de caminho do projeto deaddAzureFunctionsProject. - Use
AddAzureFunctionsProjectem vez deAddProject. Um projeto de Funções adicionado ao usarAddProjectnão consegue arrancar corretamente.
O exemplo seguinte mostra um ficheiro mínimo AppHost.cs para um projeto C# AppHost:
var builder = DistributedApplication.CreateBuilder(args);
builder.AddAzureFunctionsProject<Projects.MyFunctionsProject>("MyFunctionsProject");
builder.Build().Run();
Projeto do Funções do Azure
Para configurar com êxito a integração, verifique se o projeto do Funções do Azure atende aos seguintes requisitos:
Alvo .NET 8 ou posterior, use o SDK .NET 9 ou posterior, e utilize o modelo de trabalhador isolado.
Referência Microsoft.Azure. Functions.Worker, Microsoft.Azure. Functions.Worker.Sdk e, para gatilhos HTTP, Microsoft.Azure. Functions.Worker.Extensions.Http.AspNetCore.
Seu
Program.csarquivo deve usar aIHostApplicationBuilderversão da inicialização da instância do host. Este requisito significa que deve usarFunctionsApplication.CreateBuilder(args).Se sua solução incluir um projeto de padrão de serviço, certifique-se de que seu projeto do Functions esteja configurado para usá-lo:
- O projeto Functions deve incluir uma referência de projeto ao projeto de definições padrão do serviço.
- Antes de criar
IHostApplicationBuilder,Program.csinclua uma chamada parabuilder.AddServiceDefaults().
O exemplo a seguir mostra um arquivo mínimo Program.cs para um projeto Functions usado no Aspire:
using Microsoft.Azure.Functions.Worker.Builder;
using Microsoft.Extensions.Hosting;
var builder = FunctionsApplication.CreateBuilder(args);
builder.AddServiceDefaults();
builder.ConfigureFunctionsWebApplication();
builder.Build().Run();
Este exemplo não inclui a configuração padrão do Application Insights que aparece em muitos outros Program.cs exemplos e nos modelos do Funções do Azure. Em vez disso, você configura a integração OpenTelemetry no Aspire chamando o builder.AddServiceDefaults() método.
Para tirar o máximo proveito da integração, considere as seguintes diretrizes:
- Não inclua integrações diretas do Application Insights no projeto Functions. Em vez disso, a monitorização no Aspire é tratada através do seu suporte OpenTelemetry. Você pode configurar o Aspire para exportar dados para o Azure Monitor por meio do projeto de padrões de serviço.
- Quando o Aspire executa o projeto Functions, prefira definições injetadas pelo AppHost. Pode manter definições equivalentes em
local.settings.json, para executar o projeto autonomamente comfunc start; as variáveis de ambiente injetadas pelo Aspire substituem-nas.
Configuração da ligação com o Aspire
O AppHost define recursos e ajuda-te a criar ligações entre eles usando código. Esta seção mostra como configurar e personalizar conexões que seu projeto do Funções do Azure usa.
O Aspire inclui permissões de ligação predefinidas que o podem ajudar a começar. No entanto, essas permissões podem não ser apropriadas ou suficientes para seu aplicativo.
Para cenários que usam o RBAC (controle de acesso baseado em função) do Azure, você pode personalizar permissões chamando o WithRoleAssignments() método no recurso do projeto. Quando chamar WithRoleAssignments(), todas as atribuições de funções padrão são removidas, e você deve definir explicitamente todas as atribuições de funções que deseja. Se hospitares a tua aplicação em Apps de Contentores Azure, usar WithRoleAssignments() também requer que chames AddAzureContainerAppEnvironment() em DistributedApplicationBuilder.
Armazenamento de host do Funções do Azure
O Funções do Azure requer uma conexão de armazenamento de host (AzureWebJobsStorage) para vários de seus comportamentos principais. Quando chama AddAzureFunctionsProject<TProject>() no seu AppHost, cria uma conexão AzureWebJobsStorage por predefinição e fornece-a ao projeto Functions. Esta ligação por defeito utiliza o emulador Armazenamento do Azure para execuções de desenvolvimento local e provisiona automaticamente uma conta de armazenamento quando a implementa. Para mais controlo, substitua esta ligação apelando .WithHostStorage() ao recurso do projeto Functions.
As permissões predefinidas que o Aspire define para a ligação ao armazenamento do anfitrião dependem de chamar WithHostStorage() ou não. Adicionar WithHostStorage() faz com que uma atribuição de Colaborador da Conta de Armazenamento seja removida. A tabela a seguir lista as permissões padrão que o Aspire define para a conexão de armazenamento do host:
| Conexão de armazenamento do host | Funções predefinidas |
|---|---|
Nenhuma chamada para WithHostStorage() |
Contribuidor de dados de Blob de armazenamento, Contribuidor de dados da Queue de Armazenamento, Contribuidor de dados da tabela de armazenamento, Contribuidor da Conta de Armazenamento |
Telefonar WithHostStorage() |
Contribuidor de dados de Blob de armazenamento, Contribuidor de dados da Queue de Armazenamento, Colaborador de Tabelas de Dados de Armazenamento |
O exemplo seguinte mostra um ficheiro mínimo AppHost.cs que substitui o armazenamento do host e especifica uma atribuição de funções:
using Azure.Provisioning.Storage;
var builder = DistributedApplication.CreateBuilder(args);
builder.AddAzureContainerAppEnvironment("myEnv");
var myHostStorage = builder.AddAzureStorage("myHostStorage");
builder.AddAzureFunctionsProject<Projects.MyFunctionsProject>("MyFunctionsProject")
.WithHostStorage(myHostStorage)
.WithRoleAssignments(myHostStorage, StorageBuiltInRole.StorageBlobDataOwner);
builder.Build().Run();
Note
Administrador de Dados de Blob de Armazenamento é o papel que recomendamos para as necessidades essenciais da conexão de armazenamento do servidor. A sua aplicação pode encontrar problemas se a ligação ao serviço de blob tiver apenas o padrão Aspire de Colaborador de Dados do Blob de Armazenamento.
Para cenários de produção, inclua chamadas para WithHostStorage() e WithRoleAssignments(). Em seguida, você pode definir essa função explicitamente, juntamente com quaisquer outras que você precisa.
Conexões de gatilho e vinculação
Os seus gatilhos e associações fazem referência a conexões por nome. As seguintes integrações do Aspire proporcionam estas ligações através de uma chamada para o recurso do projeto WithReference().
| Integração Aspire | Funções predefinidas |
|---|---|
| Armazenamento de Blobs do Azure |
Contribuidor de dados de Blob de armazenamento, Contribuidor de dados da Queue de Armazenamento, Colaborador de Tabelas de Dados de Armazenamento |
| Armazenamento de Filas do Azure |
Contribuidor de dados de Blob de armazenamento, Contribuidor de dados da Queue de Armazenamento, Colaborador de Tabelas de Dados de Armazenamento |
| Hubs de Eventos do Azure | Proprietário de Dados dos Hubs de Eventos do Azure |
| Azure Service Bus | Proprietário de Dados do Barramento de Serviço do Azure |
O exemplo seguinte mostra um ficheiro minimalista AppHost.cs que configura um gatilho de fila. Neste exemplo, o gatilho de fila correspondente tem a propriedade Connection definida como MyQueueTriggerConnection, portanto, a chamada para WithReference() especifica o nome.
var builder = DistributedApplication.CreateBuilder(args);
var myAppStorage = builder.AddAzureStorage("myAppStorage").RunAsEmulator();
var queues = myAppStorage.AddQueues("queues");
builder.AddAzureFunctionsProject<Projects.MyFunctionsProject>("MyFunctionsProject")
.WithReference(queues, "MyQueueTriggerConnection");
builder.Build().Run();
Para outras integrações, as chamadas para WithReference definem a configuração de uma maneira diferente. Eles disponibilizam a configuração para integrações de clientes Aspire, mas não para gatilhos e ligações. Para essas integrações, chame WithEnvironment() para passar as informações de conexão para que o gatilho ou a ligação sejam resolvidos.
O exemplo a seguir mostra como definir a variável MyBindingConnection de ambiente para um recurso que expõe uma expressão de cadeia de conexão:
builder.AddAzureFunctionsProject<Projects.MyFunctionsProject>("MyFunctionsProject")
.WithEnvironment("MyBindingConnection", otherIntegration.Resource.ConnectionStringExpression);
Se pretender que tanto as integrações do cliente Aspire como o sistema de gatilhos e ligações utilizem uma conexão, pode configurar ambos WithReference() e WithEnvironment().
Para alguns recursos, a estrutura de uma conexão pode ser diferente entre quando você a executa localmente e quando a publica no Azure. No exemplo anterior, otherIntegration poderia ser um recurso que é executado como um emulador, portanto ConnectionStringExpression , retornaria uma cadeia de conexão do emulador. No entanto, quando o recurso é publicado, o Aspire pode configurar uma ligação baseada em identidade e ConnectionStringExpression devolve o URI do serviço. Nesse caso, para configurar conexões baseadas em identidade para o Funções do Azure, talvez seja necessário fornecer um nome de variável de ambiente diferente.
O exemplo a seguir usa builder.ExecutionContext.IsPublishMode para adicionar condicionalmente o sufixo necessário:
builder.AddAzureFunctionsProject<Projects.MyFunctionsProject>("MyFunctionsProject")
.WithEnvironment("MyBindingConnection" + (builder.ExecutionContext.IsPublishMode ? "__serviceUri" : ""), otherIntegration.Resource.ConnectionStringExpression);
Para obter detalhes sobre os formatos de conexão suportados por cada associação e as permissões que esses formatos exigem, consulte as páginas de referência da ligação.
Para mais informações sobre como o código Functions lê os valores injetados por WithReference, veja Funções do Azure runtime configuration.
Hospedando o aplicativo
Aspire suporta a implementação do Azure Container Apps para projetos Functions. Também pode utilizar a integração de pré-visualização separada do App Service para ter como destino uma aplicação de funções com suporte para contentores:
- Implementar como uma aplicação em contentor
- Implementar como uma aplicação de funções usando a integração de pré-visualização do App Service
Em ambos os casos, seu projeto é implantado como um contêiner. O Aspire encarrega-se de criar a imagem de contentor para si e enviá-la para o Registo de Contentores do Azure.
Implementar como uma aplicação em contentor
Quando o seu AppHost tem como alvo Azure Container Apps, o Aspire define regras de escalabilidade para o seu projeto de Funções usando KEDA. Ao usar Azure Container Apps, é necessário fazer uma configuração extra para as teclas de função. Para mais informações, veja Chaves de Acesso no Azure Container Apps.
Implemente o AppHost configurado executando aspire deploy. Para mais informações, consulte Deploy to Azure Container Apps e aspire deploy.
Chaves de acesso em Aplicativos de Contêiner do Azure
Vários cenários do Funções do Azure usam chaves de acesso para fornecer uma atenuação básica contra acesso indesejado. Por exemplo, as funções de gatilho HTTP por padrão exigem que uma chave de acesso seja invocada, embora esse requisito possa ser desabilitado usando a AuthLevel propriedade. Consulte Trabalhar com chaves de acesso no Funções do Azure para cenários que podem exigir uma chave.
Quando implementas um projeto de Funções usando o Aspire para Azure Container Apps, o sistema não cria ou gere automaticamente as chaves de acesso às Funções. Se precisares de usar chaves de acesso, podes geri-las como parte da configuração do teu AppHost. Esta secção mostra-lhe como criar um método de extensão que possa chamar a partir do ficheiro do AppHost.cs seu AppHost para criar e gerir chaves de acesso. Essa abordagem usa o Cofre da Chave do Azure para armazenar as chaves e as monta no aplicativo de contêiner como segredos.
Note
Este comportamento depende do fornecedor de segredos ContainerApps, que requer a versão 4.1044.0 ou posterior do host do Functions.
Estas etapas requerem a versão 0.38.3 ou posterior do Bicep. Você pode verificar sua versão do Bicep executando bicep --version a partir de um prompt de comando. Se você tiver a CLI do Azure instalada, poderá usar az bicep upgrade para atualizar rapidamente o Bicep para a versão mais recente.
Adicione os seguintes pacotes NuGet ao seu projeto AppHost:
Crie uma nova classe no seu projeto AppHost e inclua o seguinte código:
using Aspire.Hosting.Azure;
using Azure.Provisioning.AppContainers;
namespace Aspire.Hosting;
internal static class Extensions
{
private record SecretMapping(string OriginalName, IAzureKeyVaultSecretReference Reference);
public static IResourceBuilder<T> PublishWithContainerAppSecrets<T>(
this IResourceBuilder<T> builder,
IResourceBuilder<AzureKeyVaultResource>? keyVault = null,
string[]? hostKeyNames = null,
string[]? systemKeyExtensionNames = null)
where T : AzureFunctionsProjectResource
{
if (!builder.ApplicationBuilder.ExecutionContext.IsPublishMode)
{
return builder;
}
keyVault ??= builder.ApplicationBuilder.AddAzureKeyVault("functions-keys");
var hostKeysToAdd = (hostKeyNames ?? []).Append("default").Select(k => $"host-function-{k}");
var systemKeysToAdd = systemKeyExtensionNames?.Select(k => $"host-systemKey-{k}_extension") ?? [];
var secrets = hostKeysToAdd.Union(systemKeysToAdd)
.Select(secretName => new SecretMapping(
secretName,
CreateSecretIfNotExists(builder.ApplicationBuilder, keyVault, secretName.Replace("_", "-"))
)).ToList();
return builder
.WithReference(keyVault)
.WithEnvironment("AzureWebJobsSecretStorageType", "ContainerApps")
.PublishAsAzureContainerApp((infra, app) => ConfigureFunctionsContainerApp(infra, app, builder.Resource, secrets));
}
private static void ConfigureFunctionsContainerApp(
AzureResourceInfrastructure infrastructure,
ContainerApp containerApp,
IResource resource,
List<SecretMapping> secrets)
{
const string volumeName = "functions-keys";
const string mountPath = "/run/secrets/functions-keys";
var appIdentityAnnotation = resource.Annotations.OfType<AppIdentityAnnotation>().Last();
var containerAppIdentityId = appIdentityAnnotation.IdentityResource.Id.AsProvisioningParameter(infrastructure);
var containerAppSecretsVolume = new ContainerAppVolume
{
Name = volumeName,
StorageType = ContainerAppStorageType.Secret
};
foreach (var mapping in secrets)
{
var secret = mapping.Reference.AsKeyVaultSecret(infrastructure);
containerApp.Configuration.Secrets.Add(new ContainerAppWritableSecret()
{
Name = mapping.Reference.SecretName.ToLowerInvariant(),
KeyVaultUri = secret.Properties.SecretUri,
Identity = containerAppIdentityId
});
containerAppSecretsVolume.Secrets.Add(new SecretVolumeItem
{
Path = mapping.OriginalName.Replace("-", "."),
SecretRef = mapping.Reference.SecretName.ToLowerInvariant()
});
}
containerApp.Template.Containers[0].Value!.VolumeMounts.Add(new ContainerAppVolumeMount
{
VolumeName = volumeName,
MountPath = mountPath
});
containerApp.Template.Volumes.Add(containerAppSecretsVolume);
}
public static IAzureKeyVaultSecretReference CreateSecretIfNotExists(
IDistributedApplicationBuilder builder,
IResourceBuilder<AzureKeyVaultResource> keyVault,
string secretName)
{
var secretParameter = ParameterResourceBuilderExtensions.CreateDefaultPasswordParameter(builder, $"param-{secretName}", special: false);
builder.AddBicepTemplateString($"key-vault-key-{secretName}", """
param location string = resourceGroup().location
param keyVaultName string
param secretName string
@secure()
param secretValue string
// Reference the existing Key Vault
resource keyVault 'Microsoft.KeyVault/vaults@2023-07-01' existing = {
name: keyVaultName
}
// Deploy the secret only if it does not already exist
@onlyIfNotExists()
resource newSecret 'Microsoft.KeyVault/vaults/secrets@2023-07-01' = {
parent: keyVault
name: secretName
properties: {
value: secretValue
}
}
""")
.WithParameter("keyVaultName", keyVault.GetOutput("name"))
.WithParameter("secretName", secretName)
.WithParameter("secretValue", secretParameter);
return keyVault.GetSecret(secretName);
}
}
Pode então usar este método no ficheiro do seu AppHost AppHost.cs :
builder.AddAzureFunctionsProject<Projects.MyFunctionsProject>("MyFunctionsProject")
.WithHostStorage(storage)
.WithExternalHttpEndpoints()
.PublishWithContainerAppSecrets(systemKeyExtensionNames: ["mcp"]);
Este exemplo usa um cofre de chave padrão criado pelo método extension. Isso resulta em uma chave padrão e uma chave do sistema para uso com a extensão Model Context Protocol.
Para usar essas chaves de clientes, você precisa recuperá-las do cofre de chaves.
Implementar como uma aplicação de funções
Note
A implementação como aplicação de funções requer a integração do Aspire Serviço de Aplicações do Azure, que se encontra atualmente em pré-visualização.
Pode configurar o Aspire para implementar numa aplicação de funções ao utilizar a integração do Aspire Serviço de Aplicações do Azure. Como o Aspire implementa o projeto Functions como um contentor, o plano de alojamento da sua aplicação de funções deve suportar a implementação de aplicações containerizadas.
Para implementar o seu projeto Aspire Functions como uma aplicação de funções, siga estes passos:
- A partir do diretório AppHost, execute
aspire add Aspire.Hosting.Azure.AppServicepara adicionar o pacote Aspire.Hosting.Azure. AppService NuGet. - No arquivo
AppHost.cs, chameAddAzureAppServiceEnvironment()na suaIDistributedApplicationBuilderinstância para criar um plano de Serviço de Aplicações. Note-se que, apesar do nome, este não provisiona um recurso de Ambiente de Serviço de Aplicações. - No recurso do projeto Funções, chame
.WithExternalHttpEndpoints(). Isto é exigido para a implantação com a integração do Aspire Serviço de Aplicações do Azure. - No recurso do projeto Funções, chame
.PublishAsAzureAppServiceWebsite((infra, app) => app.Kind = "functionapp,linux")para personalizar esse projeto como uma aplicação de funções no plano.
Importante
Certifique-se de definir a app.Kind propriedade como "functionapp,linux". Essa configuração garante que o recurso seja criado como um aplicativo de função, o que afeta as experiências de trabalho com seu aplicativo.
O exemplo seguinte mostra um ficheiro mínimo AppHost.cs que implementa um projeto de Funções como uma aplicação de funções:
var builder = DistributedApplication.CreateBuilder(args);
builder.AddAzureAppServiceEnvironment("functions-env");
builder.AddAzureFunctionsProject<Projects.MyFunctionsProject>("MyFunctionsProject")
.WithExternalHttpEndpoints()
.PublishAsAzureAppServiceWebsite((infra, app) => app.Kind = "functionapp,linux");
builder.Build().Run();
Esta configuração cria um plano Premium V3. Ao usar uma SKU de Plano de Serviço de Aplicações dedicado, o dimensionamento não depende de eventos. Em vez disso, o dimensionamento é gerenciado por meio das configurações do plano do Serviço de Aplicativo.
Considerações e práticas recomendadas
Considere os seguintes pontos ao avaliar a integração do Funções do Azure com o Aspire:
A configuração de acionamento e vinculação através do Aspire está atualmente limitada a integrações específicas. Para obter detalhes, consulte Configuração de conexão com o Aspire neste artigo.
O arquivo
Program.csdo seu projeto de função deve usar aIHostApplicationBuilderversão da inicialização da instância do host. Ao usarIHostApplicationBuilder, pode chamarbuilder.AddServiceDefaults()para adicionar Predefinições de Serviço do Aspire ao seu projeto do Functions.O Aspire utiliza o OpenTelemetry para monitorização. Você pode configurar o Aspire para exportar dados para o Azure Monitor por meio do projeto de padrões de serviço.
Em muitos outros contextos do Funções do Azure, pode-se incluir a integração direta com o Application Insights ao registar o serviço de trabalho. Não registe uma segunda canalização direta para o Application Insights quando estiver a utilizar as Predefinições de Serviço do Aspire.
Para projetos do Functions integrados numa orquestração do Aspire, o AppHost deve fornecer a maior parte da configuração da aplicação. Pode usar
local.settings.jsonpara executar o projeto Functions de forma independente comfunc start. Quando o Aspire executa o projeto, as variáveis de ambiente injetadas pelo Aspire substituem os valores com o mesmo nome nolocal.settings.json.Evite iniciar um segundo emulador de Armazenamento do Azure para ligações que o AppHost gere. Instâncias concorrentes de emuladores podem causar conflitos de portas e armazenamento.
Para mais informações, consulte configuração em tempo de execução do Funções do Azure e telemetria do Aspire.