Chapter 10

部署与现代架构

Docker 容器化、Native AOT 超低延迟、.NET Aspire 分布式编排、OpenTelemetry 可观测性与 Semantic Kernel AI 集成。

Docker 容器化

.NET 9 支持直接通过 MSBuild 发布为 Docker 镜像,无需手写 Dockerfile(当然也可以手写以获得更多控制)。

多阶段 Dockerfile(推荐)

# 阶段一:构建
FROM mcr.microsoft.com/dotnet/sdk:9.0 AS build
WORKDIR /src

# 先复制项目文件(利用 Docker 层缓存)
COPY ["src/Api/Api.csproj", "src/Api/"]
COPY ["src/Core/Core.csproj", "src/Core/"]
RUN dotnet restore "src/Api/Api.csproj"

# 复制源码并发布
COPY . .
RUN dotnet publish "src/Api/Api.csproj" \
    -c Release \
    -o /app/publish \
    --no-restore

# 阶段二:运行时(更小的镜像)
FROM mcr.microsoft.com/dotnet/aspnet:9.0 AS final
WORKDIR /app

# 非 root 用户运行(安全最佳实践)
USER app

COPY --from=build /app/publish .
EXPOSE 8080
ENTRYPOINT ["dotnet", "Api.dll"]

MSBuild 直接发布为容器镜像

# 发布为本地 Docker 镜像(无需 Dockerfile)
dotnet publish /t:PublishContainer \
  -p ContainerImageName=myapp \
  -p ContainerImageTag=1.0.0

# 推送到 Docker Hub
dotnet publish /t:PublishContainer \
  -p ContainerRegistry=docker.io \
  -p ContainerImageName=username/myapp \
  -p ContainerImageTag=latest
<!-- .csproj 中配置容器属性 -->
<PropertyGroup>
  <ContainerBaseImage>mcr.microsoft.com/dotnet/aspnet:9.0-alpine</ContainerBaseImage>
  <ContainerImageName>my-api</ContainerImageName>
  <ContainerPort>8080</ContainerPort>
</PropertyGroup>

Native AOT:启动时间 <5ms

Native AOT(Ahead-of-Time)将整个应用编译为平台原生可执行文件,无需 .NET 运行时。适合 CLI 工具、云函数(冷启动要求严苛)、边缘计算等场景。

Native AOT 优势

  • 启动时间:<5ms(vs JIT 的 100-500ms)
  • 内存占用:减少 50-70%
  • 无需安装 .NET 运行时
  • 更小的攻击面
  • 适合容器/云函数

Native AOT 限制

  • 不支持运行时反射(需用 Source Generator)
  • 不支持动态代码加载
  • 编译时间较长
  • 部分 NuGet 包不兼容
  • EF Core 需额外配置
<!-- 启用 Native AOT 发布 -->
<PropertyGroup>
  <PublishAot>true</PublishAot>
  <InvariantGlobalization>true</InvariantGlobalization>  <!-- 减小体积 -->
</PropertyGroup>
# AOT 发布(需要相同 OS 的构建环境)
dotnet publish -r linux-x64 -c Release

# 结果:单个自包含可执行文件
ls -lh ./bin/Release/net9.0/linux-x64/publish/
# -rwxr-xr-x  1 user  group  12M Apr 9 10:00 myapp
// Minimal API + Native AOT 完整示例
using System.Text.Json.Serialization;

var builder = WebApplication.CreateSlimBuilder(args);  // Slim = AOT 优化版

// AOT 下 JSON 序列化需要 Source Generator
builder.Services.ConfigureHttpJsonOptions(options =>
    options.SerializerOptions.TypeInfoResolverChain.Insert(0, AppJsonSerializerContext.Default));

var app = builder.Build();
app.MapGet("/users", () => new[] { new User(1, "Alice") });
app.Run();

record User(int Id, string Name);

[JsonSerializable(typeof(User[]))]
partial class AppJsonSerializerContext : JsonSerializerContext { }

.NET Aspire:分布式应用框架

.NET Aspire 是 .NET 8 引入(1.0 于 2024 年 5 月正式发布)的分布式应用开发框架,解决了微服务开发中最痛苦的问题:服务编排、服务发现、配置注入、可观测性。

AppHost 项目
定义分布式应用的组合方式——哪些服务、哪些基础设施(Redis、PostgreSQL、RabbitMQ 等)、它们之间的依赖关系。开发时 Aspire 自动用 Docker 启动基础设施,服务发现和连接字符串自动注入,无需手写。
Dashboard
Aspire 内置的可观测性仪表盘,集成 OpenTelemetry,实时展示所有服务的日志、追踪、指标,以及服务间调用关系图。开发阶段无需配置 Jaeger/Grafana 等额外工具。
// AppHost/Program.cs(Aspire 编排)
var builder = DistributedApplication.CreateBuilder(args);

// 声明基础设施
var postgres = builder.AddPostgres("postgres")
    .WithDataVolume()               // 数据持久化
    .AddDatabase("appdb");

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

// 声明服务,注入依赖
var api = builder.AddProject<Projects.Api>("api")
    .WithReference(postgres)        // 自动注入连接字符串
    .WithReference(redis)
    .WaitFor(postgres);             // 等待 postgres 就绪再启动

builder.AddProject<Projects.Worker>("worker")
    .WithReference(api)
    .WithReference(postgres);

await builder.Build().RunAsync();

健康检查

builder.Services.AddHealthChecks()
    .AddNpgSql(connStr, name: "postgres")
    .AddRedis(redisConn, name: "redis")
    .AddUrlGroup(new Uri("https://api.payments.com/health"), name: "payment-api")
    .AddCheck<CustomHealthCheck>("custom");

// 端点映射
app.MapHealthChecks("/health/live",  new HealthCheckOptions { Predicate = _ => false });
app.MapHealthChecks("/health/ready", new HealthCheckOptions
{
    ResponseWriter = UIResponseWriter.WriteHealthCheckUIResponse
});

OpenTelemetry:可观测性三支柱

// 安装: dotnet add package OpenTelemetry.Extensions.Hosting
//       dotnet add package OpenTelemetry.Instrumentation.AspNetCore

builder.Services.AddOpenTelemetry()
    .WithTracing(tracing =>
    {
        tracing
            .AddAspNetCoreInstrumentation()
            .AddHttpClientInstrumentation()
            .AddEntityFrameworkCoreInstrumentation()
            .AddOtlpExporter();   // 导出到 Jaeger/Grafana Tempo
    })
    .WithMetrics(metrics =>
    {
        metrics
            .AddAspNetCoreInstrumentation()
            .AddRuntimeInstrumentation()
            .AddPrometheusExporter();  // /metrics 端点
    })
    .WithLogging(logging =>
    {
        logging.AddOtlpExporter();
    });

// 自定义 Activity(手动追踪)
private static readonly ActivitySource _activitySource =
    new("MyApp.OrderService");

public async Task<Order> ProcessOrderAsync(Order order)
{
    using var activity = _activitySource.StartActivity("ProcessOrder");
    activity?.SetTag("order.id",    order.Id);
    activity?.SetTag("order.total", order.Total);

    try
    {
        var result = await DoProcessAsync(order);
        activity?.SetStatus(ActivityStatusCode.Ok);
        return result;
    }
    catch (Exception ex)
    {
        activity?.SetStatus(ActivityStatusCode.Error, ex.Message);
        activity?.RecordException(ex);
        throw;
    }
}

Microsoft Semantic Kernel:构建 .NET AI Agent

Semantic Kernel 是微软开源的 AI 编排框架,让 .NET 开发者能方便地将 AI 能力(OpenAI、Azure OpenAI、本地 LLM)集成到应用中,并构建 AI Agent。

// 安装: dotnet add package Microsoft.SemanticKernel

var kernel = Kernel.CreateBuilder()
    .AddAzureOpenAIChatCompletion(
        deploymentName: "gpt-4o",
        endpoint:       builder.Configuration["AzureOpenAI:Endpoint"]!,
        apiKey:         builder.Configuration["AzureOpenAI:ApiKey"]!)
    .Build();

// 定义 Plugin(工具函数)
public class OrderPlugin(IOrderService orderService)
{
    [KernelFunction, Description("查询用户的订单列表")]
    public async Task<string> GetOrders(
        [Description("用户ID")] string userId)
    {
        var orders = await orderService.GetByUserIdAsync(userId);
        return JsonSerializer.Serialize(orders);
    }

    [KernelFunction, Description("取消指定订单")]
    public async Task<string> CancelOrder(
        [Description("订单ID")] string orderId)
    {
        await orderService.CancelAsync(Guid.Parse(orderId));
        return $"订单 {orderId} 已取消";
    }
}

// 注册 Plugin 并启用自动函数调用(Function Calling)
kernel.Plugins.AddFromObject(new OrderPlugin(orderService));

var settings = new OpenAIPromptExecutionSettings
{
    FunctionChoiceBehavior = FunctionChoiceBehavior.Auto()  // 自动选择工具
};

var history = new ChatHistory();
history.AddSystemMessage("你是一个客服助手,可以帮用户查询和管理订单。");
history.AddUserMessage("帮我查一下 user123 的所有订单");

var chatService = kernel.GetRequiredService<IChatCompletionService>();
var response = await chatService.GetChatMessageContentAsync(
    history, settings, kernel);

Console.WriteLine(response.Content);

云部署选项

平台特点适用场景
Azure Container Apps微软原生,Aspire 深度集成,自动缩放.NET 应用首选云平台
Azure App ServicePaaS,部署最简单,支持部署槽中小型 Web 应用
AWS App Runner全托管容器运行,自动缩放已在 AWS 生态的团队
Fly.io全球边缘节点,CLI 部署简单,费用低个人项目/初创公司
Kubernetes (AKS/EKS)最大控制权,适合复杂微服务大型企业级应用
本章小结 · 课程总结 Docker 多阶段构建让 .NET 镜像小巧安全,MSBuild 直接发布镜像更便捷。Native AOT 是 Serverless/Edge 场景的杀手锏——5ms 冷启动、无运行时依赖。.NET Aspire 彻底改变了微服务本地开发体验,服务发现、配置、可观测性全部自动化。OpenTelemetry 标准让追踪/指标/日志一体化。Semantic Kernel 让 .NET 开发者轻松站上 AI 浪潮。至此,你已掌握从 C# 13 语法到企业级云原生 .NET 9 开发的完整技能树。