Mastra Apple Container 沙箱:在 macOS 上以 OCI Linux 容器运行 Agent 工作区
【免费下载链接】mastraMastra is the modern TypeScript framework for AI-powered applications and agents.项目地址: https://gitcode.com/GitHub_Trending/ma/mastra
@mastra/apple-container是 Mastra 工作区体系中的一个本地沙箱 Provider,它通过 Apple 官方的containerCLI,在 macOS 上直接启动常驻的 OCI Linux 容器,并将 MastraWorkspaceSandbox的命令执行契约映射为container exec调用。本文基于仓库中该包的 README 与源码实现,完整讲解其安装方式、配置参数、生命周期与命令执行原理,并给出可直接运行的代码示例,帮助你为 Agent 搭建本地、隔离、可复用的 Linux 运行环境。
背景:为什么需要 Apple Container 沙箱
Mastra 的工作区(Workspace)为 Agent 提供"在隔离环境里执行命令、读写文件、运行进程"的能力,而真正干活的是各类沙箱 Provider。它们各自把 Mastra 统一的沙箱接口翻译成不同厂商的能力:云端的 E2B、Modal、Vercel 微 VM,自托管的 Docker,以及本文的主角——本地运行的 Apple Container。
Apple 开源的containerCLI 是一个原生的 OCI 容器运行时,可以在 Apple Silicon Mac 上直接运行 Linux 容器(无需 Docker Desktop)。@mastra/apple-container包正是围绕它封装出的 Provider:
- 通过
container run启动一个长生命周期的 Linux 容器(默认镜像node:22-slim,默认命令sleep infinity保证容器不退出); - 通过
container exec在容器内逐条执行工作区命令; - 与 Mastra
Workspace、MastraSandbox抽象完全兼容,接入成本极低。
从 package.json 可以看到该包要求 Node.js>=22.13.0,并以@mastra/core >=1.12.0-0 <2.0.0-0作为 peer 依赖。
安装
在项目目录下安装包:
npm install @mastra/apple-container前提条件(来自 集成测试 的探测逻辑):宿主机需要安装 ApplecontainerCLI,且container --version能正常返回。文章后续会说明如何用集成测试验证这一前提。
快速开始
README 给出了最精简的接入示例:构造沙箱、挂载宿主机目录、初始化工作区、执行命令、最后销毁。
import { Workspace } from '@mastra/core/workspace'; import { AppleContainerSandbox } from '@mastra/apple-container'; const sandbox = new AppleContainerSandbox({ image: 'node:22-slim', volumes: { '/Users/me/project': '/workspace', }, workingDir: '/workspace', }); const workspace = new Workspace({ sandbox }); await workspace.init(); const result = await workspace.sandbox?.executeCommand?.('node', ['--version']); console.log(result?.stdout); await workspace.destroy();示例中几个要点:
volumes把宿主机目录/Users/me/project以 bind mount 方式挂载到容器内/workspace,让 Agent 能读写宿主机代码,同时进程仍运行在隔离的 Linux 环境里;workingDir指定容器内默认工作目录(未设置时默认为/workspace);Workspace.init()负责拉起沙箱;workspace.destroy()在结束时销毁(默认删除容器);- 返回的
result包含success、exitCode、stdout、stderr、executionTimeMs等字段。
在仓库中,该 Provider 的入口 src/index.ts 导出了AppleContainerSandbox、DefaultAppleContainerCommandRunner、appleContainerSandboxProvider以及一系列类型定义。
完整配置参数
Provider 在 provider.ts 中暴露了一份严格的configSchema(additionalProperties: false,即不接受未声明字段),并且 单元测试 逐一断言了 schema 字段的精确集合。以下参数同时是AppleContainerSandboxOptions的成员(定义见 sandbox/index.ts):
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
id | string | 自动生成 | 沙箱稳定标识,用于"重连"到同一个容器 |
name | string | 同id | 传给container run --name的容器名 |
image | string | node:22-slim | 使用的 OCI 镜像 |
command | string[] | ['sleep','infinity'] | 容器 init 命令,必须保持容器存活以便 exec 执行命令 |
env | object | {} | 注入容器及每次 exec 的环境变量 |
volumes | object | {} | 宿主机到容器的 bind mount(宿主机路径 -> 容器路径) |
mounts | string[] | [] | 透传的container run --mount原始规格 |
network | string | — | Apple container 网络挂载规格 |
publishedPorts | string[] | [] | 端口发布规格(--publish) |
publishedSockets | string[] | [] | 套接字发布规格(--publish-socket) |
cpus | number | string | — | 分配的 CPU 数量 |
memory | string | — | 内存配额,例如1G |
platform | string | — | OCI 平台,例如linux/arm64 |
arch | string | — | 多架构镜像时选择架构 |
os | string | — | 多平台镜像时选择操作系统 |
rosetta | boolean | false | 是否启用容器内 Rosetta |
readonlyRootfs | boolean | false | 容器根文件系统只读挂载(--read-only) |
ssh | boolean | false | 转发宿主机 SSH agent 套接字 |
init | boolean | true | 启用 Apple 的 init 进程 |
virtualization | boolean | false | 向容器暴露虚拟化能力 |
capAdd | string[] | [] | 追加的 Linux capabilities |
capDrop | string[] | [] | 移除的 Linux capabilities |
tmpfs | string[] | [] | tmpfs 目标路径(仅接受容器路径,如/tmp) |
dns | string[] | [] | DNS nameserver IP |
dnsSearch | string[] | [] | DNS 搜索域 |
noDns | boolean | false | 不在容器内配置 DNS |
labels | object | {} | 容器标签(Mastra 标签始终追加) |
workingDir | string | /workspace | 容器内工作目录(已废弃,推荐使用workingDirectory) |
timeout | number | 300000 | 默认命令超时(毫秒) |
deleteOnDestroy | boolean | true | 销毁时是否删除容器 |
containerBinary | string | container | Apple container CLI 的可执行文件路径/名称(不进 schema) |
runner | object | 默认 runner | 自定义命令执行器,主要用于测试(不进 schema) |
两个值得注意的细节:
workingDir与workingDirectory:从 CHANGELOG.md 可知,自 0.5.0 起@mastra/core为所有沙箱 Provider 统一引入了workingDirectory选项,workingDir降级为兼容别名。当两者同时设置时workingDirectory生效;两者都未设置时才回落到 Provider 默认值/workspace。这一点在 单元测试 中有专门用例验证。tmpfs校验:Apple container 的--tmpfs只接受容器内路径,因此源码在构造时会调用validateTmpfsPaths校验,Docker 风格的/tmp:rw,size=64m规格会被直接拒绝并抛出错误。
底层原理:容器创建与命令执行
生命周期:start / stop / destroy
沙箱继承自核心的MastraSandbox(核心实现见 packages/core 的 workspace 模块),并实现了三种状态迁移:
start():先container inspect检查同名容器是否存在——- 不存在:用
_buildRunArgs组装container run -d --name <name> --workdir <dir>参数(包括全部 volumes、mounts、labels、端口、capability、资源限制等),随后轮询inspect并反复执行container exec ... true直到容器可执行命令(就绪超时 10 秒),创建失败且deleteOnDestroy开启时会主动delete --force清理现场; - 已存在且运行中:直接复用,不重启;
- 已存在但停止:执行
container start重启,再等待就绪。
- 不存在:用
stop():inspect确认存在且运行后执行container stop。destroy():默认执行container delete --force删除容器;若deleteOnDestroy: false,则只stop保留容器以便下次复用。
命令执行:exec + shell
executeCommand(command, args, options)的内部流程(sandbox/index.ts):
- 先
ensureRunning()确保容器在运行; - 把命令与参数拼装为 shell 命令(含参数引用
shellQuote,防止命令注入,测试里有专门用例验证特殊字符被安全引用); - 组装 CLI 参数:
container exec [--env KEY]... --workdir <cwd> <container> sh -lc "<shellCommand>"; - 通过
AppleContainerCliProcess(继承自核心ProcessHandle)以子进程方式运行container,逐块解码 stdout/stderr,支持流式回调与输出保留上限。
单次命令执行支持以下选项(ExecuteCommandOptions):cwd(本次命令的工作目录,优先于实例级配置)、env(仅本次生效)、timeout(毫秒)、abortSignal(中止信号)、onStdout/onStderr(流式回调)、maxRetainedBytes(内存中保留的最新输出字节数,超出部分以stdoutDroppedBytes等字段报告)。
超时与强制清理机制
这是实现中最精巧的部分:当设置了命令超时,源码不会简单地在宿主机侧杀掉进程,而是生成一段内层 shell 脚本——用timeout命令包裹命令,并设置trap在超时时向子进程发送 TERM 后以退出码 124 退出;同时把真实退出码写入临时文件,避免"命令自己退出 124"与"超时被杀"混淆。判定超时的规则是:退出码为 124 且 stderr 中含有特殊标记__MASTRA_APPLE_CONTAINER_TIMEOUT__,否则即使退出码是 124 也不算超时(这一正反用例均被单元测试和集成测试覆盖)。
此外,CLI 子进程层面还有一重保护:命令总超时 = 命令超时 + 10 秒宽限期,超时后先SIGTERM,1 秒内未退出再SIGKILL。AbortSignal也能随时终止命令。
安全与所有权机制
为了防止误操作他人容器,源码实现了双重保护(_assertMastraOwned与_assertCompatibleConfig):
- 所有权标签:每次创建容器都会强制打上
mastra.sandbox=true、mastra.sandbox.id=<id>、mastra.sandbox.config-hash=<hash>三个标签。重连时若容器缺少与当前 sandbox id 匹配的 Mastra 标签,会直接拒绝管理并抛出SandboxExecutionError; - 配置哈希校验:对镜像、命令、env、volumes、mounts、网络、资源等不可变配置做稳定序列化后取 SHA-256 前 16 位作为
config-hash。重连时若哈希不一致(说明容器是用另一套参数创建的),同样拒绝接管。
对应测试场景包括:无标签容器的拒绝、配置不匹配的拒绝、以及"新建容器未就绪即退出时自动清理"。
模板克隆:一个沙箱配置派生一组沙箱
clone()方法允许以某个已配置的沙箱为模板,派生出一批独立的兄弟沙箱(典型场景:按项目各建一个沙箱)。克隆会继承模板的全部配置(镜像、资源、网络、安全项、标签),仅支持按实例覆盖id与env,且克隆过程不做任何 I/O——真正的容器创建在各自start()时才发生。需要说明的是,idleTimeoutMinutes在此被忽略(Apple container 没有 Provider 侧的空闲回收机制),name也会被丢弃以便每个克隆独立命名。
const template = new AppleContainerSandbox({ image: 'ubuntu:24.04', workingDir: '/workspace' }); const projectSandbox = template.clone({ id: 'mc-project-1', env: { GITHUB_TOKEN: token }, }); await projectSandbox.start();如何验证:单元测试与集成测试
该包在 src/sandbox 下提供了两层测试:
- 单元测试(index.test.ts):通过注入 Mock
AppleContainerCommandRunner,精确断言container run参数构建顺序、生命周期调用、超时标记、环境变量合并、工作目录优先级、clone 行为等,无需真实容器环境,pnpm test:unit即可运行; - 集成测试(index.integration.test.ts):需要真实的
containerCLI。设置环境变量后运行:
MASTRA_APPLE_CONTAINER_INTEGRATION=1 pnpm test:integration集成测试会真实地启动容器(默认镜像alpine:3.20)、执行命令、验证"停止后重启同一容器""重连已运行的容器""超时命令确实被清理""deleteOnDestroy 语义"等端到端行为,是最可靠的接入验证方式。
适用场景与限制
从源码结构看,该 Provider 最适合在 macOS 本机为 Agent 提供低成本、免 Docker Desktop 的 Linux 隔离环境,例如:让 Agent 编译、运行、测试 Node 项目(node:22-slim默认镜像),或通过 bind mount 把宿主机仓库映射进容器做受控操作。
使用中需注意:
- 仅适用于安装了 Apple
containerCLI 的环境,且容器为 Linux(OCI); - 容器内命令不支持 stdin 写入(
sendStdin/closeStdin会抛出不支持错误); tmpfs、env变量名等有严格校验(环境变量名必须符合[A-Za-z_][A-Za-z0-9_]*);- 工作目录等路径需使用绝对路径,
~与$HOME不会被展开; - 版本演进请参考包的 CHANGELOG.md。
更完整的 Mastra Workspace 概念与沙箱生态可继续阅读 workspaces 目录 下的其他 Provider 实现,结合对比加深理解。
【免费下载链接】mastraMastra is the modern TypeScript framework for AI-powered applications and agents.项目地址: https://gitcode.com/GitHub_Trending/ma/mastra
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考