为了账号安全,请及时绑定邮箱和手机立即绑定

Spin 3.0来啦:全新功能让你的无服务器Wasm应用开发更上一层楼

标签:
云计算 WebApp

作者: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 能为开发者提供的潜力。

我们为何比任何时候都更激动关于 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 应用程序的开发者提供了一种更顺畅的工作流程,并且在部署时,平台工程师依然可以灵活地拆分和运行组件。

与WASI标准的更深层次整合

我们非常支持 Spin 项目中的标准。在了解社区需求的过程中,我们积极贡献于 WASI API 的开发,并且努力将这些 API 整合到 Spin 项目中,以便大家能够从上游 WebAssembly 社区的合作和知识中受益。在此基础上,我们很高兴地告诉大家,WASI Key-ValueWASI Config API 现在已正式支持在 Spin 中使用。这标志着 WASI 云核心引入 Spin 的一个重要进展。WASI 云核心是一项旨在为应用提供标准 API 来与通用云服务交互的 WASI 建议。这标志着将 WASI 云核心引入 Spin 的旅程中的一个重要下一步。

OpenTelemetry (OTel) 集成 - 内置可观测性

可观测性对于当今的应用开发和运行时环境至关重要,从 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组件,接收用户上传的图片以及他们想要的效果
  • 一个图像变换组件,进行实际的图片变换

今天的常见做法是使用相同的编程语言来构建你的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找我们聊几句!我们期待着见到您!

点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消