👨‍💻 niltor    📆 2026-09-03 17:04

发布应用

模板项目默认使用Aspire进行本地开发和服务编排。在发布阶段,推荐根据发布目标选择不同方式:

  • 单独发布某个服务镜像:使用项目中的Dockerfile和发布脚本。
  • 编排多个服务、数据库、缓存等资源:使用AppHost,并结合 Aspire 的发布和部署能力。

Note

本文中的镜像发布脚本只适合对单个服务进行镜像打包。如果需要处理数据库、缓存、EF Core 迁移 Job、服务依赖顺序和环境变量编排,应使用AppHost作为入口。

发布前准备

发布前请确认本机已经安装:

  • .NET SDK
  • Docker 或兼容的容器运行时

在项目根目录下执行以下命令,先确认项目可以正常构建:

dotnet build -c Release

模板中的后端服务通常位于src/Services目录,例如:

  • ApiService
  • AdminService
  • AdminService-Migrations(由 AppHost 的 AddEFMigrations 创建)

对外提供接口的服务一般是ApiService和AdminService。AdminService-Migrations 是一次性迁移资源,不应作为长期运行的接口服务镜像使用。

以上 AdminService 和 AdminService-Migrations 仅适用于 ApiStandard;MiniApi 只有 ApiService,固定使用 PostgreSQL,且不提供内置 EF Core 迁移资源。

单服务镜像发布

模板提供了scripts/PublishDocker.ps1脚本,用于发布一个服务并基于对应的Dockerfile构建镜像。

脚本的基本参数如下:

参数 说明
Service 服务名称,也是程序集名称,例如ApiService或AdminService。
ImageName 生成的镜像名称,例如myprojectname-api-service。
Tag 镜像标签,可选,默认值为latest。
Configuration 发布配置,可选,默认值为Release。
InstallFonts 是否安装常用字体,默认不安装。
CjkFontPackage 中文/中日韩字体包,可选值为font-wqy-zenhei或font-noto-cjk。
NoRestore 跳过还原。只有确认已经完成目标运行时的还原时才建议使用。

发布ApiService:

.\scripts\PublishDocker.ps1 -Service ApiService -ImageName myprojectname-api-service

发布AdminService并指定标签:

.\scripts\PublishDocker.ps1 -Service AdminService -ImageName myprojectname-admin-service -Tag v1

脚本会执行以下操作:

  1. 使用dotnet publish发布指定服务。
  2. 将发布产物输出到artifacts/publish/<Service>。
  3. 使用服务目录下的Dockerfile构建镜像。
  4. 输出镜像大小。
  5. 构建完成后清理对应的发布目录。

Tip

NoRestore不是默认推荐项。如果没有提前执行过目标运行时的还原,使用NoRestore会导致发布失败。

字体和多语言

ApiStandard 服务镜像默认使用 mcr.microsoft.com/dotnet/aspnet:10.0-alpine-extra;MiniApi 的 NativeAOT 镜像使用 mcr.microsoft.com/dotnet/runtime-deps:10.0-alpine-extra。两者都保留了非 invariant globalization 所需的基础能力,适合需要中文、英文等多语言处理的 Web API 服务。

默认情况下,发布脚本不会安装字体。这可以减小镜像体积,适合纯 API 场景。

如果服务中使用了图片生成、报表导出、PDF 或其他服务端文字渲染功能,需要安装字体:

.\scripts\PublishDocker.ps1 -Service AdminService -ImageName myprojectname-admin-service -InstallFonts

默认字体包包含:

  • fontconfig
  • font-dejavu
  • font-noto-emoji
  • font-wqy-zenhei

如果需要更完整的中日韩字体覆盖,可以使用font-noto-cjk:

.\scripts\PublishDocker.ps1 -Service AdminService -ImageName myprojectname-admin-service -InstallFonts -CjkFontPackage font-noto-cjk

Note

字体会明显增加镜像体积。只有服务确实需要服务端文字渲染时才建议安装。

关于 Trim 和 AOT

两套模板的发布策略不同,不能用一条“模板默认不启用 AOT”的说明覆盖:

  • ApiStandard 面向 Controller、EF Core、认证和可选第三方能力,保持 framework-dependent 发布,不建议直接开启 Trim 或 AOT。
  • MiniApi 的 ApiService.csproj 已启用 PublishAot 和 Request Delegate Generator;其发布脚本也会显式设置 PublishTrimmed=true 与 PublishAot=true。

MiniApi 发布示例:

dotnet publish src/Services/ApiService/ApiService.csproj -c Release

如果使用 MiniApi 的 Docker 发布脚本,请确认目标运行时为 linux-musl-x64,并检查所有反射、序列化和原生依赖的 AOT 兼容性。Standard 和 MiniApi 的发布限制请分别参阅各自的快速入门。

使用 AppHost 进行编排

单服务镜像发布脚本不会处理服务之间的依赖关系。例如:

  • 数据库
  • 缓存
  • EF Core 迁移 Job
  • 服务启动顺序
  • 连接字符串
  • 开发环境参数

这些内容应由AppHost统一描述。模板中的AppHost会根据配置启动基础设施资源,并将数据库、缓存等资源引用传递给服务。

aspire start --non-interactive

使用 Aspire 生成发布产物

先查看发布步骤,再生成目标平台的产物:

aspire publish --project .\src\AppHost\AppHost.csproj --list-steps --non-interactive
aspire publish --project .\src\AppHost\AppHost.csproj --output-path .\artifacts\aspire --non-interactive

当前模板包含 Kubernetes 环境,生成结果是 Helm Chart,通常包括 Chart.yaml、values.yaml、templates/ 和迁移 bundle。迁移清单的文件名可能仍为 deployment.yaml,但应检查其内容为 apiVersion: batch/v1、kind: Job。

Kubernetes Job 使用 restartPolicy: OnFailure,迁移成功后结束。发布流程应等待 Job 成功,再向 API 和后台服务放流量;镜像需要使用集群可拉取的镜像仓库地址。发布前请检查 values.yaml 中的镜像、参数、Secret 和连接字符串映射。

将生成的 Chart 交给现有集群时,可以使用 Helm:

helm upgrade --install perigon .\artifacts\aspire --namespace perigon --create-namespace
kubectl get jobs -n perigon
kubectl logs job/<migration-job-name> -n perigon

如果使用 Aspire 直接部署,先确认当前 kubectl 上下文、镜像仓库和命名空间,再执行:

aspire deploy --project .\src\AppHost\AppHost.csproj --non-interactive

参考 Aspire 官方文档:使用 AddEFMigrations 自动执行 EF Core migrations、按环境避免迁移容器重启、Kubernetes deployment 和 Seed data。

Aspire 也支持在应用模型中描述容器镜像、Dockerfile、构建参数和发布流程。对于需要统一发布多个资源的场景,可以进一步在AppHost中配置 Dockerfile 资源或自定义发布管线。

Important

如果文档、脚本和AppHost描述不一致,应以当前项目代码实现为准。

推荐实践

  • 一个服务一个镜像,镜像名使用小写短横线命名。
  • 发布脚本只负责单服务打包,不负责服务编排。
  • 生产环境不要在镜像中保存密钥,应通过环境变量、密钥服务或部署平台注入。
  • 只有需要服务端字体渲染时才安装字体。
  • 优先使用Release发布配置。
  • 镜像构建完成后,检查镜像大小和启动日志。

查看本地镜像大小:

docker images myprojectname-api-service

运行镜像:

docker run --rm -p 8080:8080 myprojectname-api-service:latest

如果服务依赖数据库或缓存,请通过部署平台或AppHost提供对应的连接字符串和环境变量。