作者:Radu Matei & Michelle Dhanani
Spin社区很高兴地推出Spin 3.0,这是Spin的最新主要版本,一个用于构建、分发和运行无服务器WebAssembly (Wasm) 应用程序的开源开发工具。
自从Spin在2022年首次发布以来,我们看到越来越多充满热情的开发者们因使用Wasm而感到兴奋不已:Wasm提供了小巧且便携的二进制文件,并具有启动延迟非常低和巨大的吞吐能力;我们还看到开发者们使用Spin在各种环境中构建和运行应用:从Kubernetes和传统云端平台,从汽车到工厂车间,甚至尝试将Spin应用程序运行在太空。
Spin 3.0 的亮点我们在 Spin 团队的成员喜欢 Wasm 因为它的轻量级、快速的冷启动和出色的安全保障。这些特性使得 Wasm 对服务器端用例非常有吸引力,适用于容器运行缓慢或占用空间过大的情况,对于需要隔离环境的关键场合以及无服务器用例,只需要使用实际需要的计算资源而且可移植性至关重要。但 Wasm 真正的美妙之处在于我们才刚刚开始探索 Wasm 能为开发者提供的潜力。
如果你还不太了解,WebAssembly 提供了一种跨不同编程语言的通用字节码格式和编译目标。WebAssembly 组件模型更进一步,它通过 WebAssembly 接口类型(WIT)来标准化组件接口。WIT 允许组件在任何原始编写语言间进行互操作,这使得情况变得更加有趣。当你将某个程序编译成 WebAssembly 组件时,你就可以在另一个用 完全不同的语言 编写的程序中使用它作为库或依赖项。不过,这背后涉及很多技术细节,实现起来并不简单。
Spin 3.0 引入了一种工作流程,以期使这种开发变得无缝,例如,编写一个针对计算密集型任务的库,使用 Rust 语言,并将其作为依赖项用于 JavaScript 应用程序中。或者你不是 Rust 开发者,也不想快速学会 Rust?没关系。你可以从 OCI 注册表中获取其他人已经构建的组件。组件依赖项可以存储、发现并从 OCI 注册表中获取,这为你提供了类似于 npm、NuGet 或 crates.io 的体验,但面向的是 Wasm。我觉得这个功能非常酷,甚至可以用它写一篇论文,但还有更多 Spin 3.0 的功能要讨论,所以你可以深入研究一下组件依赖项的文档 这里,并在后面的演示中进一步了解。
你可以在本地使用 Spin CLI 或者通过 SpinKube 来运行 Spin 应用程序中的部分组件。Spin 3.0 新增了一个实验性标志:spin up --component-id
,你可以通过它来指定要运行的 Spin 应用程序中的哪些组件。在 SpinKube 中,containerd-shim-spin 和 spin-operator 项目都支持选择性部署组件,并且在 SpinApp 自定义资源定义(CRD)规范中新增了 components
部分,这可以启用从 Spin 应用程序中选择性部署组件。这为平台工程师解锁了新的场景,让他们可以在满足特定要求的节点上选择性运行组件,同时也为选择开发包含多个组件的单个 Spin 应用程序的开发者提供了一种更顺畅的工作流程,并且在部署时,平台工程师依然可以灵活地拆分和运行组件。
我们非常支持 Spin 项目中的标准。在了解社区需求的过程中,我们积极贡献于 WASI API 的开发,并且努力将这些 API 整合到 Spin 项目中,以便大家能够从上游 WebAssembly 社区的合作和知识中受益。在此基础上,我们很高兴地告诉大家,WASI Key-Value 和 WASI Config API 现在已正式支持在 Spin 中使用。这标志着 WASI 云核心引入 Spin 的一个重要进展。WASI 云核心是一项旨在为应用提供标准 API 来与通用云服务交互的 WASI 建议。这标志着将 WASI 云核心引入 Spin 的旅程中的一个重要下一步。
可观测性对于当今的应用开发和运行时环境至关重要,从 Spin 2.4 开始,我们一直在试验如何确保 Spin 应用能够无缝集成到现有的可观测性堆栈中。Spin 3.0 现在正式支持在 Spin 应用中使用 OpenTelemetry (OTel) 可观测性。这使得将 Spin 应用的可观测性与您当前使用的工具(如 Grafana、Jaeger、Prometheus 等)进行集成变得容易。Spin 应用自带指标导出和分布式追踪功能,更不用说使用spin otel
插件设置可观测性堆栈也更简单。我们正在将学到的经验贡献给 WASI observe 规范,并与社区合作不断改进这一领域。
最后但同样重要的是,我们对Spin内部进行了大规模的重构,引入了一个名为Spin Factors的功能,其中“因素”封装了主机功能特性。在“因素”出现之前,主机功能特性被封装在我们称之为“主机组件”中,但随着Spin功能的不断增加,情况变得越来越混乱。另一个促使创建Spin Factors的因素是嵌入Spin的项目数量增加。这些嵌入具有不同的环境和需求,因此我们已经超越了“主机组件”的概念,基于这些经验构建了一个全新的抽象层,即Spin Factors。这样一来,Spin运行时变得更模块化了。每个项目都有自己的特点,我们对此表示支持。现在根据您的需求扩展Spin运行时也更简单了,虽然这需要对项目进行分叉,但这是朝着正确方向迈出的一大步。
动态展示 - Spin 3.0, 实际操作这里有个用 Spin 3.0 新特性做的例子。这一切都是基于整个生态系统中的标准工作建立的,我们正在将这种更流畅的开发体验融入 Spin。
工作场景很简单。我们正在构建一个图像变换应用程序,它有3个主要部分。
今天的常见做法是使用相同的编程语言来构建你的HTTP API组件和图像处理组件。如果这样做不可行或者性能不够,你可能需要将图像处理组件独立出来作为一个单独的微服务。
利用 Spin 3.0 的功能,我们将利用新的组件依赖特性来构建一个基于 Rust 的图像处理组件,并将其作为依赖项从一个 JavaScript 或 TypeScript 组件中使用,该组件将作为我们 HTTP API 的一部分。这展示了组件依赖特性的好处,因为它允许我们根据任务选择合适的工具。
我们先从编写“我们的图像处理组件的接口”开始。我们将定义这个接口(使用WIT格式),该接口包含一个具有两个图像转换(灰度和棕褐色)的包:
(注:此处“包”可考虑在更口语化的语境中使用“模块”或“组件”,以保持一致性。)
package component: 图像处理库; ... /// 图像处理接口。 interface 图像处理 { /// 图像处理组件返回的错误。 variant 图像处理错误 { 图像处理错误(string), IO错误(string), 未知错误(string), } /// 表示图像的类型。 type image = list<u8>; /// 对输入图像应用灰度变换。 灰度变换: func(img: image, quality: u8) -> result<image, 图像处理错误>; /// 对输入图像应用 sepia 变换。 sepia: func(img: image, quality: u8) -> result<image, 图像处理错误>; }
切换到全屏模式,切换回退出全屏
为了用 Rust 实现这个组件,我们将使用 Cargo 和一个流行的图像处理库(photon-rs)。这里提供了一个简单的组件实现框架:
fn example_function() { // 示例代码 }
impl Guest for Component { fn grayscale(img: Image, quality: u8) -> Result<Image, ImageError> { // 用高效Rust库转灰度 } fn sepia(img: Image, quality: u8) -> Result<Image, ImageError> { // 用高效Rust库转棕褐色调 } }
进入全屏 退出全屏
我们可以使用cargo component将这构建为一个Wasm组件。我们现在可以利用最新的生态系统工具,例如wkg,或将此组件发布到符合OCI规范的注册表中,使用我们正在为Spin开发的新实验插件spin deps
,例如使用spin deps
命令。
$ cargo component build --release 生成用于 image-manipulation-lib 的 src/bindings.rs 绑定代码 正在编译 image-manipulation-lib v0.1.0 在 5.20 秒内完成 `release` 配置下的优化目标构建 创建 target/wasm32-wasip1/release/image_manipulation_lib.wasm 组件 $ spin deps publish target/wasm32-wasip1/release/image_manipulation_lib.wasm \ --registry fermyon.com \ --package fermyon-experimental:image-manipulation-lib@6.0.0 已发布版本 fermyon-experimental:image-manipulation-lib@6.0.0
点击全屏 点击退出
我们现在可以使用一个发布在注册表中的Wasm组件「https://github.com/orgs/fermyon/packages/container/wasm-pkg%2Ffermyon-experimental%2Fimage-manipulation-lib/302562897?tag=6.0.0」,可以从用完全不同的语言编写的Wasm组件中调用它。
我们可以继续完善我们的图像编辑服务,通过用 TypeScript 创建 HTTP API 组件如下,该组件将依赖于我们刚才完成的 Rust 组件如下:
# 基于 TypeScript 模板新建一个 Spin 应用 $ spin new -t http-ts image-manipulation-http-api # 将我们推送到了注册表的图像处理库版本号添加为依赖项 $ spin deps add --registry fermyon.com \ fermyon-experimental:image-manipulation-lib@6.0.0
全屏模式/退出全屏
spin deps
插件帮助我们选择从发布的包中选择合适的接口,并将其作为依赖项添加到应用清单文件(spin.toml)中的 TypeScript 组件。
[图像处理HTTP API组件的依赖] "image-manipulation-lib/image-manipulation" = { version = "^6.0.0", registry = "fermyon.com", package = "fermyon-experimental:image-manipulation-lib" }
全屏 退出
注意:spin deps 插件仍处于实验性阶段,未来可能发生变化。如果您对依赖管理和使用注册表分发 Wasm 组件感兴趣,请加入我们的 Discord 服务器 一起交流吧!
现在我们就可以使用依赖项了:
import { grayscale, sepia } from "component:image-manipulation-lib/image-manipulation" // ... // 根据变换类型进行图像处理 switch (transform) { case "grayscale": transformed = grayscale(new Uint8Array(body), quality); break; case "sepia": transformed = sepia(new Uint8Array(body), quality); break; default: throw new Error("未知的图像转换"); }
切换到全屏, 切换回正常模式
查看 演示仓库 以查看完整的应用程序和构建设置。它还包含一个示例代码,说明如何从 Rust HTTP API 使用该图像处理组件。
你可以利用所有内置的 Spin 功能,包括键值数据、配置或关系数据库中的功能。如果你需要灵感的话,比如这个例子中的 HTTP API 组件使用键值存储来缓存经过转换的图像。
这时,我们可以使用 spin build
构建整个应用程序,并使用 spin up
在本地运行它,这会为我们处理所有必要的步骤。
如图所示
你可以通过 Spin 的 OpenTelemetry 插件在本地环境轻松获得开箱即用的全面可观测性:
生态系统状态.我们已经看到一些命令行插件和触发器插件的出现。感谢所有为此付出努力的贡献者们。SpinKube 项目还有一些新版本推出。containerd-shim-spin、spin-operator 和 spin 的 Kubernetes 命令行插件都新增了一些新功能,包括选择性部署在内的新功能。
谢谢啦!感谢所有为 Spin 3 做贡献、提交问题和拉取请求、参与 Discord,特别是感谢新来的贡献者。我们很高兴看到社区的成长,并继续构建更好的无服务器 WebAssembly 应用程序体验。欢迎参加我们每周的公共 Spin 项目会议,加入 Discord 频道并在仓库中互动。
特别感谢所有一直在为 WebAssembly 生态系统做贡献的人,特别是那些继续做出贡献的人,包括 Bytecode Alliance 项目的维护者,Wasmtime 项目 和致力于 WASI (WebAssembly 系统接口) 以及 WebAssembly 组件模型 的开发人员。他们的工作对支持 Spin 非常关键。
保持联络请参加我们每周的项目会议,加入我们的讨论,在Fermyon Discord 服务器中聊天和随意聊天,并关注我们在 X(前 Twitter)上的账号@fermyontech 和 @spinframework! 如果您在 KubeCon,请来我们的展位 Q1找我们聊几句!我们期待着见到您!