Baseten 发布 BDN Sealed Volumes,模型数据一次发布随处挂载
BDN Sealed Volumes: publish once, mount anywhere
Baseten 发布 BDN Sealed Volumes,可将只读数据发布为带摘要的不可变版本,并在任意部署中挂载。卷支持从 Hugging Face、S3、GCS、Azure Blob、Cloudflare R2 和 CoreWeave 桶同步,也可用 baseten volume push 上传本地目录,上传时只传输内容哈希发生变化的块。
原文给出了密封卷的版本与摘要机制,读者可据此判断模型数据在多次部署间如何保持一致。
当模型文件没有单一可信来源时,数据就会偏离其源头。
假设你微调了一个模型,然后把检查点保存到云存储。接着有人下载一份副本到自己的笔记本电脑上测试,又把它上传到别处以便提供服务,而每个部署——例如预发布、生产和测试——都有自己的配置文件指向该检查点。当某个人固定到另一个修订版本时,直到输出出现差异才会有人察觉。
同样的问题也适用于 LoRA 适配器、向量索引、分词器、嵌入索引、查找表,以及任何模型或部署产物。容器镜像在十年前就为代码解决了这个问题:你构建一次,得到一个摘要,然后在任何地方运行该摘要。我们推出 BDN Sealed Volumes,为模型数据做同样的事,并帮助我们的客户在迭代过程中保持数据一致。
什么是密封卷?
密封卷让你可以一次发布任何只读数据,并将其挂载到任何部署中。推送一个目录,或同步一个 Hugging Face 仓库、一个存储桶或一个训练检查点,BDN 就会将结果密封为一个带摘要的不可变版本。在你的 config.yaml 中引用该摘要,每个副本就能流式读取完全相同的数据,无需手动下载任何内容。
卷具体来说是一组有名称、有版本的文件,由 Baseten Delivery Network (BDN) 交付到你的部署中。卷存在于命名空间中,例如 weights,并持有一系列版本。当 baseten volume push 或 baseten volume sync 完成时,BDN 会将文件提交为新版本并将其密封。密封版本永不改变,BDN 通过其内容的摘要来标识它:
bdn:weights/qwen3-8b@b3:9f3c…推送时可以使用 --tag 参数,为特定版本赋予一个可变名称(唯一可变的部分)。例如,使用 --tag prod 推送会将 prod 指向新版本;因此,虽然 bdn:weights/qwen3-8b:prod 是人们可以读取的名称,但部署应当固定的是摘要。如果你用过容器镜像仓库,这与标签和镜像摘要之间的区分是一样的,存在的原因也相同。
由于你的摘要位于配置文件中,版本之间的不匹配会体现在差异中。
✕
一个卷包含三个密封版本。“prod”标签指向版本二,通过推送或标签命令移动到此,两个部署都固定了它的摘要。
为什么要密封卷?
密封卷是在其之上构建时保持数据一致的关键。因为它们是密封的:
每个副本提供相同的字节:密封版本永不改变,每个引用它的部署都以只读方式挂载相同的文件,因此每个副本流式读取相同的字节。固定摘要意味着后续推送无法改变此部署挂载的内容。要回滚,只需将
config.yaml指向更早的摘要。更新只上传变更的部分:BDN 将文件拆分为块,并按内容哈希将每个块只存储一次,因此与上一个检查点共享大部分字节的新检查点只上传发生变化的块。文件以哈希为键,因此 BDN 绝不会传输它已经持有的文件。这使得迭代上传(例如微调基础模型)变得快速。
部署启动无需下载步骤:由于密封卷挂载在你于
config.yaml中选择的路径上,容器一启动文件就可用。当你的模型读取数据时,字节会从 BDN 缓存层级 流式传入。启动时间不再取决于卷的大小。
如何用两条命令发布密封卷
对于 Hugging Face 上的模型,同步会作为 Baseten 上的持久后台任务运行;不会向你的机器下载任何内容。这就是整个循环:
baseten volume sync start \
--source hf://Qwen/Qwen3-8B \
--dest bdn:weights/qwen3-8b:prod \
--include "*.safetensors" --include "*.json" \
--wait当任务报告 READY 时,它会打印密封版本的引用。将其复制到部署中:
model_name: qwen3-8b
resources:
accelerator: H100
bdn:
mounts:
- source: bdn:weights/qwen3-8b@b3:<digest>
path: /mnt/weights/qwen3-8b将你的服务器指向 /mnt/weights/qwen3-8b,并使用 baseten model push 进行部署。
无需维护权重块,部署中也没有凭据。后续引用已镜像内容的部署只需通过元数据检查即可解析,而无需数据传输。
sync 对 Hugging Face、S3、GCS、Azure Blob、Cloudflare R2 和 CoreWeave 存储桶的工作方式相同。私有源需要 Baseten 密钥,而对于 S3 和 GCS,你可以完全跳过存储凭据,改用 OIDC 授予访问权限。要改为发布本地目录,请使用:
baseten volume push ./dir bdn:weights/qwen3-8b --tag prodpush 并行上传分块,并跳过 BDN 已持有的任何分块。
更新版本与回滚
使用 --tag prod 推送会将标签移动到新版本,而不发布任何内容:
baseten volume tag set --volume-ref bdn:weights/qwen3-8b@b3:<digest> --tag prod固定摘要的部署会继续提供旧版本,直到你更改 source 并重新部署。之后移动标签不会改变正在运行的副本所提供的内容,但新建和扩容的副本会挂载标签的新目标。因此,挂载标签的部署在推送后可能同时提供两个版本。
要回滚,请从 baseten volume versions 中选择较早的摘要,将其设置为 source,然后重新部署。已删除的版本可在 7 天内通过 baseten volume restore 恢复。
BDN Sealed Volumes 不仅仅用于模型权重
你的模型读取但不写入的任何内容都应放在卷中。部署在运行时读取且应放在卷中的常见文件包括:
适配器和子模型。 在单个基础模型上部署多个 LoRA 适配器,并在推理时在它们之间切换。每个适配器可以是自己的卷,新适配器无需新镜像。
预构建引擎。 TensorRT-LLM 引擎或编译图体积大、特定于 GPU 且不可变。每种 GPU 类型发布一次,并按摘要挂载,这样重新部署时无需重新构建。
索引和表。 这包括嵌入索引、词汇文件、分词器配置、查找表和安全分类器。如今这些内容会在
load()中下载,或打包进镜像,但有了卷,它们就可以版本化、跨部署共享,并在启动时可用。评估和参考数据。 例如,部署用于自我评分的黄金集,或服务层渲染的提示模板。
编译缓存。 BDN Startup Cache 是我们在卷上构建的第一个东西,它将副本的已编译内核和捕获图发布为密封卷,并在部署的每个后续副本中恢复它。它会出现在
baseten volume ls中,与你自行发布的卷并列。
其中每一项都是一个目录和一个单独的 baseten volume push。挂载多个就是在 bdn.mounts 下增加更多条目,而挂载相同摘要的两个部署在每个缓存层上共享完全相同的字节。
在训练到部署的循环中构建一致性
“复制问题”在模型训练方面最为严重:作业将检查点写入存储,然后为了提供服务,你下载权重、将它们上传到别处,并为每个部署编辑配置文件。
卷有助于阻止训练到部署循环中的数据漂移。如果你在自己的集群上训练,带有 CLI 和 API 密钥的作业会在完成时发布自己的输出:
baseten volume push ./checkpoints/step-4000 bdn:weights/my-model --tag candidate另一方面,如果你在 Baseten 上进行训练,作业的检查点已经同步到 Baseten 存储,检查点会从那里同步到卷中(无需管理凭据):
baseten volume sync start \
--source bt://my-project@job123/checkpoint-1 \
--dest bdn:weights/my-model:candidate \
--wait你自己存储桶中的检查点会通过 s3://、gs:// 或上述其他来源同步到那里。
由于 push 和 sync 只上传发生变化的块,因此每几百步发布一次检查点的训练运行每次只传输模型的一小部分,并且每个版本都保持可寻址。对于这一循环中频率更高的版本——训练器每隔几分钟发布增量,rollout 集群实时应用这些增量——请参阅我们如何为托管 RL rollout 同步增量权重(两种情况下的传输机制都是 BDN)。
BDN Sealed Volumes 有多快?
Sealed Volumes 与 BDN 权重一样,通过相同的三级缓存读取:节点磁盘、集群内缓存和镜像源。不同之处在于,weights 块会在容器启动前拉取所有文件,因此启动时间会随模型大小而增长。
相比之下,BDN Sealed Volume 可在数秒内挂载完成,模型从中读取的速度与从 weights 挂载点读取的速度相同。这意味着拉取阶段从启动时间中消失了(其他方面没有任何变化)。数据的提供速度取决于网络和磁盘,并在技术栈的每一层避免不必要的获取。
✕
同一个模型分别使用“weights”块和 BDN Sealed Volume。拉取阶段变成了挂载,而加载模型阶段在两者中是相同的工作。
惰性读取路径还使卷可以大于节点的磁盘,因为节点只保留模型访问过的块,并驱逐可以再次获取的块。当模型读取一个已被驱逐的块时,集群内缓存(与帮助实现 BDN 快速冷启动的是同一层)会以网络线速将其返回。
weights 块与 Sealed Volumes 的未来
如果你目前使用 weights 块进行部署,则无需做任何更改。随着迁移的推进,我们会自动将 weights 部署迁移到 Sealed Volumes,你这边无需更改配置。
对于新的权重,我们鼓励你直接使用 sealed volumes:将源同步到卷中并挂载它。
以下是 weight 块和卷目前在这两方面的对比:
要迁移,请对 weights 中的源运行一次同步,然后将结果挂载到相同的 mount_location。你的模型代码无需任何更改。
挂载点是只读的;对于模型在运行时写入的文件,请使用 b10cache。
开始使用
要开始使用 BDN Sealed Volumes,请将 Baseten CLI 升级到 1.1.0 或更高版本(brew upgrade baseten),如果你使用 Truss 部署,请将 Truss 升级到 0.18.30 或更高版本。然后运行快速入门,它会在约五分钟内发布一个目录、挂载它并部署一个模型。管理和同步页面涵盖了版本、回滚以及所有源类型。
Sealed volumes 是 BDN Fabric 的第一个面向用户的原语,BDN Fabric 是下一代 Baseten Delivery Network。如果你想详细讨论你的权重流水线,请联系与我们的工程师交流。
注意:截至本文最后更新日期,卷挂载在 T4 或 L4 实例上不可用。
致谢
非常感谢参与实现 BDN Sealed Volumes 的众多人员:Angie Montemayor、Xiaoqian Liu、Kamal Haddad、Ahmet Balkan、Amy Hu、Christine Wang、Shreya Ravi、Brian Broll、Sid Gupta、Chad Retz 和 Patrick R。
来源:Baseten Blog · baseten.co