Dela via


Anpassa Azure resurser

Om du använder Azure för att vara värd för resurser för en .NET Aspire lösning har du detaljerad kontroll över dessa resurser. Du kan antingen låta .NET.NET Aspire konfigurera dem om standardegenskaperna passar dina behov eller åsidosätta standardvärden för att styra deras beteende. Nu ska vi undersöka hur du kan anpassa infrastrukturen Azure från .NET Aspire kod.

Azure SDK för .NET innehåller 📦Azure.Provisioning NuGet-paket och en uppsättning tjänstspecifika Azure provisioningpaket. Dessa Azure provisioneringsbibliotek gör det enkelt att deklarativt specificera Azure infrastruktur inbyggt i .NET. Med deras API:er kan du skriva objektorienterad infrastruktur i C#, vilket resulterar i Bicep. Bicep är ett domänspecifikt språk (DSL) för att distribuera Azure resurser deklarativt.

Det är möjligt att etablera Azure resurser manuellt, men .NET Aspire förenklar processen genom att tillhandahålla en uppsättning API:er för att uttrycka Azure resurser. Dessa API:er är tillgängliga som tilläggsmetoder i .NET AspireAzure värdbibliotek, vilket utökar IDistributedApplicationBuilder-gränssnittet. När du adderar Azure resurser till din applikationsvärd, läggs lämplig provisioneringsfunktionalitet till på ett implicit sätt. Med andra ord behöver du inte anropa några etablerings-API:er direkt.

Eftersom .NET Aspire modellerar Azure resurser inom Azure värdintegrationer används Azure SDK för att tillhandahålla dessa resurser. Bicep-filer genereras för att definiera de Azure-resurser som behövs. De genererade Bicep-filerna matas ut tillsammans med manifestfilen när du publicerar din app.

Det finns flera sätt att påverka de genererade Bicep-filerna:

Lokal provisionering och Azure.Provisioning

För att undvika att sammanblanda termer och för att förenkla förståelsen av "tilldelning" är det viktigt att förstå skillnaden mellan lokal tilldelning och Azure tilldelning:

  • Lokal tilldelning:

    Som standard, när du anropar någon av värdintegrerings-API:erna för att lägga till Azure-resurser, anropas Azure-API:et implicit. Det här API:et registrerar tjänster i DI-behållaren (dependency injection) som används för att tillhandahålla Azure resurser när appvärden startar. Detta begrepp kallas lokal provisionering. Mer information finns i Lokal Azure försörjning.

  • Azure.Provisioning:

    Azure.Provisioning refererar till NuGet-paketet och är en uppsättning bibliotek som gör att du kan använda C# för att generera Bicep. Hostingintegreringarna i Azure använder dessa bibliotek i bakgrunden för att generera Bicep-filer som definierar de .NET Aspire resurser du behöver. För mer information, se Azure.Provisioning anpassning.

Azure.Provisioning anpassning

Alla .NET AspireAzure hostingintegreringar exponerar olika Azure resurser, och de är alla underklasser av typen AzureProvisioningResource – som själv ärver från AzureBicepResource. Detta möjliggör tillägg som är allmänt typbegränsade till den här typen, vilket gör det möjligt för ett fluent-API att anpassa infrastrukturen efter dina behov. Även om .NET.NET Aspire tillhandahåller standardvärden kan du påverka den genererade Bicep med hjälp av dessa API:er.

Konfigurera infrastruktur

Oavsett vilken Azure-resurs du arbetar med kedjar du ett anrop till ConfigureInfrastructure-tilläggsmetoden för att konfigurera dess underliggande infrastruktur. Med den här metoden kan du anpassa infrastrukturen för den Azure resursen genom att skicka ett configure ombud av typen Action<AzureResourceInfrastructure>. Den AzureResourceInfrastructure typen är en underklass av Azure.Provisioning.Infrastructure. Den här typen exponerar en massiv API-yta för att konfigurera den underliggande infrastrukturen för den Azure resursen.

Tänk på följande exempel:

var sku = builder.AddParameter("storage-sku");

var storage = builder.AddAzureStorage("storage")
    .ConfigureInfrastructure(infra =>
    {
        var resources = infra.GetProvisionableResources();

        var storageAccount = resources.OfType<StorageAccount>().Single();

        storageAccount.Sku = new StorageSku
        {
            Name = sku.AsProvisioningParameter(infra)
        };
    });

Föregående kod:

  • Lägger till en parameter med namnet storage-sku.
  • Lägger till Azure Storage med AddAzureStorage-API:et som heter storage.
  • Kedjar ett anrop till ConfigureInfrastructure för att anpassa Azure Storage-infrastrukturen:

Detta exemplifierar flödet av en extern parameter till Azure Storage-infrastrukturen, vilket resulterar i att den genererade Bicep-filen återspeglar den önskade konfigurationen.

Lägg till Azure infrastruktur

Alla Azure tjänster exponeras inte som .NET Aspire integreringar. Även om de kan finnas vid ett senare tillfälle kan du fortfarande etablera tjänster som är tillgängliga i Azure.Provisioning.* bibliotek. Föreställ dig ett scenario där du har en arbetarservice som ansvarar för att hantera ett Azure containerregister. Anta nu att ett programvärdprojekt är beroende av 📦Azure. Provisioning.ContainerRegistry NuGet-paket.

Du kan använda AddAzureInfrastructure API:et för att lägga till Azure Container Registry-infrastrukturen i appens värd.

var acr = builder.AddAzureInfrastructure("acr", infra =>
{
    var registry = new ContainerRegistryService("acr")
    {
        Sku = new()
        {
            Name = ContainerRegistrySkuName.Standard
        },
    };
    infra.Add(registry);

    var output = new ProvisioningOutput("registryName", typeof(string))
    {
        Value = registry.Name
    };
    infra.Add(output);
});

builder.AddProject<Projects.WorkerService>("worker")
       .WithEnvironment(
            "ACR_REGISTRY_NAME",
            new BicepOutputReference("registryName", acr.Resource));

Föregående kod:

  • Anropar AddAzureInfrastructure med namnet acr.
  • Tillhandahåller ett configureInfrastructure ombud för att anpassa Azure Container Registry-infrastrukturen:
    • Skapar en ContainerRegistryService med namnet acr och en standard-SKU.
    • Lägger till Azure Container Registry-tjänsten i variabeln infra.
    • Instansierar en ProvisioningOutput med namnet registryName, en typ av stringoch ett värde som motsvarar namnet på Azure Container Registry.
    • Lägger till utdata i variabeln infra.
  • Lägger till ett projekt med namnet worker till byggaren.
  • Kopplar ett anrop till WithEnvironment för att ställa in miljövariabeln ACR_REGISTRY_NAME i projektet till värdet av registryName:s utdata.

Funktionen visar hur du lägger till Azure infrastruktur i värdprojekt för appen, även om Azure-tjänsten inte direkt exponeras som en .NET Aspire-integration. Den visar vidare hur man leder utdata från Azure Container Registry till ett beroende projekts miljö.

Överväg den resulterande Bicep-filen:

@description('The location for the resource(s) to be deployed.')
param location string = resourceGroup().location

resource acr 'Microsoft.ContainerRegistry/registries@2023-07-01' = {
  name: take('acr${uniqueString(resourceGroup().id)}', 50)
  location: location
  sku: {
    name: 'Standard'
  }
}

output registryName string = acr.name

Bicep-filen återspeglar den önskade konfigurationen av Azure Container Registry, enligt definitionen i AddAzureInfrastructure-API:et.

Använd anpassade Bicep-mallar

När du riktar in dig på Azure som önskad molnleverantör kan du använda Bicep för att definiera infrastrukturen som kod. Syftet är att drastiskt förenkla redigeringsupplevelsen med en renare syntax och bättre stöd för modularitet och återanvändning av kod.

Även om .NET.NET Aspire tillhandahåller en uppsättning fördefinierade Bicep-mallar kan det finnas tillfällen då du antingen vill anpassa mallarna eller skapa egna. I det här avsnittet beskrivs de begrepp och motsvarande API:er som du kan använda för att anpassa Bicep-mallarna.

Viktigt!

Det här avsnittet är inte avsett att lära dig Bicep, utan snarare för att ge vägledning om hur du skapar anpassade Bicep-mallar för användning med .NET.NET Aspire.

Som en del av Azure implementeringsberättelsen för .NET Aspireger Azure Developer CLI (azd) förståelse för ditt projekt .NET Aspire och ger möjlighet att distribuera det till Azure. azd CLI använder Bicep-mallarna för att distribuera programmet till Azure.

Installera Aspire.Hosting.Azure paket

När du vill referera till Bicep-filer är det möjligt att du inte använder någon av de Azure värdintegreringar. I det här fallet kan du fortfarande referera till Bicep-filer genom att installera Aspire.Hosting.Azure-paketet. Det här paketet innehåller nödvändiga API:er för att referera till Bicep-filer och anpassa Azure resurser.

Tips/Råd

Om du använder någon av hostingintegreringarna Azure behöver du inte installera paketet Aspire.Hosting.Azure eftersom det är ett transitivt beroende.

Om du vill använda någon av de här funktionerna 📦Aspire.Hosting.Azure NuGet-paketet måste vara installerat:

dotnet add package Aspire.Hosting.Azure

Mer information finns i dotnet lägg till paket eller Hantera paketberoenden i .NET applikationer.

Vad du kan förvänta dig av exemplen

Alla exempel i det här avsnittet förutsätter att du använder Aspire.Hosting.Azure namnområdet. Dessutom förutsätter exemplen att du har en IDistributedApplicationBuilder instans:

using Aspire.Hosting.Azure;

var builder = DistributedApplication.CreateBuilder(args);

// Examples go here...

builder.Build().Run();

När du anropar någon av Bicep-relaterade API:er görs som standard även ett anrop till AddAzureProvisioning som lägger till stöd för att generera Azure resurser dynamiskt under programstarten. Mer information finns i Lokal tillhandahållande och Azure.Provisioning.

Referensfiler för Bicep

Anta att du har en Bicep-mall i en fil med namnet storage.bicep som etablerar ett Azure Storage-konto:

param location string = resourceGroup().location
param storageAccountName string = 'toylaunch${uniqueString(resourceGroup().id)}'

resource storageAccount 'Microsoft.Storage/storageAccounts@2021-06-01' = {
  name: storageAccountName
  location: location
  sku: {
    name: 'Standard_LRS'
  }
  kind: 'StorageV2'
  properties: {
    accessTier: 'Hot'
  }
}

Om du vill lägga till en referens till Bicep-filen på disken anropar du metoden AddBicepTemplate. Tänk på följande exempel:

builder.AddBicepTemplate(
    name: "storage",
    bicepFile: "../infra/storage.bicep");

Föregående kod lägger till en referens till en Bicep-fil som finns på ../infra/storage.bicep. Filsökvägarna ska vara i förhållande till appvärdprojektet. Den här referensen resulterar i att en AzureBicepResource läggs till i programmets resurssamling med namnet "storage", och API:et returnerar en IResourceBuilder<AzureBicepResource> instans som kan användas för att anpassa resursen ytterligare.

Referens Bicep övergripande

Det vanligaste scenariot är att ha en Bicep-fil på disk, men du kan också lägga till Bicep-mallar direkt i koden. Infogade mallar kan vara användbara när du vill definiera en mall i kod eller när du vill generera mallen dynamiskt. Om du vill lägga till en inbäddad Bicep-mall anropar du metoden AddBicepTemplateString med Bicep-mallen som en string. Tänk på följande exempel:

builder.AddBicepTemplateString(
        name: "ai",
        bicepContent: """
        @description('That name is the name of our application.')
        param cognitiveServiceName string = 'CognitiveService-${uniqueString(resourceGroup().id)}'

        @description('Location for all resources.')
        param location string = resourceGroup().location

        @allowed([
          'S0'
        ])
        param sku string = 'S0'

        resource cognitiveService 'Microsoft.CognitiveServices/accounts@2021-10-01' = {
          name: cognitiveServiceName
          location: location
          sku: {
            name: sku
          }
          kind: 'CognitiveServices'
          properties: {
            apiProperties: {
              statisticsEnabled: false
            }
          }
        }
        """
    );

I det här exemplet definieras Bicep-mallen som en inbäddad string och läggs till i programmets resurssamling med namnet "ai". Det här exemplet skapar en Azure AI-resurs.

Skicka parametrar till Bicep-mallar

Bicep stöder godkännande av parametrar, som kan användas för att anpassa mallens beteende. Om du vill skicka parametrar till en Bicep-mall från .NET.NET Aspirekedjar du anrop till metoden WithParameter enligt följande exempel:

var region = builder.AddParameter("region");

builder.AddBicepTemplate("storage", "../infra/storage.bicep")
       .WithParameter("region", region)
       .WithParameter("storageName", "app-storage")
       .WithParameter("tags", ["latest","dev"]);

Föregående kod:

  • Lägger till en parameter med namnet "region" till builder-instansen.
  • Lägger till en referens till en Bicep-fil som finns på ../infra/storage.bicep.
  • Skickar parametern "region" till Bicep-mallen, som löses med standardmetoden för parameterupplösning.
  • Skickar "storageName"-parametern till Bicep-mallen med ett hårdkodat värde.
  • Skickar parametern "tags" till Bicep-mallen med en matris med strängar.

Mer information finns i Externa parametrar.

Välkända parametrar

.NET .NET Aspire innehåller en uppsättning välkända parametrar som kan skickas till Bicep-mallar. Dessa parametrar används för att ge information om programmet och miljön till Bicep-mallarna. Följande välkända parametrar är tillgängliga:

Fält Beskrivning Värde
AzureBicepResource.KnownParameters.KeyVaultName Namnet på nyckelvalvsresursen som används för att lagra hemliga utdata. "keyVaultName"
AzureBicepResource.KnownParameters.Location Platsen för resursen. Detta krävs för alla resurser. "location"
AzureBicepResource.KnownParameters.LogAnalyticsWorkspaceId Resurs-ID för log analytics-arbetsytan. "logAnalyticsWorkspaceId"
AzureBicepResource.KnownParameters.PrincipalId Huvud-ID för den aktuella användaren eller den hanterade identiteten. "principalId"
AzureBicepResource.KnownParameters.PrincipalName Huvudnamnet för den aktuella användaren eller den hanterade identiteten. "principalName"
AzureBicepResource.KnownParameters.PrincipalType Huvudtypen för den aktuella användaren eller den hanterade identiteten. Antingen User eller ServicePrincipal. "principalType"

Om du vill använda en välkänd parameter skickar du parameternamnet till metoden WithParameter, till exempel WithParameter(AzureBicepResource.KnownParameters.KeyVaultName). Du skickar inte värden för välkända parametrar eftersom .NET.NET Aspire löser dem åt dig.

Tänk dig ett exempel där du vill konfigurera en Azure Event Grid-webhook. Du kan definiera Bicep-mallen på följande sätt:

param topicName string
param webHookEndpoint string
param principalId string
param principalType string
param location string = resourceGroup().location

// The topic name must be unique because it's represented by a DNS entry. 
// must be between 3-50 characters and contain only values a-z, A-Z, 0-9, and "-".

resource topic 'Microsoft.EventGrid/topics@2023-12-15-preview' = {
  name: toLower(take('${topicName}${uniqueString(resourceGroup().id)}', 50))
  location: location

  resource eventSubscription 'eventSubscriptions' = {
    name: 'customSub'
    properties: {
      destination: {
        endpointType: 'WebHook'
        properties: {
          endpointUrl: webHookEndpoint
        }
      }
    }
  }
}

resource EventGridRoleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = {
  name: guid(topic.id, principalId, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'd5a91429-5739-47e2-a06b-3470a27159e7'))
  scope: topic
  properties: {
    principalId: principalId
    principalType: principalType
    roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'd5a91429-5739-47e2-a06b-3470a27159e7')
  }
}

output endpoint string = topic.properties.endpoint

Den här Bicep-mallen definierar flera parametrar, inklusive topicName, webHookEndpoint, principalId, principalTypeoch den valfria location. Om du vill skicka dessa parametrar till Bicep-mallen kan du använda följande kodfragment:

var webHookApi = builder.AddProject<Projects.WebHook_Api>("webhook-api");

var webHookEndpointExpression = ReferenceExpression.Create(
        $"{webHookApi.GetEndpoint("https")}/hook");

builder.AddBicepTemplate("event-grid-webhook", "../infra/event-grid-webhook.bicep")
       .WithParameter("topicName", "events")
       .WithParameter(AzureBicepResource.KnownParameters.PrincipalId)
       .WithParameter(AzureBicepResource.KnownParameters.PrincipalType)
       .WithParameter("webHookEndpoint", () => webHookEndpointExpression);
  • Det webHookApi projektet läggs till som en referens till builder.
  • Parametern topicName tilldelas ett hårdkodat namnvärde.
  • Parametern webHookEndpoint skickas som ett uttryck som löses till URL:en från api-projektreferensernas "https"-slutpunkt med /hook-rutten.
  • Parametrarna principalId och principalType skickas som välkända parametrar.

De välkända parametrarna är konventionsbaserade och bör inte åtföljas av ett motsvarande värde när de skickas med hjälp av WithParameter-API:et. Välkända parametrar förenklar vissa vanliga funktioner, till exempel rolltilldelningar, när de läggs till i Bicep-mallarna, som du ser i föregående exempel. Rolltilldelningar krävs för att Event Grid-webhooken ska skicka händelser till den angivna slutpunkten. Mer information finns i rolltilldelningen Event Grid Data Sender.

Hämta utdata från referenser i Bicep

Förutom att skicka parametrar till Bicep-mallar kan du även hämta utdata från Bicep-mallarna. Överväg följande Bicep-mall eftersom den definierar en output med namnet endpoint:

param storageName string
param location string = resourceGroup().location

resource myStorageAccount 'Microsoft.Storage/storageAccounts@2019-06-01' = {
  name: storageName
  location: location
  kind: 'StorageV2'
  sku:{
    name:'Standard_LRS'
    tier: 'Standard'
  }
  properties: {
    accessTier: 'Hot'
  }
}

output endpoint string = myStorageAccount.properties.primaryEndpoints.blob

Bicep definierar ett utdata med namnet endpoint. Om du vill hämta utdata från Bicep-mallen anropar du metoden GetOutput på en IResourceBuilder<AzureBicepResource>-instans, vilket visas i följande C#-kodfragment:

var storage = builder.AddBicepTemplate(
        name: "storage",
        bicepFile: "../infra/storage.bicep"
    );

var endpoint = storage.GetOutput("endpoint");

I det här exemplet hämtas utdata från Bicep-mallen och lagras i en endpoint variabel. Vanligtvis skickar du dessa utdata som en miljövariabel till en annan resurs som förlitar sig på den. Om du till exempel hade ett ASP.NET Core minimalt API-projekt som var beroende av den här slutpunkten kan du skicka utdata som en miljövariabel till projektet med hjälp av följande kodfragment:

var storage = builder.AddBicepTemplate(
                name: "storage",
                bicepFile: "../infra/storage.bicep"
            );

var endpoint = storage.GetOutput("endpoint");

var apiService = builder.AddProject<Projects.AspireSample_ApiService>(
        name: "apiservice"
    )
    .WithEnvironment("STORAGE_ENDPOINT", endpoint);

Mer information finns i Bicep-utdata.

Hämta hemliga utdata från Bicep-referenser

Det är viktigt att undvika utdata av hemligheter vid arbete med Bicep. Om utdata anses vara en hemlighet, vilket innebär att den inte ska exponeras i loggar eller på andra platser, kan du behandla den som sådan. Detta kan uppnås genom att lagra hemligheten i Azure Key Vault och referera till den i Bicep-mallen. .NET Aspire's Azure integrering ger ett mönster för säker lagring av utdata från Bicep-mallen genom att tillåta resurser att använda parametern keyVaultName för att lagra hemligheter i Azure Key Vault.

Tänk på följande Bicep-mall som ett exempel på hur du kan demonstrera det här konceptet med att skydda hemliga utdata:

param databaseAccountName string
param keyVaultName string

param databases array = []

@description('Tags that will be applied to all resources')
param tags object = {}

param location string = resourceGroup().location

var resourceToken = uniqueString(resourceGroup().id)

resource cosmosDb 'Microsoft.DocumentDB/databaseAccounts@2023-04-15' = {
    name: replace('${databaseAccountName}-${resourceToken}', '-', '')
    location: location
    kind: 'GlobalDocumentDB'
    tags: tags
    properties: {
        consistencyPolicy: { defaultConsistencyLevel: 'Session' }
        locations: [
            {
                locationName: location
                failoverPriority: 0
            }
        ]
        databaseAccountOfferType: 'Standard'
    }

    resource db 'sqlDatabases@2023-04-15' = [for name in databases: {
        name: '${name}'
        location: location
        tags: tags
        properties: {
            resource: {
                id: '${name}'
            }
        }
    }]
}

var primaryMasterKey = cosmosDb.listKeys(cosmosDb.apiVersion).primaryMasterKey

resource vault 'Microsoft.KeyVault/vaults@2023-07-01' existing = {
    name: keyVaultName

    resource secret 'secrets@2023-07-01' = {
        name: 'connectionString'
        properties: {
            value: 'AccountEndpoint=${cosmosDb.properties.documentEndpoint};AccountKey=${primaryMasterKey}'
        }
    }
}

Den föregående Bicep-mallen förväntar sig en parameter av typen keyVaultName, tillsammans med flera andra parametrar. Den definierar sedan en resurs av typen Azure Cosmos DB och lagrar en hemlighet i Azure Key Vaultmed namnet connectionString, vilket representerar en fullständigt kvalificerad anslutningssträng till instansen Cosmos DB. Om du vill komma åt det här värdet för den hemliga anslutningssträngen kan du använda följande kodfragment:

var cosmos = builder.AddBicepTemplate("cosmos", "../infra/cosmosdb.bicep")
    .WithParameter("databaseAccountName", "fallout-db")
    .WithParameter(AzureBicepResource.KnownParameters.KeyVaultName)
    .WithParameter("databases", ["vault-33", "vault-111"]);

var connectionString =
    cosmos.GetSecretOutput("connectionString");

builder.AddProject<Projects.WebHook_Api>("api")
    .WithEnvironment(
        "ConnectionStrings__cosmos",
        connectionString);

I föregående kodfragment läggs cosmos Bicep-mallen till som en referens till builder. Den hemliga utdata connectionString hämtas från Bicep-mallen och lagras i en variabel. De hemliga utdata skickas sedan som en miljövariabel (ConnectionStrings__cosmos) till api projektet. Den här miljövariabeln används för att ansluta till den Cosmos DB instansen.

När den här resursen distribueras kommer den underliggande distributionsmekanismen automatiskt att referera till hemligheter från Azure Key Vault. För att garantera hemlig isolering skapar .NET.NET Aspire ett Nyckelvalv per källa.

Anmärkning

I lokalt provisionsläge extraheras hemligheten från Key Vault och ställs in som en miljövariabel. Mer information finns i Lokal Azure försörjning.