> ## Documentation Index
> Fetch the complete documentation index at: https://docs.flashduty.com/llms.txt
> Use this file to discover all available pages before exploring further.

# 运行环境

> 运行环境决定 AI SRE Agent 在哪里执行命令、读写文件、运行 Skill 与连接 MCP。本文先说明 Sandbox 与 BYOC Runner 的关系，再分别介绍云端 Sandbox、自托管 Runner、权限配置、会话选择与常见排查。

<Info>
  **内测功能**：AI SRE 目前处于内测阶段，专业版及以上用户可申请免费试用。请通过 [AI SRE 内测申请表](https://c9xudyniiq.feishu.cn/share/base/form/shrcn0ngCfdoygiaHnAT80BfZiH) 提交申请，审核通过后将开通白名单；内测期间功能与界面可能调整。
</Info>

## 概述

***

**运行环境**（Environment）是 AI SRE Agent 实际执行动作的地方。Agent 的每一次工具调用，包括执行命令、读写文件、运行 Skill、连接 MCP 服务，都会落在一个运行环境里。

AI SRE 提供两类运行环境：

<CardGroup cols={2}>
  <Card title="云端 Sandbox" icon="cloud" href="/zh/ai-sre/sandbox">
    Flashduty 托管的临时容器，零安装、开箱即用。没有当前成员可用的在线 BYOC Runner 时，会话会自动回退到云端 Sandbox。
  </Card>

  <Card title="BYOC Runner" icon="server" href="#byoc-runner">
    部署在您自己机器上的常驻进程。它通过 WebSocket 连接 AI SRE，让 Agent 在您的网络边界内执行任务。
  </Card>
</CardGroup>

默认选择逻辑是：**优先使用当前成员可用的在线 BYOC Runner；否则使用云端 Sandbox。** 可用 Runner 包括账户级 Runner，以及当前成员所属团队下的团队级 Runner。您也可以在会话输入框的环境选择器中固定使用云端 Sandbox，或固定使用某个具体 Runner。

<Note>
  控制台里的记录称为 **Environment**，跑在机器上的进程称为 **Runner**。一个 BYOC Environment 对应一个 Runner 进程；云端 Sandbox 则由系统按会话管理。
</Note>

## 云端 Sandbox

***

云端 Sandbox 是 Flashduty 托管的临时执行容器。它适合快速上手、演示，以及不需要访问您内网的排查。您不需要安装任何进程，也不需要维护机器。

适合使用云端 Sandbox 的场景：

* 还没有部署 Runner，想先体验 AI SRE；
* 排查只需要访问 Flashduty 数据、可信公网服务或公开文档；
* 一次性、轻量任务，不值得准备常驻机器；
* 希望强制隔离在托管环境中执行，而不是使用账户下已有 Runner。

<Warning>
  云端 Sandbox 不能访问您的 VPC、专线、内网数据库、内网 API 或跳板机。需要直连这些资源时，请使用 [BYOC Runner](#byoc-runner)，把执行位置放到能访问目标资源的机器上。
</Warning>

更多生命周期、出网边界与会话选择细节，见 [Sandbox](/zh/ai-sre/sandbox)。

## BYOC Runner

***

BYOC（Bring Your Own Compute）Runner 是您部署在自己机器上的 `flashduty-runner` 进程。它与 AI SRE 保持常驻 WebSocket 连接，收到任务后在本机执行命令、读写文件、运行 Skill，并按需连接本机可达的 MCP 服务。

BYOC Runner 的价值来自执行位置：

<AccordionGroup>
  <Accordion title="触达真实环境" icon="server">
    Runner 跑在您的机器上，因此能访问这台机器本身可达的 VPC、内网、专线、Kubernetes 集群、云厂商 CLI、数据库或跳板机。
  </Accordion>

  <Accordion title="数据驻留" icon="key">
    命令输出、日志、临时文件和工具执行结果优先留在您的网络边界内。Agent 能读取和分析这些信息，但执行面仍由您机器的系统账号、文件权限和网络策略约束。
  </Accordion>

  <Accordion title="本地权限可控" icon="shield-check">
    您可以决定 Runner 运行在哪个 OS 用户下、能访问哪些目录、拥有哪些 CLI 凭据，以及是否加载本页的[权限配置](#权限配置)收敛命令范围。
  </Accordion>
</AccordionGroup>

<Tip>
  BYOC Runner 的出网策略由您的机器和防火墙决定。云端 Sandbox 的“按域名配置出网允许列表”不适用于 BYOC，因此自托管 Environment 表单里不提供网络访问配置。
</Tip>

### 创建并连接

在 AI SRE 左侧菜单进入 **Environments**，创建一个自托管 Environment。创建时需要填写：

| 字段 | 是否必填 | 说明                                                                                 |
| -- | ---- | ---------------------------------------------------------------------------------- |
| 名称 | 否    | 在账户范围内唯一，最长 128 字符。留空时，Runner 首次连接并发送心跳后，会自动用机器主机名命名；若主机名重复，会追加 Environment ID 后缀。 |
| 范围 | 是    | 账户范围对整个账户可见；团队范围仅对该团队成员可见和可编辑。见[作用域](#作用域)。                                        |
| 标签 | 否    | 用于任务路由的标签，逗号分隔，例如 `linux, docker, gpu`。                                            |

创建成功后会弹出**接入指引**，包含这条 Environment 的 Token、安装命令、升级命令和卸载命令。列表行里的钥匙按钮或 pending 状态的“查看接入指引”也会打开同一个弹窗。

### 安装方式

接入指引里的命令会自动填入真实 `TOKEN` 与 `URL`。以下示例只展示占位符，请以控制台生成的命令为准。

<Tabs>
  <Tab title="Linux (systemd)">
    在目标机器上以 root / sudo 执行：

    ```bash theme={null}
    curl -fsSL https://static.flashcat.cloud/flashduty-runner/install.sh | \
      sudo TOKEN=<your-token> \
      URL=<connect-url> \
      bash
    ```

    脚本会安装二进制、创建 systemd 服务，并写入 `/etc/flashduty-runner/env`。同一条命令可用于首次安装和升级；如果已是最新版本，会自动跳过。
  </Tab>

  <Tab title="Docker">
    在已安装 Docker 的机器上启动容器：

    ```bash theme={null}
    docker run -d \
      --name flashduty-runner \
      -e FLASHDUTY_RUNNER_TOKEN=<your-token> \
      -e FLASHDUTY_RUNNER_URL=<connect-url> \
      -v /var/flashduty/workspace:/workspace \
      registry.flashcat.cloud/public/flashduty-runner:latest
    ```

    Docker 权限取决于容器挂载。需要 kubeconfig、云厂商 CLI 凭据或 Docker socket 时，在镜像名前追加对应的 `-v` / `-e` 参数。
  </Tab>

  <Tab title="手动 / macOS">
    先安装二进制，再手动启动进程：

    ```bash theme={null}
    curl -fsSL https://static.flashcat.cloud/flashduty-runner/install.sh | sudo bash -s -- --no-service

    FLASHDUTY_RUNNER_TOKEN=<your-token> \
    FLASHDUTY_RUNNER_URL=<connect-url> \
    flashduty-runner run
    ```

    手动模式不会注册 systemd 服务，适合 macOS、临时排查或您已有自己的进程管理方式。
  </Tab>
</Tabs>

<Note>
  `connect-url` 与 `install_script_url` 都由后端下发，前端不会硬编码。私有化或离线部署可以把安装脚本分发源替换为内部镜像，但镜像需要同时提供 `install.sh`、`releases/latest` 与 `releases/download/<version>/...` release assets。
</Note>

### Linux 服务用户

Linux (systemd) 安装默认使用安装脚本自动创建的 `flashduty` 用户。该用户没有 sudo 权限，systemd unit 会启用 `NoNewPrivileges=true`、`ProtectSystem=strict`、`PrivateTmp=true` 等限制，并只把 Runner 的状态目录设为可写。

如果 Runner 需要读取某个已有用户的 kubeconfig、云厂商 CLI 凭据或 Docker 权限组，可以在接入指引里填写“Linux 服务用户”，或手动在命令中增加 `RUN_AS`：

```bash theme={null}
curl -fsSL https://static.flashcat.cloud/flashduty-runner/install.sh | \
  sudo TOKEN=<your-token> \
  URL=<connect-url> \
  RUN_AS=<existing-user> \
  bash
```

`RUN_AS` 等价于安装脚本的 `--run-as <user>` 参数，要求该系统用户已经存在。这样做会让 systemd 服务以该用户运行，也会相应放宽该用户主目录的保护策略。

<Warning>
  只有在 Runner 确实需要读取该用户的本地凭据或加入该用户所在权限组时，才指定 `RUN_AS`。否则优先使用默认 `flashduty` 用户。
</Warning>

### Token、升级和卸载

Token 是 Runner 连接 AI SRE 的唯一凭据。它会写入安装命令或环境变量中，请只在安装、升级或排查连接时查看，不要发给无关人员。若怀疑泄露，请删除对应 Environment 后重新创建。

Runner 启动后会持续发送心跳。列表状态含义如下：

| 状态           | 含义                              |
| ------------ | ------------------------------- |
| 等待中（pending） | Environment 已创建，但 Runner 从未连接过。 |
| 在线（online）   | Runner 当前已连接，心跳正常，可承接任务。        |
| 离线（offline）  | Runner 曾连接过，但当前心跳已断。            |

Runner 版本由服务端在心跳中比对。发现新版本时，Runner 会收到升级通知并自行下载、校验、替换。手动重跑安装命令也可升级。卸载命令也在接入指引里：`--uninstall` 保留配置卸载，`--purge` 清除配置与数据。

## 权限配置

***

Runner 默认使用允许全部命令的规则：

```yaml theme={null}
permission:
  "*": "allow"
```

当您希望把 Runner 的命令执行范围收敛到允许列表或拒绝列表时，可以在 Runner 所在机器上创建一个 YAML 文件，并通过 `--permission-config` 或 `FLASHDUTY_RUNNER_PERMISSION_CONFIG` 指定它。权限配置是 Runner 本机文件，不在控制台表单里编辑。

Linux (systemd) 安装后，推荐在 `/etc/flashduty-runner/env` 中加入：

```bash theme={null}
FLASHDUTY_RUNNER_PERMISSION_CONFIG=/etc/flashduty-runner/permission.yaml
```

然后重启服务：

```bash theme={null}
sudo systemctl restart flashduty-runner
```

手动启动时也可以直接传参数：

```bash theme={null}
flashduty-runner run \
  --token <your-token> \
  --permission-config /etc/flashduty-runner/permission.yaml
```

一个常见的只读排查配置如下：

```yaml theme={null}
permission:
  "*": "deny"
  "kubectl get *": "allow"
  "kubectl describe *": "allow"
  "kubectl logs *": "allow"
  "ls": "allow"
  "ls *": "allow"
  "cat *": "allow"
  "head *": "allow"
  "tail *": "allow"
  "grep *": "allow"
  "pwd": "allow"
  "whoami": "allow"
  "date": "allow"
```

规则语义：

* `permission` 是顶层 key，下面是 `glob pattern: allow|deny` 的扁平映射；
* 未指定配置文件时，Runner 允许全部命令；
* 一旦指定配置文件，文件缺失、YAML 格式错误或 `permission` 为空都会让 Runner 拒绝启动，避免因配置错误回退到允许全部；
* 命令按规范化后的 shell 片段匹配，空格差异不会影响匹配；
* 规则按“`*` 之前的字面前缀更长者更具体”排序，更具体的规则先匹配，`*` 总是最后兜底；
* Runner 会检查管道、命令替换、进程替换、算术展开里的命令；
* 写重定向会按形如 `> /path`、`>> /path`、`&> /path` 的合成命令检查；读重定向本身不会额外拦截。

<Tip>
  权限配置会在 Runner 启动时加载。修改 YAML 后需要重启 Runner，新的规则才会生效。
</Tip>

## 权限配置

***

Runner 默认允许执行任意命令——与直接在自己的 shell 里运行 AI 模型一样，信任模型的判断。如果需要限制 Runner 可执行的命令范围，可以通过 `--permission-config` 参数或 `FLASHDUTY_RUNNER_PERMISSION_CONFIG` 环境变量为 Runner 指定一个 YAML 规则文件：

```bash theme={null}
flashduty-runner run --token <your-token> --permission-config /etc/flashduty-runner/permission.yaml

# 或通过环境变量
export FLASHDUTY_RUNNER_PERMISSION_CONFIG=/etc/flashduty-runner/permission.yaml
```

规则文件顶层键是 `permission`，值是 **glob 模式 → `allow`/`deny`** 的映射：

```yaml theme={null}
permission:
  "*": "deny"
  "kubectl get *": "allow"
  "kubectl describe *": "allow"
  "cat *": "allow"
```

* 规则会应用到命令的每一处出现——包括管道（`cmd1 | cmd2`）、`$(...)`/反引号命令替换、进程替换，以及写入重定向目标（因此 `echo x > /etc/passwd` 会像执行命令一样被拦截）。
* **最具体的规则优先**：第一个 `*` 之前字面前缀最长的模式最先被尝试匹配，兜底规则 `"*"` 始终最后尝试，第一个匹配的规则生效。
* 该文件仅在 Runner **启动时加载一次**——修改规则后需要重启 Runner 才能生效，不支持热重载。
* 若指定了该 flag/环境变量，但文件缺失、格式错误，或未在 `permission` 键下定义任何规则，Runner 会**拒绝启动**（fail closed），而不是静默放行所有命令：显式配置权限即代表明确希望限制执行范围，配置写错时应当报错而非留下安全隐患。
* 不设置该 flag/环境变量是默认行为，等价于允许所有命令。

<AccordionGroup>
  <Accordion title="严格模式（推荐用于共享环境）" icon="lock">
    默认拒绝所有命令，仅显式放行需要的命令：

    ```yaml theme={null}
    permission:
      "*": "deny"
      "kubectl get *": "allow"
      "kubectl describe *": "allow"
      "kubectl logs *": "allow"
      "cat *": "allow"
      "ls *": "allow"
    ```
  </Accordion>

  <Accordion title="信任模式（用于专属/隔离环境）" icon="unlock">
    等价于完全不设置 `--permission-config`，但允许显式声明例外：

    ```yaml theme={null}
    permission:
      "*": "allow"                 # 信任 AI 模型
      "rm -rf /": "deny"           # 如需要可阻止灾难性命令
    ```

    适用于 Runner 运行在隔离 VM/容器、影响范围有限，或更看重响应速度而非限制权限的场景。
  </Accordion>

  <Accordion title="只读模式（仅用于监控）" icon="eye">
    只放行只读命令，适合仅用于观测、不希望 Runner 修改任何状态的场景：

    ```yaml theme={null}
    permission:
      "*": "deny"
      "cat *": "allow"
      "head *": "allow"
      "tail *": "allow"
      "ls *": "allow"
      "grep *": "allow"
      "ps *": "allow"
      "df *": "allow"
      "free *": "allow"
    ```
  </Accordion>
</AccordionGroup>

<Note>
  命令权限当前仅支持通过配置文件设置，控制台暂无对应的可视化配置界面。
</Note>

## 在会话中选择环境

***

聊天输入框底部的环境选择器决定新会话在哪里执行：

| 选项                  | 含义                                             |
| ------------------- | ---------------------------------------------- |
| **自动**              | 新会话默认值。优先使用当前成员可用的在线 Runner，否则回退到云端 Sandbox。   |
| **云端 Sandbox · 默认** | 强制使用系统托管的云端 Sandbox，忽略自托管 Runner。              |
| **自托管 Environment** | 列出当前成员可使用的 Runner。离线、从未连接或团队权限不匹配的 Runner 不可选。 |

<Warning>
  环境选择对一条会话是一次性锁定的：会话首次发送消息时确定的运行环境会被记录，后续轮次始终沿用，不会因为您之后切换选择器而改变。要换环境，请新建会话。
</Warning>

历史会话打开时，选择器会以只读形式展示这条会话当初锁定的环境及其当前状态。如果绑定的 Runner 已离线或被删除，该会话不能继续发送消息；请先恢复 Runner，或新建会话改用云端 Sandbox。

## 作用域

***

每个 BYOC Environment 都有账户级与团队级两档作用域：

| 作用域 | 可见范围                    |
| --- | ----------------------- |
| 账户级 | 整个账户内所有成员可见、可选择并可用于运行。  |
| 团队级 | 仅该团队成员可见、可编辑、可选择并可用于运行。 |

编辑权限遵循统一规则：

1. 账户所有者或账户管理员可编辑任意 Environment；
2. 团队成员可编辑本团队的团队级 Environment；
3. 不存在“创建者额外权限”，不是创建者也可以按上述规则编辑。

<Note>
  账户仍是运行时安全边界，但团队作用域也会参与 Runner 选择：系统自动选择 Runner 或按 ID 固定 Runner 时，只会使用账户级 Runner，或当前成员所属团队下的团队级 Runner。这样可以避免成员把会话落到自己无权使用的团队 Runner 上。
</Note>

## 故障排查

***

排查 Runner 问题时，先看 Environments 列表的**状态**与**最后心跳**。

<AccordionGroup>
  <Accordion title="Runner 显示离线" icon="bug">
    离线说明 Runner 曾连接过，但 AI SRE 在约 90 秒内没有收到心跳。请检查 systemd 服务或进程是否在运行、机器是否休眠或断网、到 AI SRE 的出网是否被防火墙阻断。恢复进程和网络后，Runner 会自动重连。
  </Accordion>

  <Accordion title="Runner 一直等待首次连接" icon="wrench">
    等待中说明这条 Environment 从未成功连接过。请确认安装命令完整执行、Token 属于这条 Environment、`URL` 从目标机器可达。如果使用了权限配置，也要确认配置文件存在且 YAML 可解析。
  </Accordion>

  <Accordion title="会话提示连接超时或无响应" icon="server">
    如果会话固定到了某个离线 Runner，AI SRE 不会偷偷改派到其他环境。请先恢复该 Runner，或新建会话并选择“自动”或“云端 Sandbox”。如果 Runner 在线但任务失败，多半是 Runner 到目标资源这一段的网络或权限问题。
  </Accordion>
</AccordionGroup>

<Tip>
  最快的定位方法：**离线 / 等待中**看 Runner 到 AI SRE 的连接；**在线但执行失败**看 Runner 到目标资源的网络、凭据和权限。
</Tip>

## 相关页面

***

<CardGroup cols={2}>
  <Card title="Sandbox" icon="cloud" href="/zh/ai-sre/sandbox">
    了解云端 Sandbox 的生命周期、适用场景与出网边界。
  </Card>

  <Card title="控制台" icon="comments" href="/zh/ai-sre/sessions">
    在会话中查看绑定的运行环境、团队与 Agent 调用的资源。
  </Card>

  <Card title="MCP（外部工具）" icon="plug" href="/zh/ai-sre/mcp">
    MCP 连接在 Agent 运行时于所选环境内建立。
  </Card>

  <Card title="Skill" icon="bug" href="/zh/ai-sre/skills">
    Skill 在所选运行环境中执行。
  </Card>
</CardGroup>
