On this page
持久卷
持久卷让你可以将区域块存储附加到沙箱中,从而使数据在进程重启和新连接之间得以保留。它们非常适合包缓存、构建产物、SQLite 数据库,或任何需要少量耐久存储但不需要将代码提升为完整 Deno Deploy 应用的工作流。
预配存储 Jump to heading
持久卷目前处于私有测试阶段。如需访问此功能,请联系 support
:::
使用 Client.volumes 预配置存储 Jump to heading
使用管理 Deploy 应用的相同 Client 类。
import { Client } from "@deno/sandbox";
const client = new Client();
const volume = await client.volumes.create({
slug: "training-cache",
region: "ord", // ord(芝加哥)或 ams(阿姆斯特丹)
capacity: "2GB", // 接受字节数或 "1GB"/"512MB" 等样式的字符串
});
console.log(volume);
// {
// id: "8a0f...",
// slug: "training-cache",
// region: "ord",
// capacity: 2147483648,
// used: 0
// }
from deno_sandbox import DenoDeploy
sdk = DenoDeploy()
volume = sdk.volumes.create(
slug="training-cache",
region="ord", # ord (芝加哥) 或 ams (阿姆斯特丹)
capacity="2GB" # 接受字节数或 "1GB"/"512MB" 样式的字符串
)
print(volume)
# {
# "id": "8a0f...",
# "slug": "training-cache",
# "region": "ord",
# "capacity": 2147483648,
# "used": 0
# }
from deno_sandbox import AsyncDenoDeploy
sdk = AsyncDenoDeploy()
volume = await sdk.volumes.create(
slug="training-cache",
region="ord", # ord (芝加哥) 或 ams (阿姆斯特丹)
capacity="2GB" # 接受字节数或 "1GB"/"512MB" 样式的字符串
)
print(volume)
# {
# "id": "8a0f...",
# "slug": "training-cache",
# "region": "ord",
# "capacity": 2147483648,
# "used": 0
# }
| 字段 | 是否必需 | 详情 |
|---|---|---|
slug |
✅ | 在组织内唯一。Slug 会成为挂载元数据的一部分,请选择描述性强的名称。 |
region |
✅ | 必须匹配可用的沙箱区域(目前为 "ord" 或 "ams")。只有同一区域的沙箱才能挂载该卷。 |
capacity |
✅ | 介于 300 MB 和 20 GB 之间。支持字节数,或带有 GB/MB/KB(十进制)或 GiB/MiB/KiB(二进制)单位的字符串。 |
检查和搜索卷 Jump to heading
client.volumes.list() 返回分页结果和辅助迭代器,client.volumes.get() 可按 slug 或 UUID 获取单个记录。
const page = await client.volumes.list({ search: "training" });
for (const vol of page.items) {
console.log(vol.slug, vol.estimatedFlattenedSize, vol.capacity);
}
const vol = await client.volumes.get("training-cache");
page = sdk.volumes.list(search="training")
for vol in page.items:
print(f"{vol['slug']} {vol['estimatedFlattenedSize']} {vol['capacity']}")
vol = sdk.volumes.get("training-cache")
page = await sdk.volumes.list(search="training")
async for vol in page:
print(f"{vol['slug']} {vol['estimatedFlattenedSize']} {vol['capacity']}")
vol = await sdk.volumes.get("training-cache")
used 字段报告控制平面从底层集群获得的最新估算值。该值可能会比实际情况滞后几分钟,因此创建卷时请预留足够的容量。
在沙箱内挂载卷 Jump to heading
调用 Sandbox.create() 时传入 volumes 映射。键为挂载路径,值为卷的 slug 或 ID。沙箱和卷必须位于同一区域。
Sandbox.create() 和 client.sandboxes.create() 功能相同——根据你的代码风格选择使用即可。
import { Client, Sandbox } from "@deno/sandbox";
const client = new Client();
const volume = await client.volumes.create({
slug: "dataset",
region: "ord",
capacity: "1GB",
});
// 第一次运行时向卷中写入文件
{
await using sandbox = await Sandbox.create({
region: "ord",
volumes: {
"/data/dataset": volume.slug,
},
labels: { job: "prepare" },
});
await sandbox.fs.writeTextFile("/data/dataset/hello.txt", "Persist me!\n");
}
// 新沙箱 —— 可能在数小时之后启动 —— 可以读取同一个文件
{
await using sandbox = await Sandbox.create({
region: "ord",
volumes: {
"/data/dataset": volume.id, // ID 也可用
},
});
const contents = await sandbox.fs.readTextFile("/data/dataset/hello.txt");
console.log(contents); // "Persist me!"
}
from deno_sandbox import DenoDeploy
sdk = DenoDeploy()
volume = sdk.volumes.create(
slug="dataset",
region="ord",
capacity="1GB"
)
# 第一次运行时向卷中写入文件
with sdk.sandbox.create(
region="ord",
volumes={
"/data/dataset": volume["slug"],
},
labels={"job": "prepare"}
) as sandbox:
sandbox.fs.write_text_file("/data/dataset/hello.txt", "Persist me!\n")
# 新沙箱 —— 可能数小时后启动 —— 可以读取同一个文件
with sdk.sandbox.create(
region="ord",
volumes={
"/data/dataset": volume["id"], # ID 也可以用
}
) as sandbox:
contents = sandbox.fs.read_text_file("/data/dataset/hello.txt")
print(contents) # "Persist me!"
from deno_sandbox import AsyncDenoDeploy
sdk = AsyncDenoDeploy()
volume = await sdk.volumes.create(
slug="dataset",
region="ord",
capacity="1GB"
)
# 第一次运行时向卷中写入文件
async with sdk.sandbox.create(
region="ord",
volumes={
"/data/dataset": volume["slug"],
},
labels={"job": "prepare"}
) as sandbox:
await sandbox.fs.write_text_file("/data/dataset/hello.txt", "Persist me!\n")
# 新沙箱 —— 可能数小时后启动 —— 可以读取同一个文件
async with sdk.sandbox.create(
region="ord",
volumes={
"/data/dataset": volume["id"], # ID 也可以用
}
) as sandbox:
contents = await sandbox.fs.read_text_file("/data/dataset/hello.txt")
print(contents) # "Persist me!"
挂载点表现得像普通目录。你可以创建子文件夹、写入二进制文件,或直接从卷中执行程序。
安全删除卷 Jump to heading
await client.volumes.delete("training-cache");
sdk.volumes.delete("training-cache")
await sdk.volumes.delete("training-cache")
删除是一个两步过程:
- API 会立即将卷标记为删除状态,阻止新沙箱请求挂载它,并释放该 slug 以供将来使用。
- 后台任务将在 24 小时后从集群中移除底层块存储。此宽限期允许你在意外删除卷时联系支持。
宽限期内无法挂载或读取该卷。
快照 Jump to heading
快照是从卷创建的只读镜像。当沙箱以快照作为根目录启动时,整个文件系统被快照内容替换。你可以运行一次 apt-get install 或 npm install,创建快照,然后所有未来的沙箱启动时都会立即拥有预安装的软件。
创建快照的工作流程 Jump to heading
- 从基础镜像创建一个可启动卷
- 使用该卷作为
root(可写)启动沙箱 - 安装软件
- 对该卷进行快照
从快照启动的沙箱会立即启动并拥有所有预配置的软件。
当卷用 from 选项创建时即为可启动。目前唯一可用的基础镜像是 builtin:debian-13。
import { Client } from "@deno/sandbox";
const client = new Client();
// 1. 创建一个可启动卷
const volume = await client.volumes.create({
region: "ord",
slug: "my-toolchain",
capacity: "10GiB",
from: "builtin:debian-13",
});
// 2. 启动沙箱,使用该卷作为根目录(可写)
await using sandbox = await client.sandboxes.create({
region: "ord",
root: volume.slug,
});
// 3. 安装软件
await sandbox.sh`apt-get update && apt-get install -y nodejs npm`;
await sandbox.sh`npm install -g typescript`;
// 4. 对卷进行快照
const snapshot = await client.volumes.snapshot(volume.id, {
slug: "my-toolchain-snapshot",
});
# 从卷创建快照
deno sandbox snapshots create my-toolchain my-toolchain-snapshot
从快照启动 Jump to heading
拿到快照后,可用其作为创建新沙箱时的 root。沙箱必须和快照位于同一区域:
await using sandbox = await client.sandboxes.create({
region: "ord",
root: "my-toolchain-snapshot", // 快照的 slug 或 ID
});
// TypeScript 和 Node.js 已经安装好
await sandbox.sh`tsc --version`;
await sandbox.sh`node --version`;
沙箱启动时,快照的文件系统作为根目录。会话期间所有写操作都是临时性的,它们不会修改快照。
列出快照 Jump to heading
const page = await client.snapshots.list();
for (const snap of page.items) {
console.log(snap.slug, snap.region, snap.bootable);
}
$ deno sandbox snapshots list
ID SLUG REGION ALLOCATED BOOTABLE
snp_ord_spmbe47dysccpy277ma6 my-toolchain-snapshot ord 217.05 MiB TRUE
从快照创建卷 Jump to heading
从快照创建一个新的可写卷:
const volume = await client.volumes.create({
region: "ord",
slug: "my-toolchain-fork",
capacity: "10GiB",
from: "my-toolchain-snapshot",
});
新卷包含快照内容且完全可写。你可以用它来修改快照内容然后重新创建快照。
删除快照 Jump to heading
await client.snapshots.delete("my-toolchain-snapshot");
deno sandbox snapshots delete my-toolchain-snapshot
卷 和 快照对比 Jump to heading
| 特性 | 卷(Volumes) | 快照(Snapshots) |
|---|---|---|
| 访问权限 | 读写 | 只读 |
| 挂载点 | 任意路径,启动卷可用作根目录 | 仅根文件系统 |
| 使用场景 | 缓存、数据库、安装软件 | 预安装的软件、工具链 |
| 并发使用 | 同时只能一个沙箱挂载 | 多个沙箱可以同时使用 |
| 区域 | 必须与沙箱区域匹配 | 必须与沙箱区域匹配 |