发布应用
模板项目默认使用Aspire进行本地开发和服务编排。在发布阶段,推荐根据发布目标选择不同方式:
- 单独发布某个服务镜像:使用项目中的
Dockerfile和发布脚本。 - 编排多个服务、数据库、缓存等资源:使用
AppHost,并结合 Aspire 的发布和部署能力。
Note
本文中的镜像发布脚本只适合对单个服务进行镜像打包。如果需要处理数据库、缓存、EF Core 迁移 Job、服务依赖顺序和环境变量编排,应使用AppHost作为入口。
发布前准备
发布前请确认本机已经安装:
- .NET SDK
- Docker 或兼容的容器运行时
在项目根目录下执行以下命令,先确认项目可以正常构建:
dotnet build -c Release
模板中的后端服务通常位于src/Services目录,例如:
ApiServiceAdminServiceAdminService-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
脚本会执行以下操作:
- 使用
dotnet publish发布指定服务。 - 将发布产物输出到
artifacts/publish/<Service>。 - 使用服务目录下的
Dockerfile构建镜像。 - 输出镜像大小。
- 构建完成后清理对应的发布目录。
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
默认字体包包含:
fontconfigfont-dejavufont-noto-emojifont-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提供对应的连接字符串和环境变量。
In this article