Microsoft 刚发布的 .NET Aspire 9.3 把开发者在本地和云端之间反复横跳的痛点狠狠戳了一轮——新增的 aspire destroy 一键拆毁所有部署资源,Kubernetes 原生部署进入预览,Next.js 和 Vite 项目拿到了一等公民的发布支持,容器隧道默认开启,浏览器日志也能直接捕获。不过伴随这些功能而来的还有几项破坏性变更,升级前需要逐条核对。
一条命令销毁所有部署资源
过去用 Aspire 部署到 Azure、Kubernetes 或 Docker Compose 后,清理资源是一件让人头疼的事——你得分别跑到 Azure Portal 删资源组、kubectl delete 一堆资源、再手动停掉 Compose 服务,遗漏一个资源就继续烧钱。9.3 新增的 aspire destroy 把这三条退路合并成一条:
# 销毁当前 Aspire 项目在所有环境中的部署资源
aspire destroy
# 只销毁 Azure 资源,保留本地 Compose 和 K8s
aspire destroy --target azure
# 销毁前跳过确认提示(CI 场景常用)
aspire destroy --force
命令会按环境逐一清理:先删除 Azure 资源组及其下所有资源,再卸载 Kubernetes 中的 Helm Release 和关联 Secret/ConfigMap,最后 docker compose down 清掉本地容器和网络。执行过程中每一步都有日志输出,失败时不会静默跳过,而是报出具体资源 ID 供你手动跟进。
实际使用时建议先跑一次 aspire destroy --target azure 确认云端资源清理干净,再处理本地环境,避免远程资源残留导致费用泄漏。
Kubernetes 原生部署进入预览阶段
Aspire 之前对 Kubernetes 的支持是间接的——先发布到 Azure Container Apps,再由 Azure 托管 K8s。9.3 引入了原生 K8s 部署预览,直接把 App Host 模型翻译成 Kubernetes 资源清单,不再依赖 Azure 中间层。
下面是一个最小化的部署流程示例:
# 1. 生成 Kubernetes 资源清单(预览功能需显式声明目标)
aspire publish --target kubernetes --output-path ./k8s-manifests
# 2. 检查生成的清单结构
ls ./k8s-manifests/
# 输出大致如下:
# deployment.yaml service.yaml configmap.yaml secret.yaml
# 3. 直接应用到现有集群
kubectl apply -f ./k8s-manifests/ --namespace my-aspire-app
# 4. 验证 Pod 状态
kubectl get pods -n my-aspire-app -w
生成的清单会为每个 Aspire 服务产出独立的 Deployment 和 Service,依赖关系通过 ConfigMap 注入环境变量表达。目前预览版有几个已知边界:不支持自动 HPA 配置、Ingress 需要手动补充、StatefulSet 场景尚未覆盖。如果你的项目已经用 Helm 或 Kustomize 管理清单,可以把 Aspire 生成的 YAML 作为子图表嵌入现有体系,而不是完全替换。
JavaScript 项目拿到一等公民发布支持
9.3 之前,Next.js 和 Vite 项目在 Aspire 中的发布路径是"先打包成静态文件,再塞进一个通用容器"——流程粗糙且缺乏框架感知。新版本为这两个框架提供了专门的发布 Profile,生成符合框架特征的容器镜像和部署配置。
以 Next.js 为例,发布后的容器镜像会自动包含 standalone 输出模式所需的全部依赖,而不是把整个 .next 目录无差别拷进去:
# Next.js 项目发布到 Azure Container Apps
aspire publish --target azure-container-apps
# Vite 项目发布到同一目标
aspire publish --target azure-container-apps
对应的 App Host 配置大致如下(关键部分):
var builder = DistributedApplication.CreateBuilder(args);
// Next.js 项目作为一等公民添加
var nextApp = builder.AddNpmApp("frontend", "../frontend", "dev")
.WithReference(apiService) // 自动注入后端服务 URL
.PublishAsDockerContainer(); // 发布时生成框架感知的镜像
var apiService = builder.AddProject<Projects.ApiService>("api");
builder.Build().Run();
AddNpmApp 会识别 package.json 中的启动脚本,PublishAsDockerContainer 在发布阶段调用框架专属的构建逻辑。Vite 项目同理,产出的是多阶段构建的 Nginx 静态托管镜像,而非通用 Node.js 运行时。
容器隧道默认开启与浏览器日志捕获
调试微服务时最烦的一件事是:服务跑在容器里,端口没暴露到宿主机,你想访问内部接口只能手动加 WithHttpEndpoint。9.3 把容器隧道(Container Tunnel)改为默认开启——所有容器服务的 HTTP 端点自动映射到 localhost,开发阶段不再需要逐个声明外部端口。
# 启动 App Host 后,控制台输出类似:
# frontend: http://localhost:7134 (tunneled)
# api: http://localhost:7135 (tunneled)
# redis: tcp://localhost:7136 (tunneled)
浏览器日志捕获是另一个实用改进。Aspire Dashboard 现在能接收前端应用在浏览器中输出的 console.log/console.error,通过 WebSocket 回传到 Dashboard 的日志面板。这意味着你在 Next.js 页面里打的调试日志,和后端 API 的结构化日志出现在同一个视图里,排查前后端联调问题时不用再开两个终端窗口。
破坏性变更与升级检查清单
9.3 带来的破坏性变更主要集中在命名规范和默认行为调整上,升级前务必逐条确认:
| 变更项 | 旧行为 | 新行为 | 影响范围 |
|---|---|---|---|
| 容器隧道 | 需显式 WithContainerTunnel |
默认开启 | 依赖手动端口映射的脚本会冲突 |
| 发布输出目录结构 | 单层扁平 YAML | 按环境分目录 | CI 中引用输出路径的步骤需更新 |
AddNpmApp 启动脚本参数 |
--script 位置不固定 |
严格按 name、path、script 顺序 |
旧参数顺序会报编译错误 |
| Azure 资源命名前缀 | 无前缀 | 默认加 aspire- 前缀 |
已有 ARM 模板中硬编码资源名的需调整 |
升级建议:
- 先在隔离环境跑
aspire destroy——确认旧版部署资源全部清掉,避免新旧资源命名冲突。 - 检查 CI/CD 中引用发布输出路径的步骤——目录结构变了,路径硬编码的地方会断。
- 容器隧道默认开启后,如果你的测试脚本依赖特定端口分配逻辑,用
WithContainerTunnel(false)显式关闭。 - JavaScript 项目重新跑一次
aspire publish,对比新旧镜像大小和启动时间——框架感知构建通常能缩减 30-50% 的镜像体积。
9.3 的核心思路是把"从本地开发到云端部署再到资源清理"这条链路上的手动环节逐一消灭。aspire destroy 解决了最容易被忽视的清理问题,K8s 原生部署预览让非 Azure 用户有了直通路径,JavaScript 一等公民支持补上了前端项目的短板。如果你已经在用 Aspire 管理微服务开发环境,这版值得尽快升级——但务必先对照破坏性变更清单逐条排查。