Sandbox Extra 镜像推送与升级指南
日期 : 2026-07-02
环境 : Daytona v0.190.0 (Docker Compose 本地部署)
镜像 :
sandbox-extra:0.1(约 5GB / 1.38GB content)背景:由于daytona默认的镜像不满足自己的需要,于是自己改造了镜像重新打包为sandbox-extra镜像,接下来列出了推送到daytona的snapshot的过程
目录
- 整体流程概览
- 前置准备与关键参数
- [方式一:通过 Daytona API 创建 Snapshot(推荐)](#方式一:通过 Daytona API 创建 Snapshot(推荐) "#3-%E6%96%B9%E5%BC%8F%E4%B8%80%E9%80%9A%E8%BF%87-daytona-api-%E5%88%9B%E5%BB%BA-snapshot%E6%8E%A8%E8%8D%90")
- [方式二:通过 Web Dashboard 操作](#方式二:通过 Web Dashboard 操作 "#4-%E6%96%B9%E5%BC%8F%E4%BA%8C%E9%80%9A%E8%BF%87-web-dashboard-%E6%93%8D%E4%BD%9C")
- [方式三:通过 Daytona CLI 操作(开发中)](#方式三:通过 Daytona CLI 操作(开发中) "#5-%E6%96%B9%E5%BC%8F%E4%B8%89%E9%80%9A%E8%BF%87-daytona-cli-%E6%93%8D%E4%BD%9C%E5%BC%80%E5%8F%91%E4%B8%AD")
- 踩坑记录
- 后续升级镜像的标准操作流程
- [常见问题 FAQ](#常见问题 FAQ "#8-%E5%B8%B8%E8%A7%81%E9%97%AE%E9%A2%98-faq")
1. 整体流程概览
2. 前置准备与关键参数
2.1 环境信息
| 参数 | 值 |
|---|---|
| Daytona API 地址 | http://localhost:3000 |
| Registry 地址(宿主机) | localhost:6000 |
| Registry 地址(容器内部) | registry:6000 ← 关键! |
| Registry 登录 | admin / password |
| Registry 项目 | daytona |
| 组织 ID (Organization ID) | 9038b0ab-b214-46d2-a14e-d2113ecf2fd4 |
| Dex OIDC 地址 | http://localhost:5556/dex |
| Web Dashboard | http://localhost:3000/dashboard |
2.2 认证凭据
yaml
Web 登录账号: dev@daytona.io / password
API Key: dtn_b4b9e38cfcc3677bae7d72dc0812ecf7dacdb5534789e9ce2d1b89bf605d1132
⚠️ 注意 : API Key 默认权限不足以创建 snapshot(返回 403),需要用 JWT Token 认证。
3. 方式一:通过 Daytona API 创建 Snapshot(推荐)
3.1 获取 JWT Token
Daytona 使用 Dex 做 OIDC 认证,可以通过 Device Code Flow 或 Web 登录 获取 JWT Token。
方法 A:通过 Web 登录获取(最简单)
- 打开浏览器访问
http://localhost:3000/dashboard - 用
dev@daytona.io/password登录 - 登录后从浏览器开发者工具中复制 JWT Token:
- F12 → Application → Local Storage → 找到 token
- 或者在 API 请求头中复制
Authorization: Bearer xxx
方法 B:通过 Device Code Flow(命令行)
bash
# 1. 获取设备认证码
curl -s -X POST http://localhost:5556/dex/device/code \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "client_id=daytona&scope=openid%20profile%20email"
# 返回示例:
# { "device_code": "xxx", "user_code": "XXXX-XXXX",
# "verification_uri_complete": "http://localhost:5556/dex/device?user_code=XXXX-XXXX" }
# 2. 浏览器打开 verification_uri_complete 链接,用 dev@daytona.io 登录
# 3. 轮询获取 token
curl -s -X POST http://localhost:5556/dex/token \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=urn:ietf:params:oauth:grant-type:device_code" \
-d "device_code=xxx" \
-d "client_id=daytona"
3.2 验证 Token
bash
# 验证 JWT Token 有效,获取组织 ID
curl -s http://localhost:3000/api/organizations \
-H "Authorization: Bearer <JWT_TOKEN>" | jq .
# 返回示例:
# [ { "id": "9038b0ab-b214-46d2-a14e-d2113ecf2fd4", "name": "Personal", ... } ]
3.3 推送镜像到本地 Registry
bash
# 1. 给镜像打上 Registry 标签
docker tag sandbox-extra:0.1 localhost:6000/daytona/sandbox-extra:0.1
# 2. 推送到本地 Registry
docker push localhost:6000/daytona/sandbox-extra:0.1
验证推送成功:
bashcurl -s http://localhost:6000/v2/_catalog | jq . curl -s http://localhost:6000/v2/daytona/sandbox-extra/tags/list | jq .
3.4 创建 Snapshot
bash
TOKEN="<JWT_TOKEN>"
ORG_ID="9038b0ab-b214-46d2-a14e-d2113ecf2fd4"
curl -s -X POST http://localhost:3000/api/snapshots \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-H "X-Daytona-Organization-ID: $ORG_ID" \
-d '{
"name": "sandbox-extra",
"imageName": "registry:6000/daytona/sandbox-extra:0.1",
"cpu": 2,
"memory": 4,
"disk": 10,
"sandboxClass": "container"
}' | jq .
参数说明:
| 参数 | 说明 | 建议值 |
|---|---|---|
name |
Snapshot 名称,唯一标识 | sandbox-extra |
imageName |
容器内部 Registry 地址 | registry:6000/daytona/sandbox-extra:0.1 |
cpu |
Sandbox 分配的 CPU 核数 | 2 |
memory |
内存大小 (GB) | 4 |
disk |
磁盘大小 (GB) | 10 |
sandboxClass |
Sandbox 类型 | container |
3.5 查看 Snapshot 状态
bash
curl -s http://localhost:3000/api/snapshots \
-H "Authorization: Bearer $TOKEN" \
-H "X-Daytona-Organization-ID: $ORG_ID" | jq '.items[] | {name, state, size, errorReason}'
可能的状态流转:
pending → pulling → active ✅ (成功)
pending → pulling → error ❌ (失败,查看 errorReason)
3.6 删除 Snapshot(如需重试)
bash
SNAPSHOT_ID="<snapshot-id>"
curl -s -X DELETE "http://localhost:3000/api/snapshots/$SNAPSHOT_ID" \
-H "Authorization: Bearer $TOKEN" \
-H "X-Daytona-Organization-ID: $ORG_ID"
4. 方式二:通过 Web Dashboard 操作
4.1 登录 Dashboard
- 浏览器打开
http://localhost:3000/dashboard - 使用
dev@daytona.io/password登录 - Dex 会重定向回 Dashboard
4.2 推送镜像到 Registry(前提)
无论哪种方式,都需要先将镜像推送到本地 Registry:
bash
docker tag sandbox-extra:0.1 localhost:6000/daytona/sandbox-extra:0.1
docker push localhost:6000/daytona/sandbox-extra:0.1
4.3 通过界面创建 Snapshot(推测)
⚠️ 注意: 以下内容基于 API 行为推导,实际界面可能略有差异。
- 登录 Dashboard 后,找到 Snapshots(快照)管理页面
- 点击 Create Snapshot(创建快照)
- 填写以下信息:
- Name :
sandbox-extra - Image Name :
registry:6000/daytona/sandbox-extra:0.1- ⚠️ 必须用容器内部地址
registry:6000,不能用localhost:6000
- ⚠️ 必须用容器内部地址
- CPU / Memory / Disk: 按需设置
- Name :
- 点击 Create(创建)
- 等待状态从
pending→pulling→active
4.4 Registry UI 查看镜像
另外,可以通过 Registry UI 查看已推送的镜像:
- 地址:
http://localhost:5100 - 可以查看
daytona/sandbox-extra仓库及其标签
5. 方式三:通过 Daytona CLI 操作(开发中)
Daytona CLI (daytona) 当前版本 (v0.190.0) 主要用于服务端管理和 Sandbox 交互,暂未提供直接的 snapshot 管理命令。
bash
# 查看 CLI 当前可用的命令
daytona --help
如果需要从 CLI 操作,可考虑使用 curl 封装脚本(见方式一)。
6. 踩坑记录
坑 1:localhost:6000 vs registry:6000(最重要!)
❌ 错误做法:
bash
# 创建 snapshot 时使用了宿主机视角的地址
"imageName": "localhost:6000/daytona/sandbox-extra:0.1"
❌ 报错信息:
vbnet
Snapshot localhost:6000/daytona/sandbox-extra:0.1 failed to inspect in registry.
Error: Error response from daemon: Get "http://localhost:6000/v2/":
dial tcp [::1]:6000: connect: connection refused
✅ 正确做法:
bash
# 使用 Docker 内部网络的服务名
"imageName": "registry:6000/daytona/sandbox-extra:0.1"
原因分析:
makefile
宿主机视角: localhost:6000 → 可访问 Registry
Runner容器视角: localhost:6000 → 指向 Runner 自己 (连接被拒绝)
Runner容器视角: registry:6000 → Docker DNS 解析到 Registry 容器 (✅)
Runner 会去拉取镜像,所以要用 容器内部网络 的地址。
坑 2:API Key 权限不足
❌ 错误做法:
bash
# 直接用 API Key 调用 POST /api/snapshots
Authorization: Bearer dtn_b4b9e38cfcc3677bae7d72dc0812ecf7dacdb5534789e9ce2d1b89bf605d1132
❌ 报错信息:
yaml
403 Forbidden: Access denied
原因: 创建 snapshot 需要 write:snapshots 权限,而 API Key 默认可能没有此权限。
✅ 解决方法: 使用 JWT Token(通过 Web 登录获取)代替 API Key。
坑 3:Dex 不支持 password grant type
❌ 错误做法:
bash
curl -X POST http://localhost:5556/dex/token \
-d "grant_type=password&client_id=daytona&username=dev@daytona.io&password=password"
❌ 报错信息:
json
{ "error": "unsupported_grant_type" }
原因: Dex 配置中未启用 password grant type,只支持:
urn:ietf:params:oauth:grant-type:device_code(设备码)urn:ietf:params:oauth:grant-type:token-exchange(令牌交换)
✅ 解决方法: 通过 Web 登录获取 JWT,或使用 Device Code Flow。
坑 4:相同的 name 不能重复创建
第一次失败后需要先删除再重新创建,否则创建会失败。
7. 后续升级镜像的标准操作流程
当构建了新的 sandbox-extra:0.2(或更新版本)时,按以下步骤操作:
Step 1: 构建新版本镜像
bash
# 在你的构建目录下
cd /root/daytona-sandbox-extra
./build.sh # 或其他构建命令
Step 2: 推送新版本到 Registry
bash
# 打标签
docker tag sandbox-extra:0.2 localhost:6000/daytona/sandbox-extra:0.2
# 推送到 Registry
docker push localhost:6000/daytona/sandbox-extra:0.2
Step 3: 通过 Dashboard 创建新 Snapshot
- 登录
http://localhost:3000/dashboard - 进入 Snapshots 管理页面
- 点击 Create Snapshot
- 填写:
- Name :
sandbox-extra-v2(或不同的名称) - Image Name :
registry:6000/daytona/sandbox-extra:0.2 - Resource: 按需设置
- Name :
- 点击创建,等待状态变为
active
Step 4(可选): 通过 API 创建
bash
JWT="<你的JWT Token>"
ORG_ID="9038b0ab-b214-46d2-a14e-d2113ecf2fd4"
curl -s -X POST http://localhost:3000/api/snapshots \
-H "Authorization: Bearer $JWT" \
-H "Content-Type: application/json" \
-H "X-Daytona-Organization-ID: $ORG_ID" \
-d '{
"name": "sandbox-extra-v2",
"imageName": "registry:6000/daytona/sandbox-extra:0.2",
"cpu": 2,
"memory": 4,
"disk": 10,
"sandboxClass": "container"
}' | jq .
完整一键脚本
bash
#!/bin/bash
# file: /root/daytona/docker/push-sandbox-extra.sh
set -e
VERSION="${1:-0.1}"
JWT="$JWT_TOKEN" # 先 export JWT_TOKEN=...
ORG_ID="9038b0ab-b214-46d2-a14e-d2113ecf2fd4"
echo "=== 1. 打标签 ==="
docker tag sandbox-extra:${VERSION} localhost:6000/daytona/sandbox-extra:${VERSION}
echo "=== 2. 推送镜像 ==="
docker push localhost:6000/daytona/sandbox-extra:${VERSION}
echo "=== 3. 创建 Snapshot ==="
curl -s -X POST http://localhost:3000/api/snapshots \
-H "Authorization: Bearer $JWT" \
-H "Content-Type: application/json" \
-H "X-Daytona-Organization-ID: $ORG_ID" \
-d "{
\"name\": \"sandbox-extra-v${VERSION}\",
\"imageName\": \"registry:6000/daytona/sandbox-extra:${VERSION}\",
\"cpu\": 2,
\"memory\": 4,
\"disk\": 10,
\"sandboxClass\": \"container\"
}" | jq .
echo "=== 4. 等待拉取完成 ==="
sleep 5
curl -s http://localhost:3000/api/snapshots \
-H "Authorization: Bearer $JWT" \
-H "X-Daytona-Organization-ID: $ORG_ID" | jq '.items[] | {name, state, size, errorReason}'
使用方法:
bash
export JWT_TOKEN="eyJxxxxx"
bash /root/daytona/docker/push-sandbox-extra.sh 0.2
8. 常见问题 FAQ
Q: 创建 snapshot 后一直卡在 pending 状态?
A: 检查 runner 是否正常运行:docker ps | grep runner。runner 负责拉取镜像。
Q: 状态变为 error,错误信息包含 "connection refused"?
A: 镜像地址使用了 localhost:6000,应改为 registry:6000。详见 [坑 1](#坑 1 "#%E5%9D%91-1localhost6000-vs-registry6000%E6%9C%80%E9%87%8D%E8%A6%81")。
Q: API 返回 401 Unauthorized?
A: Token 可能已过期。JWT Token 有效期约 24 小时,过期后重新通过 Web 登录获取。
Q: API 返回 403 Forbidden?
A: 改用 JWT Token 而不是 API Key。详见 [坑 2](#坑 2 "#%E5%9D%91-2api-key-%E6%9D%83%E9%99%90%E4%B8%8D%E8%B6%B3")。
Q: 如何获取 Organization ID?
A: 调 GET /api/organizations 接口:
bash
curl -s http://localhost:3000/api/organizations \
-H "Authorization: Bearer $JWT" | jq '.[0].id'
Q: Registry 里有哪些镜像?
A: 通过 Registry API 查看:
bash
# 查看所有仓库
curl -s http://localhost:6000/v2/_catalog | jq .
# 查看特定仓库的标签
curl -s http://localhost:6000/v2/daytona/sandbox-extra/tags/list | jq .
Q: 如何查看 Runner 的日志排查问题?
A: docker logs daytona-runner-1 --tail 50
最后更新: 2026-07-02 | Daytona v0.190.0 | Docker Compose 部署