README_zh.md
1 # 宿主机目录挂载示例 2 3 本示例演示如何使用 OpenSandbox Volume API 将宿主机目录挂载到沙箱容器中。宿主机目录挂载支持宿主机与沙箱环境之间的双向文件共享,适用于共享数据集、模型检查点、配置文件或收集沙箱输出等场景。 4 5 ## 演示场景 6 7 | # | 场景 | 说明 | 8 |---|------|------| 9 | 1 | **读写挂载** | 挂载宿主机目录,支持双向文件读写 | 10 | 2 | **只读挂载** | 提供沙箱不可修改的共享数据 | 11 | 3 | **SubPath 挂载** | 仅挂载宿主机路径下的指定子目录 | 12 13 ## 前置条件 14 15 ### 1. 启动 OpenSandbox 服务 16 17 ```shell 18 git clone git@github.com:alibaba/OpenSandbox.git 19 cd OpenSandbox/server 20 cp opensandbox_server/examples/example.config.zh.toml ~/.sandbox.toml 21 uv sync && uv run python -m opensandbox_server.main 22 ``` 23 24 ### 2. 配置允许的宿主机路径 25 26 出于安全考虑,服务端会限制可挂载的宿主机路径。请在 `~/.sandbox.toml` 中添加 `[storage]` 配置段: 27 28 ```toml 29 [storage] 30 # 允许进行 bind mount 的宿主机路径前缀白名单。 31 # 仅匹配这些前缀的路径才能被挂载到沙箱中。 32 # 如果为空,则允许所有路径(不建议在生产环境使用)。 33 allowed_host_paths = ["/tmp/opensandbox-data", "/data/shared"] 34 ``` 35 36 > **安全提示**:在生产环境中,请务必设置明确的 `allowed_host_paths`,以防止沙箱访问敏感的宿主机目录。空列表表示允许所有路径,适合本地开发,但不适用于共享环境。 37 38 ### 3. 创建宿主机目录 39 40 ```shell 41 # 创建与沙箱共享的目录 42 mkdir -p /tmp/opensandbox-data 43 echo "hello-from-host" > /tmp/opensandbox-data/marker.txt 44 45 # 创建用于 subpath 演示的子目录 46 mkdir -p /tmp/opensandbox-data/datasets/train 47 echo -e "id,value\n1,100\n2,200\n3,300" > /tmp/opensandbox-data/datasets/train/data.csv 48 ``` 49 50 ### 4. 从源码安装 SDK 51 52 Volume 功能需要从源码安装最新版 SDK: 53 54 ```shell 55 # 在项目根目录下执行(推荐使用 uv) 56 uv pip install -e sdks/sandbox/python 57 58 # 或者使用 pip(需要在虚拟环境中执行) 59 # python3 -m venv .venv && source .venv/bin/activate 60 # pip install -e sdks/sandbox/python 61 ``` 62 63 ### 5. 拉取沙箱镜像 64 65 ```shell 66 docker pull registry.cn-hangzhou.aliyuncs.com/acs/ubuntu:latest 67 ``` 68 69 ## 运行 70 71 ```shell 72 SANDBOX_IMAGE=registry.cn-hangzhou.aliyuncs.com/acs/ubuntu:latest \ 73 HOST_VOLUME_PATH=/tmp/opensandbox-data uv run python examples/host-volume-mount/main.py 74 ``` 75 76 ## 预期输出 77 78 ```text 79 Using HOST_VOLUME_PATH: /tmp/opensandbox-data 80 81 OpenSandbox server : localhost:8080 82 Sandbox image : registry.cn-hangzhou.aliyuncs.com/acs/ubuntu:latest 83 Host volume path : /tmp/opensandbox-data 84 85 ============================================================ 86 Scenario 1: Read-Write Host Volume Mount 87 ============================================================ 88 Host path : /tmp/opensandbox-data 89 Mount path: /mnt/shared 90 91 [1] Listing files visible from inside the sandbox: 92 total 4 93 drwxr-xr-x 1 root root 128 Feb 6 09:24 . 94 drwxr-xr-x 1 root root 12 Feb 6 11:50 .. 95 drwxr-xr-x 1 root root 96 Feb 6 09:24 datasets 96 -rw-r--r-- 1 root root 16 Feb 6 09:24 marker.txt 97 98 [2] Writing a file from inside the sandbox: 99 -> Written: /mnt/shared/sandbox-greeting.txt 100 101 [3] Reading back the file: 102 Hello from sandbox! 103 104 [4] Verified on host: /tmp/opensandbox-data/sandbox-greeting.txt 105 Content: Hello from sandbox! 106 107 Scenario 1 completed. 108 109 ============================================================ 110 Scenario 2: Read-Only Host Volume Mount 111 ============================================================ 112 Host path : /tmp/opensandbox-data 113 Mount path: /mnt/readonly 114 115 [1] Reading files from read-only mount: 116 total 8 117 drwxr-xr-x 1 root root 160 Feb 6 11:50 . 118 drwxr-xr-x 1 root root 16 Feb 6 11:50 .. 119 drwxr-xr-x 1 root root 96 Feb 6 09:24 datasets 120 -rw-r--r-- 1 root root 16 Feb 6 09:24 marker.txt 121 -rw-r--r-- 1 root root 20 Feb 6 11:50 sandbox-greeting.txt 122 123 [2] Reading marker.txt: 124 hello-from-host 125 126 [3] Attempting to write (should fail): 127 touch: cannot touch '/mnt/readonly/should-fail.txt': Read-only file system 128 Write denied (expected) 129 130 Scenario 2 completed. 131 132 ============================================================ 133 Scenario 3: SubPath Host Volume Mount 134 ============================================================ 135 Host path : /tmp/opensandbox-data 136 SubPath : datasets/train 137 Mount path: /mnt/training-data 138 139 [1] Listing mounted subpath content: 140 total 4 141 drwxr-xr-x 1 root root 96 Feb 6 09:24 . 142 drwxr-xr-x 1 root root 26 Feb 6 11:50 .. 143 -rw-r--r-- 1 root root 27 Feb 6 11:50 data.csv 144 145 [2] Reading data.csv: 146 id,value 147 1,100 148 2,200 149 3,300 150 151 Scenario 3 completed. 152 153 ============================================================ 154 All scenarios completed successfully! 155 ============================================================ 156 ``` 157 158 ## 各 SDK 用法速览 159 160 ### Python(异步) 161 162 ```python 163 from opensandbox import Sandbox 164 from opensandbox.models.sandboxes import Host, Volume 165 166 sandbox = await Sandbox.create( 167 image="ubuntu", 168 volumes=[ 169 Volume( 170 name="my-data", 171 host=Host(path="/data/shared"), 172 mountPath="/mnt/data", 173 readOnly=False, # 可选,默认为 False 174 subPath="subdir", # 可选,挂载子目录 175 ), 176 ], 177 ) 178 ``` 179 180 ### Python(同步) 181 182 ```python 183 from opensandbox import SandboxSync 184 from opensandbox.models.sandboxes import Host, Volume 185 186 sandbox = SandboxSync.create( 187 image="ubuntu", 188 volumes=[ 189 Volume( 190 name="my-data", 191 host=Host(path="/data/shared"), 192 mountPath="/mnt/data", 193 ), 194 ], 195 ) 196 ``` 197 198 ### JavaScript / TypeScript 199 200 ```typescript 201 import { Sandbox } from "@alibaba-group/opensandbox"; 202 203 const sandbox = await Sandbox.create({ 204 image: "ubuntu", 205 volumes: [ 206 { 207 name: "my-data", 208 host: { path: "/data/shared" }, 209 mountPath: "/mnt/data", 210 readOnly: false, 211 }, 212 ], 213 }); 214 ``` 215 216 ### Java / Kotlin 217 218 ```java 219 Volume volume = Volume.builder() 220 .name("my-data") 221 .host(Host.of("/data/shared")) 222 .mountPath("/mnt/data") 223 .readOnly(false) 224 .build(); 225 226 Sandbox sandbox = Sandbox.builder() 227 .image("ubuntu") 228 .volume(volume) 229 .build(); 230 ``` 231 232 ## 参考资料 233 234 - [OSEP-0003: Volume 与 VolumeBinding 支持](../../oseps/0003-volume-and-volumebinding-support.md) — 设计提案 235 - [Sandbox Lifecycle API 规范](../../specs/sandbox-lifecycle.yml) — Volume 定义的 OpenAPI 规范 236 - [服务端配置示例](../../server/example.config.zh.toml) — `[storage]` 段中的 `allowed_host_paths` 配置