ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Spin 应用通过 OCI Registry 分发:SIP 008 设计与源码实现深度解析

Spin 应用通过 OCI Registry 分发:SIP 008 设计与源码实现深度解析 云原生微服务【免费下载链接】spinSpin is the open source developer tool for building and running serverless applications powered by WebAssembly.项目地址https://gitcode.com/gh_mirrors/spin1/spin点击查看免费下载导读本文围绕 Spin 项目的改进提案 SIP 008 - Distributing Spin applications using OCI registries完整梳理 Spin 应用从传统 Bindle 分发机制迁移到 OCI Registry 的动机、用户交互设计、OCI 镜像结构设计、认证方案与源码级实现细节。读完本文你将掌握spin oci push、spin oci pull、spin oci login与spin up --oci背后的完整链路如何把一个包含元数据、Wasm 模块和静态资源的 Spin 应用打包为多层 OCI artifact、如何复用 Docker 凭据、以及 Spin 如何用 locked application 作为配置对象从本地缓存中重建并运行应用。背景为什么 Spin 要引入 OCI Registry自 Spin 首次发布以来应用分发一直依赖 Bindle——一个最初为分发 WebAssembly 应用及配套文件而设计的实验性聚合对象存储项目。然而 Bindle 作为相对早期的项目暴露了两个突出问题没有托管版 Bindle 服务用户分发 Spin 应用必须自行搭建并维护基础设施这对最简单的应用来说也显著增加了复杂度基础设施的横向扩容在 Bindle 项目中是尚未解决的难题。与此同时OCIOpen Container Initiative 已成为打包与分发容器镜像的事实标准且随着 OCI Artifacts 项目的推进容器 Registry 的使用范围正扩展到越来越多的 artifact 类型。所有主流云厂商均提供托管 Registry 服务其中不少已支持分发其他类型的 artifact。因此 SIP 008 提议让 Spin 直接支持通过 OCI Registry 分发应用一举解决上述两个问题借助现成的托管服务如 GitHub Container Registry、Docker Hub、AWS Elastic Container Registry、Azure Container Registry、Google Artifact Registry 等用户无需自建分发基础设施扩容问题交给托管服务解决即便自建容器 Registry 的横向扩容也有远比 Bindle 丰富的资源与方案。提案核心基于 OCI artifact 的 Spin 应用分发SIP 008 的核心观点是一个 Spin 应用由元数据 组件信息以及组成这些组件的Wasm 模块和静态资源构成。因此一个 Spin 应用在概念上并不是“单一 artifact”而是多个不同对象的集合。基于此提案设计Spin 应用发布到 OCI Registry 后将成为一个新的 OCIartifact拥有多个层layers注意 OCI 中image与artifact是两种不同实体。具体约定如下实体说明配置对象 media typeapplication/vnd.fermyon.spin.application.v1config承载 Spin 应用定义Wasm 模块层每个组件的 Wasm 模块成为一个独立 layerapplication/vnd.wasm.content.layer.v1wasm静态资源层组件引用的每个静态资源也成为独立 layerapplication/vnd.wasm.content.layer.v1data正因为每个文件与每个 Wasm 模块都成为独立的 layerRegistry 可以高效地对应用进行去重de-duplicate与分发多个应用共享同一 Wasm 模块或静态文件时Registry 只需存储一份 blob。应用定义用什么表示locked application剩下的关键问题是如何表示 Spin 应用定义。Spin 引入了locked application锁定应用这一内部表示——它是 Spin 应用的一种中间表示能够以内容寻址content-address的方式引用 Wasm 模块与静态资源。SIP 008 的实现正是将 locked application 作为 OCI 配置对象即 OCI manifest 中的config项使用。用户体验设计push / pull / run 三命令提案给出的目标用户体验非常直接把应用推送到兼容 Registry、拉取到本地、然后运行$ spin oci push ghcr.io/username/my-spin-application:v1 INFO spin_publish::oci::client: Pushed https://ghcr.io/v2/username/my-spin-application/manifests/sha256:9f4e7eebb27c0174fe6654ef5e0f908f1edc8f625324a9f49967ccde44a6516b $ spin oci pull ghcr.io/username/my-spin-application:v1 INFO spin_publish::oci::client: Pulled ghcr.io/username/my-spin-application:v1sha256:9f4e7eebb27c0174fe6654ef5e0f908f1edc8f625324a9f49967ccde44a6516b $ spin up --oci ghcr.io/username/my-spin-application:v1 INFO spin_publish::oci::client: Pulled ghcr.io/username/my-spin-application:v1sha256:9f4e7eebb27c0174fe6654ef5e0f908f1edc8f625324a9f49967ccde44a6516b Serving http://127.0.0.1:3000其中spin up --oci reference会在启动前自动完成拉取然后基于本地缓存直接运行应用。认证复用 Docker 凭据 内置spin oci login历史上dockerCLI 是与容器镜像、Registry 交互的主流工具链因此提案要求spin oci能够复用已登录用户的 Docker 凭据同时大多数容器 Registry 服务也都有基于docker login的登录说明。但本地装有 Docker 不应成为使用 Spin 的前提。为此提案设计了spin oci login命令让 Spin CLI 直接向目标 Registry 完成认证$ spin oci login --username username --password password # OR 通过 stdin 读取密码避免密码出现在命令行历史中 $ echo $CONTAINER_REGISTRY_PASSWORD | spin oci login --username username --password-stdin这一交互方式对标docker login命令。源码印证凭据的获取与存储优先级从仓库源码看认证逻辑已经落地在 crates/oci/src/client.rs 的Client::auth中其凭据解析优先级为优先读取 Spin 自身的认证配置文件$XDG_CONFIG_HOME/fermyon/registry-auth.json由 crates/oci/src/auth.rs 维护auths字段以 registry server 为 key、以 base64 编码的username:password为 value读取失败则回退到 Docker 凭据docker_credentialcrate支持UsernamePassword形式若 Docker 凭据是IdentityToken形式则退化为匿名认证兜底为匿名认证RegistryAuth::Anonymous。此外Client::logincrates/oci/src/client.rs在保存凭据前会先调用validate_credentials向 Registry 发送一次认证请求提前校验凭据有效性避免用户在第一次 push/pull 时才遇到认证错误。从 Bindle 迁移到 OCI Registry将分发机制从 Bindle 切换到 OCI 对项目而言是破坏性变更。为降低迁移成本提案建议提供从 Bindle 迁移到 OCI Registry 的功能。考虑到该工具的“临时性”——其价值会随时间迅速衰减且未来移除它会再次造成破坏性变更——该功能最适合做成一个 Spin 插件按需安装、独立分发spin bindle2oci \ --bindle-server server \ --bindle-username username \ --bindle-password password \ --bindle name \ --oci new-reference注意该迁移工具在 SIP 008 成文时尚未开始实现见下文“实现状态”。一个完整的实例manifest、locked app 与本地缓存结构提案用github-stars-webhook这个应用完整演示了从spin.toml到 OCI manifest、locked application再到本地拉取缓存目录的完整形态。应用定义spin.tomlspin_version 1 authors [Radu Matei radu.mateifermyon.com] description name github-stars-webhook trigger { type http, base / } version 0.1.0 [[component]] id github-star-webhook source target/spin-http-js.wasm files [my-file.json] allowed_http_hosts [https://hooks.slack.com] [component.trigger] route /...该应用包含一个组件github-star-webhookWasm 源为target/spin-http-js.wasm与一个静态资源my-file.json。将其发布到 GitHub Container Registry$ spin oci push ghcr.io/radu-matei/spin-example:v1 INFO spin_publish::oci::client: Pushed https://ghcr.io/v2/radu-matei/spin-example/manifests/sha256:8f86a27fbc457416701c4d18680083f598076d0a52dca2a5936e92754a845ed1 $ spin oci pull ghcr.io/radu-matei/spin-example:v1 INFO spin_publish::oci::client: Pulled ghcr.io/radu-matei/spin-example:v1sha256:8f86a27fbc457416701c4d18680083f598076d0a52dca2a5936e92754a845ed1拉取后的本地缓存目录结构$ tree /Users/radu/Library/Application\ Support/fermyon/registry └── oci ├── data │ └── sha256:a4699e4f9ef3f4922f38f0d017aa26438908f38caf020a739e0ee27fe796eb02 ├── manifests │ └── ghcr.io │ └── radu-matei │ └── spin-example │ └── v1 │ ├── config.json │ └── manifest.json └── wasm └── sha256:55c29ad4b0ad0c6bd8ec1ffc8f04e63342e5901280037ef706b1b114475d3cbb缓存目录按「Registry 名 / 仓库路径 / tag」组织 manifestblob 则按 sha256 digest 存放在wasmWasm 模块与data静态资源两个目录中。这与仓库中的实现完全对应Cache::ensure_dirscrates/loader/src/cache.rs会创建root/registry/{manifests,wasm,data}三个子目录Client::pullcrates/oci/src/client.rs将 manifest 写入cache_root/registry/oci/manifests/registry/repository/tag/manifest.json把 Wasm 层写入 wasm 目录、其他层含归档层解包后写入 data 目录。OCI manifest应用成为多层 artifact查看manifest.json可以看到 artifact 配置的顶层 media type 正是application/vnd.fermyon.spin.application.v1config{ schemaVersion: 2, config: { mediaType: application/vnd.fermyon.spin.application.v1config, digest: sha256:b36160facea3076ad136c09bd4975a429805945ad313b4674363841d5a7f66a0, size: 643 }, layers: [ { mediaType: application/vnd.wasm.content.layer.v1wasm, digest: sha256:55c29ad4b0ad0c6bd8ec1ffc8f04e63342e5901280037ef706b1b114475d3cbb, size: 2147122 }, { mediaType: application/vnd.wasm.content.layer.v1data, digest: sha256:a4699e4f9ef3f4922f38f0d017aa26438908f38caf020a739e0ee27fe796eb02, size: 178 } ] }manifest 中出现了两个 layer组件的 Wasm 模块层与组件引用的静态资源层。每新增一个组件其 Wasm 模块与静态资源都会成为 manifest 中各自的独立 layer。层与配置对象之间的引用通过sha256digest 建立这与仓库中assemble_layers系列函数的行为一致push时先为每个组件的 source、每个依赖、每个 trigger 依赖以及每个静态资源文件生成独立ImageLayer再以 locked app 序列化结果作为配置层crates/oci/src/client.rs。OCI 配置对象即 locked applicationconfig.json正是 Spin 能够直接据以运行应用的 locked application manifest{ spin_lock_version: 0, metadata: { description: , name: github-stars-webhook, trigger: { base: /, type: http }, version: 0.1.0 }, triggers: [ { id: trigger--github-star-webhook, trigger_type: http, trigger_config: { component: github-star-webhook, executor: null, route: /... } } ], components: [ { id: github-star-webhook, metadata: { allowed_http_hosts: [https://hooks.slack.com] }, source: { content_type: application/wasm, digest: sha256:55c29ad4b0ad0c6bd8ec1ffc8f04e63342e5901280037ef706b1b114475d3cbb }, files: [ { digest: sha256:a4699e4f9ef3f4922f38f0d017aa26438908f38caf020a739e0ee27fe796eb02, path: my-file.json } ] } ] }观察组件source与files中的digest字段——它们与 OCI manifest 中各 layer 的 digest 一一对应即组件内容以内容寻址方式指向 Registry 中的实际 blob。这正构成了 Spin push、pull、run 全流程所需的全部信息push 时锁定应用的引用pull 时按 digest 取回内容run 时从本地缓存还原应用。这一结构在 crates/oci/src/loader.rs 的OciLoader::load_from_cache中得到印证读取配置对象后若包含spin_lock_version字段则将其解析为LockedApp并把origin元数据写为vnd.fermyon.origin-oci:reference由 crates/oci/src/lib.rs 定义的ORIGIN_URL_SCHEME随后调用resolve_component_content_refscrates/oci/src/loader.rs将每个组件 source、依赖、trigger 依赖的 Wasm 内容替换为缓存中的 wasm 文件路径把静态资源复制/落盘到临时挂载目录并更新files引用。关于 Wasm 层 media type 的社区现状提案明确提示上述 media type 并非最终定稿可能随社区对 OCI Registry 中 Wasm 模块的标准化而调整。文档列举了当时的几种既有方案wasm-to-oci与oci-distribution使用application/vnd.wasm.content.layer.v1wasmsolo-io/wasm/spec使用application/vnd.module.wasm.content.layer.v1wasmDocker 的预览实现似乎以application/vnd.docker.container.image.v1json分发。简言之当时尚无统一标准。倾向于为模块采用application/vnd.module.wasm.content.layer.v1wasm的理由是未来可能引入components概念。仓库实现中同样保留了这一演进空间Wasm 层 media type 被定义为常量WASM_LAYER_MEDIA_TYPE并注释“一旦上游定义规范值将更新”crates/oci/src/client.rs拉取时 Wasm 层与数据层分别写入缓存的不同目录且Cache::wasm_file在 wasm 目录缺失时会回退查找 data 目录crates/loader/src/cache.rs以兼容未来 media type 的变化。spin oci push的设计宽松的 tag 与版本策略spin oci push的目标是让用户借助广泛可用的容器 Registry 服务分发应用并尽可能灵活地与用户现有工作流集成因此在版本号与 tag 可变性上刻意保持无意见unopinionated。方式一命令行显式指定引用$ spin oci push --file path to spin.toml myregistry.com/myusername/myapp:v1 # OR $ spin oci push --file path to spin.toml myregistry.com/myusername/myapp:latest # OR $ spin oci push --file path to spin.toml myregistry.com/myusername/myapp:v0.1.0r2d2方式二从spin.toml推导引用与 tag当spin.toml中的应用名与版本构成完整引用时无需在命令行重复指定name myregistry.com/myusername/myapp version 1.2.3$ spin oci push --file path to spin.toml ... Pushed the application to myregistry.com/myusername/myapp:v1.2.3 # OR 附加构建信息 $ spin oci push --file path to spin.toml --buildinfo ... Pushed the application to myregistry.com/myusername/myapp:v1.2.3r2d2注意当未在命令行显式传值、由spin.toml推导引用与 tag 时应用名必须包含完整限定的引用fully qualified reference且 tag 只能是语义化版本。源码佐证push 的内部流程从源码看Client::pushcrates/oci/src/client.rs的流程为解析 reference → 获取认证 → 用spin_loader::from_file依据spin.toml构建 locked application → 对每个组件调用validate::ensure_wasms校验 source/dependency/trigger dependency 都是合法 Wasm → 组装层并推送。组装层时支持两种模式ComposeMode::All推送前先用 crates/compose 对组件进行预组合composition依赖与 trigger 依赖合并进组件 Wasm最终每组件一个层ComposeMode::Skip跳过组合依赖与 trigger 依赖如 HTTP 中间件各自成为独立层避免发布结果仍指向推送机器的本地文件系统。此外还有几项与推送强相关的实现细节归档层默认每文件一层AssemblyMode::Simple当层数超过MAX_LAYER_COUNT - 1常量 500对齐主流 Registry 的镜像层数上限如 Elastic Container Registry 的 500 层限制或设置环境变量SPIN_OCI_ARCHIVE_LAYERS时改为AssemblyMode::Archive——组件的所有静态资源打包进单个application/vnd.wasm.content.bundle.v1.targzip归档层crates/oci/src/utils.rs 实现 tar.gz 打包/解包小内容内联小于DEFAULT_CONTENT_REF_INLINE_MAX_SIZE128 字节的内容直接内联进配置对象的ContentRef不单独推送 blob以规避部分 OCI 实现不支持极小 blob 的问题层去重assemble_layers对生成的层做unique()去重多个组件共享同一 Wasm/文件时只推一份OCI 注解除非显式关闭推送时自动生成org.opencontainers.image.{authors,title,description,version,created}等预定义注解显式注解优先详见all_annotationscrates/oci/src/client.rsimage config构建 OCI image config 时写入architecture: wasm、os: wasip1并通过 labelcom.fermyon.spin.lockedAppDigest引用 locked app 配置层的 digest避免不同应用得到相同 image ID。对spin deploy的影响与spin oci push的灵活性不同spin deploy属于有明确观点的意见化工作流可以继续强制自己的 tag 可变性与版本策略。提案采用渐进式迁移策略至少先发布一个包含spin oci的 minor 版本在 Fermyon Platform 与 Fermyon Cloud 支持接受 OCI 引用之后先实现spin deploy --oci功能然后才把spin deploy的默认行为改为期望 OCI Registry届时 Fermyon Platform 与 Fermyon Cloud 已同步支持该变更。实现状态与 FAQSIP 008 成文时的实现状态如下spin oci push、spin oci pull、spin oci run已在原型 PR 中实现可参考 crates/oci 模块其中OciLoader同时支持加载应用与单个 Wasm 包两种 artifact底层通过 Krustlet 的oci-distributioncrate 与容器 Registry 交互当时使用一个待回馈上游的 forkloader 内部仍需进一步打磨方可合并Bindle → OCI 迁移工具尚未启动spin oci login当时尚未实现其核心逻辑现已在 crates/oci/src/client.rs 与 crates/oci/src/auth.rs 中落地。FAQ 还回应了与 Bytecode Alliance Registry 项目warg的关系Spin 维护者也是该 Registry 项目的创建者之一该项目的目标之一是复用包括 OCI Registry 在内的既有存储作为后端待其成熟后Spin 计划将其作为分发机制之一。关键源码索引关注点位置SIP 008 原始提案docs/content/sips/008-using-oci-registries.mdOCI 客户端push/pull/login/认证crates/oci/src/client.rs、crates/oci/src/auth.rsOCI 加载器pull 后重建可运行应用crates/oci/src/loader.rs归档/解包工具crates/oci/src/utils.rsOCI 引用识别启发式is_probably_oci_referencecrates/oci/src/lib.rs本地缓存结构manifests/wasm/datacrates/loader/src/cache.rs组件预组合crates/compose/src/lib.rs补充说明SIP 008 属于早期设计提案文中命令语法如--file、--buildinfo与最终 CLI 形态可能存在差异使用时请以当前版本spin oci push --help的实际输出为准提案中的参考链接如原型 PR、oci-distribution用于理解演进脉络文中已改为仓库内源码证据。赞分享云原生微服务【免费下载链接】spinSpin is the open source developer tool for building and running serverless applications powered by WebAssembly.项目地址https://gitcode.com/gh_mirrors/spin1/spin点击查看免费下载相关推荐Spin 服务链式调用Service Chaining深度解析SIP 017 设计决策与源码实现Spin 服务链式调用Service Chaining深度解析SIP 017 设计决策与源码实现 本篇技术指南围绕 Spin 官方设计提案 SIP 017云原生微服务Spin 插件体系深度解析基于 SIP 006 的 spin plugin 命令、Manifest 规范与源码实现Spin 插件体系深度解析基于 SIP 006 的 spin plugin 命令、Manifest 规范与源码实现 本文以 Spin 开源仓库中的 SIP 0云原生微服务GSD 工作流工具通过 MCP 暴露实现 Provider ParityADR-008 实施计划深度解析GSD 工作流工具通过 MCP 暴露实现 Provider ParityADR 008 实施计划深度解析 本文是 GSD 项目内部架构决策 ADR 008将人工智能AI Agent代码智能体Agent 编排CLIAI 应用上一篇WarcraftHelper让经典魔兽争霸3在现代电脑上焕发新生下一篇AMD Ryzen处理器终极调试指南SMUDebugTool让你的硬件性能飞起来创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表