Mastra Apple Container 沙箱:在 macOS 上以 OCI Linux 容器运行 Agent 工作区
2026/9/15 11:43:21 网站建设 项目流程

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在容器内逐条执行工作区命令;
  • 与 MastraWorkspaceMastraSandbox抽象完全兼容,接入成本极低。

从 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包含successexitCodestdoutstderrexecutionTimeMs等字段。

在仓库中,该 Provider 的入口 src/index.ts 导出了AppleContainerSandboxDefaultAppleContainerCommandRunnerappleContainerSandboxProvider以及一系列类型定义。

完整配置参数

Provider 在 provider.ts 中暴露了一份严格的configSchemaadditionalProperties: false,即不接受未声明字段),并且 单元测试 逐一断言了 schema 字段的精确集合。以下参数同时是AppleContainerSandboxOptions的成员(定义见 sandbox/index.ts):

参数类型默认值说明
idstring自动生成沙箱稳定标识,用于"重连"到同一个容器
namestringid传给container run --name的容器名
imagestringnode:22-slim使用的 OCI 镜像
commandstring[]['sleep','infinity']容器 init 命令,必须保持容器存活以便 exec 执行命令
envobject{}注入容器及每次 exec 的环境变量
volumesobject{}宿主机到容器的 bind mount(宿主机路径 -> 容器路径)
mountsstring[][]透传的container run --mount原始规格
networkstringApple container 网络挂载规格
publishedPortsstring[][]端口发布规格(--publish
publishedSocketsstring[][]套接字发布规格(--publish-socket
cpusnumber | string分配的 CPU 数量
memorystring内存配额,例如1G
platformstringOCI 平台,例如linux/arm64
archstring多架构镜像时选择架构
osstring多平台镜像时选择操作系统
rosettabooleanfalse是否启用容器内 Rosetta
readonlyRootfsbooleanfalse容器根文件系统只读挂载(--read-only
sshbooleanfalse转发宿主机 SSH agent 套接字
initbooleantrue启用 Apple 的 init 进程
virtualizationbooleanfalse向容器暴露虚拟化能力
capAddstring[][]追加的 Linux capabilities
capDropstring[][]移除的 Linux capabilities
tmpfsstring[][]tmpfs 目标路径(仅接受容器路径,如/tmp
dnsstring[][]DNS nameserver IP
dnsSearchstring[][]DNS 搜索域
noDnsbooleanfalse不在容器内配置 DNS
labelsobject{}容器标签(Mastra 标签始终追加)
workingDirstring/workspace容器内工作目录(已废弃,推荐使用workingDirectory
timeoutnumber300000默认命令超时(毫秒)
deleteOnDestroybooleantrue销毁时是否删除容器
containerBinarystringcontainerApple container CLI 的可执行文件路径/名称(不进 schema)
runnerobject默认 runner自定义命令执行器,主要用于测试(不进 schema)

两个值得注意的细节:

  • workingDirworkingDirectory:从 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):

  1. ensureRunning()确保容器在运行;
  2. 把命令与参数拼装为 shell 命令(含参数引用shellQuote,防止命令注入,测试里有专门用例验证特殊字符被安全引用);
  3. 组装 CLI 参数:container exec [--env KEY]... --workdir <cwd> <container> sh -lc "<shellCommand>"
  4. 通过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 秒内未退出再SIGKILLAbortSignal也能随时终止命令。

安全与所有权机制

为了防止误操作他人容器,源码实现了双重保护(_assertMastraOwned_assertCompatibleConfig):

  • 所有权标签:每次创建容器都会强制打上mastra.sandbox=truemastra.sandbox.id=<id>mastra.sandbox.config-hash=<hash>三个标签。重连时若容器缺少与当前 sandbox id 匹配的 Mastra 标签,会直接拒绝管理并抛出SandboxExecutionError
  • 配置哈希校验:对镜像、命令、env、volumes、mounts、网络、资源等不可变配置做稳定序列化后取 SHA-256 前 16 位作为config-hash。重连时若哈希不一致(说明容器是用另一套参数创建的),同样拒绝接管。

对应测试场景包括:无标签容器的拒绝、配置不匹配的拒绝、以及"新建容器未就绪即退出时自动清理"。

模板克隆:一个沙箱配置派生一组沙箱

clone()方法允许以某个已配置的沙箱为模板,派生出一批独立的兄弟沙箱(典型场景:按项目各建一个沙箱)。克隆会继承模板的全部配置(镜像、资源、网络、安全项、标签),仅支持按实例覆盖idenv,且克隆过程不做任何 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):通过注入 MockAppleContainerCommandRunner,精确断言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 把宿主机仓库映射进容器做受控操作。

使用中需注意:

  • 仅适用于安装了 ApplecontainerCLI 的环境,且容器为 Linux(OCI);
  • 容器内命令不支持 stdin 写入(sendStdin/closeStdin会抛出不支持错误);
  • tmpfsenv变量名等有严格校验(环境变量名必须符合[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),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询