文件挂载机制
本章说明容器内部的文件系统是怎么构造出来的。每个容器里看到的 /workspace 目录并不是凭空出现的,而是通过 K8s 的 Volume(卷)机制把宿主机(运行 K3s 的物理机器)上的目录映射进去的。
1. 容器内的文件系统视图
agentcore 启动后看到的文件结构:
/workspace/ ← 容器根工作目录
├── in/ ← 输入(只读区域)
│ ├── run-context.json ← Backend 从数据库生成的运行上下文
│ ├── report.pdf ← 用户上传的文件
│ └── data.csv ← 用户上传的文件
├── out/ ← 输出(agentcore 写入)
│ └── artifacts/ ← agentcore 生成的文件(可选)
├── tmp/ ← 临时目录
├── session/ ← 本地缓存与日志(可选)
│ ├── cache/ ← 本地缓存
│ └── logs/ ← Worker 日志与排障信息
├── pkg/ ← Agent 包文件(只读)
│ ├── system-prompt.md
│ └── tools.json
└── mounts/ ← 用户授权的外部目录(可选)
└── my-data/ ← 用户授权挂载的本地目录
2. 四类挂载卷
系统使用四种不同的 Volume(卷)来构建上述文件结构:
graph TB
subgraph INSIDE["容器内"]
WS["/workspace<br/>hostPath 卷"]
SESS["/workspace/session<br/>hostPath 卷"]
PKG["/workspace/pkg<br/>ConfigMap 卷"]
MNT["/workspace/mounts/xxx<br/>hostPath 卷"]
end
subgraph HOST_SIDE["宿主机"]
H_WS["workspaces/[run-id]/"]
H_SESS["sessions/[session-id]/"]
H_PKG["ConfigMap 资源<br/>(K3s 管理)"]
H_MNT["用户指定的本地目录"]
end
H_WS -.->|挂载| WS
H_SESS -.->|挂载| SESS
H_PKG -.->|挂载| PKG
H_MNT -.->|挂载| MNT
2.1 工作区卷(Workspace Volume)
| 属性 | 说明 |
|---|---|
| 类型 | hostPath(宿主机目录挂载) |
| 宿主机路径 | workspaces/[run-id]/ |
| 容器挂载点 | /workspace |
| 生命周期 | 随 Run 创建,Run 结束后保留供结果读取 |
| 读写权限 | 可读可写 |
这是每次运行的独占工作区,不同 Run 之间互不共享。
2.2 会话本地目录卷(Session Local Volume)
| 属性 | 说明 |
|---|---|
| 类型 | hostPath |
| 宿主机路径 | sessions/[session-id]/ |
| 容器挂载点 | /workspace/session |
| 生命周期 | 随 Session 创建,可跨 Run 保留 |
| 读写权限 | 可读可写 |
这个目录主要用于缓存、日志、临时产物等本地文件。
当前方案下,多轮连续性的权威状态由 Backend 查询数据库并通过协议提供给 Worker,而不是依赖容器直接读取这里的数据库文件。
2.3 包文件卷(Package Volume)
| 属性 | 说明 |
|---|---|
| 类型 | ConfigMap(K8s 配置映射资源) |
| 数据来源 | Agent 包中的所有文件 |
| 容器挂载点 | /workspace/pkg |
| 生命周期 | 随 Run 创建和销毁 |
| 读写权限 | 只读 |
Agent 包文件不是从宿主机目录挂载的,而是通过 K8s 的 ConfigMap 机制以“虚拟文件“形式出现在容器内。这种方式不依赖文件在宿主机的具体路径。
限制:ConfigMap 单个资源有 1 MB 的大小限制。如果 Agent 包文件总量超过此限制,需要考虑其他方案。
2.4 用户挂载卷(Mount Grant Volume)
| 属性 | 说明 |
|---|---|
| 类型 | hostPath |
| 宿主机路径 | 用户通过 mount_grant 指定的路径 |
| 容器挂载点 | /workspace/mounts/[名称] |
| 生命周期 | 仅本次 Run |
| 读写权限 | 根据配置可只读或读写 |
mount_grant(挂载授权)允许用户将本地目录直接挂进容器。安全限制:
- 路径必须在白名单内
- 不能挂载系统目录(如
/etc、/var) - 支持只读模式
3. 卷的构建过程
graph TB
LP[LaunchPlan] --> VOL["volumes.rs<br/>卷布局模块"]
VOL --> V1["workspace_volume()<br/>工作区卷"]
VOL --> V2["session_state_volume()<br/>会话状态卷"]
VOL --> V3["package_volume()<br/>包文件卷"]
VOL --> V4["mount_grant_volumes()<br/>用户挂载卷"]
V1 --> WK["workload_worker.rs<br/>组装到 Deployment 定义"]
V2 --> WK
V3 --> WK
V4 --> WK
volumes.rs(卷布局模块)读取 LaunchPlan 中的路径信息,为每种卷生成对应的 K8s Volume 和 VolumeMount 定义,最终由 workload_worker.rs(SessionWorker 渲染模块)统一写入 Deployment 的 Pod 模板。
4. 安全上下文
除了卷挂载,每个容器还应用了严格的安全策略:
| 安全措施 | 说明 |
|---|---|
runAsNonRoot: true | 禁止以 root 身份运行 |
allowPrivilegeEscalation: false | 禁止权限提升 |
capabilities: drop ALL | 移除所有 Linux 特权能力 |
| seccomp RuntimeDefault | 使用系统默认的系统调用过滤策略 |
automountServiceAccountToken: false | 不自动挂载 K8s API 凭证 |
这意味着容器内的 agentcore 只能访问明确挂载进来的目录,无法访问宿主机的其他文件,也无法调用 K8s API。数据库访问也不会直接从容器发起,而是统一回到 Backend。
5. hostPath 的限制与未来方向
当前所有文件相关的卷都使用 hostPath 方式,这意味着:
| 约束 | 影响 |
|---|---|
| Pod 调度限于本机 | 本地部署模式下无影响;远程多节点部署时需要 nodeAffinity 固定 |
| 无法跨机器共享 | 本地单节点不受影响;远程多节点需要引入 NFS 或 CSI |
| 不提供自动备份 | 需要自行实现备份策略 |
代码中已通过 VolumeBackend 枚举预留了扩展点,未来可以切换到 PersistentVolumeClaim(持久卷声明)等方案。
下一步
了解了挂载机制后,请继续阅读 外部文件访问 了解如何让容器访问用户本地的大文件和目录。