Aspire 编排概述

Aspire 提供用于在分布式应用程序中表达资源和依赖项的 API。 除了这些 API,还有一些工具和框架 可实现多种引人注目的场景。 编排器旨在用于本地开发目的,不支持在生产环境中使用。

在继续之前,请考虑Aspire中使用的一些常见术语:

  • 应用模型:构成分布式应用程序(DistributedApplication)的资源集合,这些资源在 Aspire.Hosting.ApplicationModel 命名空间中定义。 有关更正式的定义,请参阅 定义应用模型
  • AppHost/Orchestrator 项目:协调 .NET的 项目,按约定以 .AppHost 后缀命名。
  • 资源资源 是应用程序的依赖部分,例如 .NET 项目、容器、可执行、数据库、缓存或云服务。 它表示应用程序中可以管理或引用的任何一个部分。
  • 集成:集成是一个 NuGet 包,用于为AppHost建模资源,或配置客户端以便在消费应用中使用的包。 有关详细信息,请参阅 Aspire 集成概述
  • 引用:引用定义资源之间的连接,用 WithReference API 表示为依赖项。 有关详细信息,请参阅 参考资源参考现有资源

注意

Aspire业务流程旨在通过简化云原生应用的配置和互连的管理来增强 本地开发 体验。 虽然它是一个宝贵的开发工具,但它并不旨在取代生产环境系统,如 Kubernetes,这些系统专门设计为在该上下文中脱颖而出。

定义应用模型

Aspire 使你能够有效地生成、预配、部署、配置、测试、运行和监视分布式应用程序。 这些功能由 应用模型提供支持,该模型定义解决方案中的 Aspire 资源及其互连。

应用模型不仅仅是资源列表,它表示应用程序的完整拓扑。 这包括资源、其依赖项及其配置之间的关系。 资源可以包括应用程序依赖的项目、可执行文件、容器、外部服务和云资源。

Aspire在 AppHost 项目中Program文件定义应用模型:

var builder = DistributedApplication.CreateBuilder(args);

// Add resources to the app model

builder.Build().Run();

调用 DistributedApplication.CreateBuilder时,你将获得用于配置应用模型的实例 IDistributedApplicationBuilder。 此生成器提供添加资源、定义依赖项和设置应用程序的整体结构的方法。 添加资源后,调用 Build 以创建应用模型。 这些模板包括链接调用Build()的代码,该调用返回实例DistributedApplication,然后调用Run()

AppHost 项目

AppHost 项目处理运行属于 Aspire 项目的所有项目。 换句话说,它负责协调应用模型中的所有应用。 项目本身是一个 .NET 可执行项目,它引用 📦Aspire.Hosting.AppHost NuGet 程序包,并且使用 Aspire SDK

<Project Sdk="Microsoft.NET.Sdk">

    <Sdk Name="Aspire.AppHost.Sdk" Version="9.5.1" />
    
    <PropertyGroup>
        <OutputType>Exe</OutputType>
        <TargetFramework>net9.0</TargetFramework>
        <!-- Omitted for brevity -->
    </PropertyGroup>

    <ItemGroup>
        <PackageReference Include="Aspire.Hosting.AppHost" Version="9.5.1" />
    </ItemGroup>

    <!-- Omitted for brevity -->

</Project>

以下代码描述了一个 Program AppHost,具有两个项目引用和一个 Redis 缓存:

var builder = DistributedApplication.CreateBuilder(args);

var cache = builder.AddRedis("cache");

var apiservice = builder.AddProject<Projects.AspireApp_ApiService>("apiservice");

builder.AddProject<Projects.AspireApp_Web>("webfrontend")
       .WithExternalHttpEndpoints()
       .WithReference(cache)
       .WaitFor(cache)
       .WithReference(apiService)
       .WaitFor(apiService);

builder.Build().Run();

前面的代码:

  • 使用 CreateBuilder 方法创建新的应用模型生成器。
  • 使用 Redis 方法添加名为“cache”的 cacheAddRedis 资源。
  • 使用 AddProject 方法添加名为“apiservice”的项目资源。
  • 使用 AddProject 方法添加名为“webfrontend”的项目资源。
  • 使用 BuildRun 方法生成和运行应用模型。

示例代码使用 AspireRedis 托管集成

若要帮助可视化 AppHost 项目与描述的资源之间的关系,请考虑下图:

初学者应用程序模板中的 Aspire 项目之间的关系。

每个资源必须唯一命名。 此图显示了每个资源及其之间的关系。 容器资源名为“cache”,项目资源名为“apiservice”和“webfrontend”。 Web 前端项目引用缓存和 API 服务项目。 以这种方式表达引用时,Web 前端项目表示它依赖于这两个资源,即“cache”和“apiservice”。

内置资源类型

Aspire 项目由一组资源组成。 📦 Aspire.Hosting.AppHost NuGet 包中的主要基资源类型在下表中有所描述:

方法 资源类型 描述
AddProject ProjectResource 例如,.NET 项目,比如一个 ASP.NET Core 网页应用。
AddContainer ContainerResource 容器映像,例如 Docker 映像。
AddExecutable ExecutableResource 可执行文件,例如 Node.js 应用程序
AddParameter ParameterResource 可用于 表示外部参数的参数资源。

项目资源表示属于应用模型的 .NET 项目。 向 AppHost 项目添加项目引用时, Aspire SDK 会在命名空间中 Projects 为每个引用的项目生成一个类型。 有关详细信息,请参阅 Aspire SDK:项目引用

若要将项目添加到应用模型,请使用 AddProject 方法:

var builder = DistributedApplication.CreateBuilder(args);

// Adds the project "apiservice" of type "Projects.AspireApp_ApiService".
var apiservice = builder.AddProject<Projects.AspireApp_ApiService>("apiservice");

通过将同一项目的多个实例添加到应用模型,可以复制和横向扩展项目。 若要配置副本,请使用 WithReplicas 方法:

var builder = DistributedApplication.CreateBuilder(args);

// Adds the project "apiservice" of type "Projects.AspireApp_ApiService".
var apiservice = builder.AddProject<Projects.AspireApp_ApiService>("apiservice")
                        .WithReplicas(3);

前面的代码将“apiservice”项目资源的三个副本添加到应用模型。 有关详细信息,请参阅 Aspire 仪表板:资源副本

参考资源

引用表示资源之间的依赖关系。 例如,你可以想象一种 Web 前端依赖于 Redis 缓存的场景。 请考虑以下示例 AppHost Program C# 代码:

var builder = DistributedApplication.CreateBuilder(args);

var cache = builder.AddRedis("cache");

builder.AddProject<Projects.AspireApp_Web>("webfrontend")
       .WithReference(cache);

“webfrontend” 项目资源使用 WithReference 为“缓存”容器资源添加依赖项。 这些依赖项可以表示连接字符串或 服务发现 信息。 在前面的示例中,环境变量 注入到名为 ConnectionStrings__cache的“webfrontend”资源中。 此环境变量包含一个连接字符串,webfrontend 使用该字符串通过 Redis连接到 Aspire,例如 Redis。

连接字符串和终结点引用

通常表示项目资源之间的依赖关系。 请考虑以下示例代码:

var builder = DistributedApplication.CreateBuilder(args);

var cache = builder.AddRedis("cache");

var apiservice = builder.AddProject<Projects.AspireApp_ApiService>("apiservice");

builder.AddProject<Projects.AspireApp_Web>("webfrontend")
       .WithReference(cache)
       .WithReference(apiservice);

项目与项目之间的引用的处理方式不同于具有明确定义的连接字符串的资源。 不再将连接字符串注入到“webfrontend”资源中,而是注入支持服务发现的环境变量。

方法 环境变量
WithReference(cache) ConnectionStrings__cache="localhost:62354"
WithReference(apiservice) services__apiservice__http__0="http://localhost:5455"
services__apiservice__https__0="https://localhost:7356"

添加对“apiservice”项目的引用会导致将服务发现环境变量添加到前端。 这是因为通常通过 HTTP/gRPC 进行项目到项目通信。 有关详细信息,请参阅 Aspire 服务发现

若要从 ContainerResourceExecutableResource获取特定终结点,请使用以下终结点 API 之一:

然后调用 GetEndpoint API 获取用于在 WithReference 方法中引用的端点:

var builder = DistributedApplication.CreateBuilder(args);

var customContainer = builder.AddContainer("myapp", "mycustomcontainer")
                             .WithHttpEndpoint(port: 9043, name: "endpoint");

var endpoint = customContainer.GetEndpoint("endpoint");

var apiservice = builder.AddProject<Projects.AspireApp_ApiService>("apiservice")
                        .WithReference(endpoint);
方法 环境变量
WithReference(endpoint) services__myapp__endpoint__0=https://localhost:9043

port 参数是容器正在侦听的端口。 有关容器端口的详细信息,请参阅 容器端口。 有关服务发现的详细信息,请参阅 Aspire 服务发现

服务终结点环境变量格式

在上一部分中,WithReference 方法用于表达资源之间的依赖关系。 当服务终结点导致环境变量注入依赖资源时,格式可能并不明显。 本部分提供有关此格式的详细信息。

当一个资源依赖于另一个资源时,AppHost 会将环境变量注入依赖资源。 这些环境变量用于配置依赖的资源以连接到它所依赖的资源。 环境变量的格式特定于 Aspire 服务终结点,并且以与 服务发现兼容的方式表示服务终结点。

服务终结点环境变量名称的前缀为 services__(双下划线),然后是服务名称、终结点名称,最后是索引。 索引允许为单个服务的多个终结点分配多个标识符,从第一个终结点的 0 开始,每个终结点的标识符递增。

请考虑以下环境变量示例:

services__apiservice__http__0

前面的环境变量表示 apiservice 服务的第一个 HTTP 终结点。 环境变量的值是服务终结点的 URL。 命名端点可以表示如下:

services__apiservice__myendpoint__0

在前面的示例中,apiservice 服务具有名为 myendpoint的命名终结点。 环境变量的值是服务终结点的 URL。

引用现有资源

在某些情况下,可能需要引用现有资源,这可能是一种部署到云提供商的资源。 例如,你可能想要引用 Azure 数据库。 在这种情况下,你将依赖 执行上下文 动态确定 AppHost 是在“运行”模式还是“发布”模式下运行。 如果在本地运行并想要依赖云资源,则可以使用 IsRunMode 属性有条件地添加引用。 可以选择改为在发布模式下创建资源。 某些 托管集成 支持直接提供连接字符串,可用于引用现有资源。

同样,在某些使用场景中,您可能希望将 Aspire 集成到现有解决方案中。 一种常见方法是将 Aspire AppHost 项目添加到现有解决方案。 在 AppHost 中,通过添加对 AppHost 的项目引用并 构建应用模型来表达依赖项。 例如,一个项目可能依赖于另一个项目。 这些依赖项使用 WithReference 方法表示。 有关详细信息,请参阅 将 Aspire 添加到现有 .NET 应用中

执行上下文

公开 IDistributedApplicationBuilder 执行上下文(DistributedApplicationExecutionContext),该上下文提供有关 AppHost 的当前执行的信息。 此上下文可用于评估 AppHost 是作为“运行”模式执行还是作为发布操作的一部分。 请考虑以下属性:

  • IsRunMode:如果当前操作正在运行,则返回 true
  • IsPublishMode:如果当前操作正在发布,则返回 true

如果要根据当前操作有条件地执行代码,此信息非常有用。 请考虑以下示例,该示例演示如何使用 IsRunMode 属性。 在这种情况下,扩展方法用于在本地开发运行中为 RabbitMQ 生成稳定的节点名称。

private static IResourceBuilder<RabbitMQServerResource> RunWithStableNodeName(
    this IResourceBuilder<RabbitMQServerResource> builder)
{
    if (builder.ApplicationBuilder.ExecutionContext.IsRunMode)
    {
        builder.WithEnvironment(context =>
        {
            // Set a stable node name so queue storage is consistent between sessions
            var nodeName = $"{builder.Resource.Name}@localhost";
            context.EnvironmentVariables["RABBITMQ_NODENAME"] = nodeName;
        });
    }

    return builder;
}

执行上下文通常用于有条件地添加指向现有资源的资源或连接字符串。 请考虑以下示例,该示例演示如何根据执行上下文有条件地添加 Redis 或连接字符串:

var builder = DistributedApplication.CreateBuilder(args);

var redis = builder.ExecutionContext.IsRunMode
    ? builder.AddRedis("redis")
    : builder.AddConnectionString("redis");

builder.AddProject<Projects.WebApplication>("api")
       .WithReference(redis);

builder.Build().Run();

在前面的代码中:

  • 如果 AppHost 处于“运行”模式,则会添加一个Redis 容器资源。
  • 如果 AppHost 处于“发布”模式,则会添加连接字符串。

在本地运行时,可以轻松反转此逻辑以连接到现有 Redis 资源,并在发布时创建新的 Redis 资源。

重要

Aspire 提供用于控制资源生成器形式的常见 API,使资源能够根据执行模式以不同的方式行为。 fluent API 的前缀为 RunAs*PublishAs*RunAs* API 会影响本地开发(或运行模式)行为,而 PublishAs* API 会影响资源的发布。 若要详细了解 Azure 资源如何使用这些 API,请参阅 使用现有 Azure 资源

另请参阅