# 容器化

> 介绍以容器、微虚拟机或沙箱隔离运行 pi 的四种模式与配置要点。

---

LLMS 索引： [llms.txt](/llms.txt)

---

Pi 默认以全部权限运行，但在某些情况下，你会希望更好地控制 Pi 可以写入哪些目录、拥有哪些访问权限。

总体上有两种选择：
1. 将整个 `pi` 进程放在隔离环境中运行，或者
2. 在宿主机上运行 `pi`，把工具执行路由到隔离环境中。

## 选择模式 {#choose-a-pattern}

| 模式 | 隔离内容 | 适用场景 | 备注 |
| --- | --- | --- | --- |
| Gondolin 扩展 | 内置工具和 `!` 命令 | 本地微虚拟机隔离，同时把认证保留在宿主机上 | 见 [`examples/extensions/gondolin/`](https://github.com/earendil-works/pi/tree/main/packages/coding-agent/examples/extensions/gondolin/)。 |
| 普通 Docker | 整个 `pi` 进程在本地容器中 | 简单的本地隔离 | 提供商 API 密钥会进入容器。 |
| OpenShell | 整个 `pi` 进程在受策略控制的沙箱中 | 本地或远程的托管沙箱 | 需要 OpenShell 网关 |
| Docker Sandboxes | 整个 `pi` 进程在托管沙箱中 | 本地隔离，提供商密钥保留在宿主机上 | 需要 Docker Sandboxes（`sbx`）。 |

扩展在 `pi` 进程所在的位置运行。如果你在宿主机上运行 pi 并使用工具路由扩展，其他自定义扩展工具仍会在宿主机上运行，除非它们也把自己的操作委托出去。

## Gondolin {#gondolin}

[Gondolin](https://github.com/earendil-works/gondolin) 是一个本地 Linux 微虚拟机。
当你想让 `pi` 留在宿主机上、而所有内置工具都路由到虚拟机内执行时，可以使用[示例扩展](https://github.com/earendil-works/pi/tree/main/packages/coding-agent/examples/extensions/gondolin)。

安装：

```bash
cp -R packages/coding-agent/examples/extensions/gondolin ~/.pi/agent/extensions/gondolin
cd ~/.pi/agent/extensions/gondolin
npm install --ignore-scripts
```

在要挂载的项目中运行：

```bash
cd /path/to/project
pi -e ~/.pi/agent/extensions/gondolin
```

该扩展会把宿主机当前工作目录挂载到虚拟机内的 `/workspace`，并接管 `read`、`write`、`edit`、`bash`、`grep`、`find` 和 `ls`。
用户的 `!` 命令同样会被路由到虚拟机中。
`/workspace` 下的文件改动会直接写回宿主机。

环境要求：`@earendil-works/gondolin` 需要 Node.js >= 23.6.0，另外需要 QEMU（须通过你的包管理器安装）。

## 普通 Docker {#plain-docker}

当你想要最简单的本地容器边界时，可以把整个 `pi` 进程放进 Docker 中运行。

`Dockerfile.pi`：

```dockerfile
FROM node:24-bookworm-slim

RUN apt-get update \
  && apt-get install -y --no-install-recommends bash ca-certificates git ripgrep \
  && rm -rf /var/lib/apt/lists/*
RUN npm install -g --ignore-scripts @earendil-works/pi-coding-agent

WORKDIR /workspace
ENTRYPOINT ["pi"]
```

构建并运行：

```bash
docker build -t pi-sandbox -f Dockerfile.pi .

docker run --rm -it \
  -e ANTHROPIC_API_KEY \
  -v "$PWD:/workspace" \
  -v pi-agent-home:/root/.pi/agent \
  pi-sandbox
```

`-v "$PWD:/workspace"` 会把你当前所在的目录挂载到容器内的 /workspace，这样 Docker 内部对 `/workspace` 的读写会直接影响宿主机文件，效果与 Gondolin 示例相同。

如果希望容器内有独立的设置和会话，可以为 `/root/.pi/agent` 使用命名卷。挂载宿主机的 `~/.pi/agent` 会把宿主机的认证和会话文件暴露给容器。

## OpenShell {#openshell}

当你需要带有文件系统、进程、网络、凭据和推理控制的策略型沙箱时，可以使用 [NVIDIA OpenShell](https://docs.nvidia.com/openshell/about/overview)。
OpenShell 可以通过由 Docker、Podman 或虚拟机运行时支撑的本地网关运行沙箱，也可以通过远程 Kubernetes 网关运行。

每个沙箱都需要一个活跃的网关。
在创建沙箱之前，先注册并选择一个：

```bash
openshell gateway add <gateway-url> --name <name>
openshell gateway select <name>
```

在 OpenShell 沙箱内启动 `pi`：

```bash
openshell sandbox create --name pi-sandbox --from pi -- pi
```

在这种模式下，整个 `pi` 进程都在沙箱内运行。
内置工具、`!` 命令和扩展工具都在 OpenShell 边界内执行。

如果网关是远程的，项目文件不会从宿主机绑定挂载，也就是说沙箱内的写入不会反映到你的机器上。
请在沙箱内克隆仓库，或使用 OpenShell 的文件传输命令：

```bash
openshell sandbox upload pi-sandbox ./repo /workspace
openshell sandbox download pi-sandbox /workspace/repo ./repo-out
```

OpenShell 提供商可以让原始的模型 API 密钥留在沙箱之外。
配置推理路由之后，沙箱内的代码可以调用 `https://inference.local`，由网关在上游注入配置好的提供商凭据。
如果你希望模型流量走这条路线，可以将 Pi 配置为使用对应的 OpenAI 兼容或 Anthropic 兼容端点。

## Docker Sandboxes {#docker-sandboxes}

[Docker Sandboxes](https://docs.docker.com/ai/sandboxes/) 是 Docker 提供的托管沙箱运行时，会把整个 `pi` 进程放进沙箱中运行。
它是[没有内置沙箱](/book/pi/security/#no-built-in-sandbox)所指的那种容器边界之一。

与上面的普通 Docker 模式不同，提供商凭据不会传入容器。
沙箱收到的是一个哨兵值（sentinel），由 `sbx` 代理在出口处向 `api.anthropic.com` 替换为真实凭据。
凭据在创建时接线，因此在创建沙箱之前，要先把凭据存放在宿主机上。

对于 Claude Pro/Max 订阅，先在一台装有 Claude Code 的机器上运行 `claude setup-token`，然后把结果存储到宿主机上。
如果已经绑定了 `anthropic` secret，请先移除它：否则代理会在 Bearer token 之外再附加一个 `x-api-key` 头，Anthropic 会拒绝该请求。
`sbx secret set-custom` 从 stdin 读取 token，因此不会留在 shell 历史记录中。

```bash
sbx secret rm anthropic

sbx secret set-custom \
  --host api.anthropic.com \
  --env ANTHROPIC_OAUTH_TOKEN \
  --placeholder 'sk-ant-oat01-{rand}'
```

沙箱拿到的是 OAuth 形式的占位符而非真实 token，由代理在出口到该主机时替换；`ANTHROPIC_OAUTH_TOKEN` 是 pi 本身就会读取并优先于 API 密钥使用的变量，因此无需额外的 pi 配置。

如果是 API 密钥，则改用 `sbx secret set anthropic` 存储。该套件（kit）以相同的方式接线：作为一个由代理在出口处替换的哨兵值。

凭据存放好之后，在要挂载的项目中启动 `pi`：

```bash
sbx run --kit "docker.io/sbx/pi-kit:latest" pi
```

该套件已把 `pi` 预置到镜像中，因此沙箱启动时无需安装任何东西，当前目录就是沙箱工作区。

不要在沙箱内认证：在里面运行 `/login` 会把真实 token 写入容器，破坏代理模型。

脚本化使用的方式相同：

```bash
sbx exec <sandbox-name> -- pi -p "list the failing tests"
```

完整的凭据矩阵、故障排除和版本固定，请参阅[套件文档](https://github.com/docker/sbx-kits-contrib/tree/main/pi)。

---

反链：

- [安全](/book/pi/security/)
