部署指南
Sakura AI 完整部署流程:Docker 镜像、源码部署、GitHub App、数据库、Setup Wizard 与 Host Updater 守护进程。
部署方式概览
| 方式 | 适用场景 | 是否需要源码 | WebUI 手动更新 | 说明 |
|---|---|---|---|---|
| 官方在线服务 | 快速体验 | 否 | 由平台管理 | https://ai.firefly520.top/ 注册即用 |
| Linux Docker 全量部署 | 生产自建(推荐) | 否 | 支持 | 拉起 Web + MySQL + Redis,安装 Host Updater,并启用 Agent OS 沙箱 |
| macOS / Windows Compose 部署 | 容器化自建 | 否 | 不支持 | 可检查新版本;不提供 Linux sandboxd,Agent shell/依赖执行会 fail-closed |
| Docker 仅 Web 镜像 | 已有 MySQL/Redis | 否 | 不支持 | 仅启动 Web 容器,连接外部存储 |
| 源码部署 / 开发 | 二次开发、自定义构建 | 是 | 不支持 | 克隆仓库本地运行 |
所有配置(GitHub App、AI 模型、数据库等)通过首次启动后的 Setup Wizard 在 Web 界面完成,无需手动编辑配置文件。
一、Docker 部署
1.1 全量部署(MySQL + Redis 一并拉起)
Linux(包含 Host Updater,推荐):
sudo install -d -o root -g root -m 0755 /opt/sakura-ai/docker
sudo curl --fail --location \
https://raw.githubusercontent.com/Sakura520222/Sakura-AI/main/docker/docker-compose.prod.yml \
--output /opt/sakura-ai/docker/docker-compose.prod.yml
sudo curl --fail --location \
https://raw.githubusercontent.com/Sakura520222/Sakura-AI/main/start.sh \
--output /opt/sakura-ai/start.sh
sudo chmod 0644 /opt/sakura-ai/docker/docker-compose.prod.yml
sudo chmod 0755 /opt/sakura-ai/start.sh
cd /opt/sakura-ai
sudo ./start.sh --prod推荐路径固定为 root 管理的 /opt/sakura-ai。启动脚本将 COMPOSE_PROJECT_NAME=sakura-ai 持久化到部署状态,并为所有 Compose 操作显式传入项目名。start.sh --prod 会先在 root-owned、权限为 0600 的 pending 状态副本中准备 .deploy/deployment.env;若 Web 初始值是移动的 :latest,脚本先从 GitHub 解析一个非 draft/prerelease 的具体稳定 Release,再拉取并固定该 Release 的 Web :vX.Y.Z@sha256:...,随后从同一 Release 的 agent-sandbox-manifest.json 固定 sandboxd/runner digest。只有完整解析验证以及 Web、sandboxd、runner 和 Compose 所需镜像的 pull/inspect 全部成功后,pending 副本才会原子替换权威 .deploy/deployment.env;任一步失败都会丢弃 pending 副本并保持旧状态,且在 Compose 启动前 fail-closed。脚本随后创建独立 GID 9473 和 /run/sakura-ai-sandbox,先启动并验证 sandboxd,再启动 Web/MySQL/Redis。随后脚本下载并启动 Host Updater(独立 GID 9472 和 /run/sakura-ai)。生产 daemon 启动前会验证 binary、start.sh、Compose、deployment.env 及其完整父目录链均由 root 控制且不可由 group/other 写入;任一身份、权限、协议、runtime、workspace 或 digest 不匹配都会 fail-closed。新版本检查会自动执行,但安装更新必须由超级管理员在 WebUI 版本管理器中手动确认。
Agent OS 沙箱(Linux)
Agent 的 shell、grep 和自动依赖安装不会在 Web 进程中直接执行。Web 通过只读 UDS /run/sakura-ai-sandbox/sandboxd.sock 向独立 sandboxd 提交严格版本化请求;sandboxd 为每条请求创建一次性 runner 容器,并固定应用以下策略:
--network none、只读 rootfs、65532:65532、--cap-drop ALL、no-new-privileges;- CPU、内存、PID、
nofile与 combined stdout/stderr 字节上限; - 创建 runner 前由 root-owned sandboxd 仅将当前任务 worktree handoff 给固定
65532:65532;无法完成 ownership 合同时拒绝执行,绝不使用0777; - 普通 linked worktree 的 task gitdir 以可写受控 mount 暴露,base common
.git只读暴露,并通过固定GIT_DIR/GIT_COMMON_DIR/GIT_WORK_TREE让 Git 不依赖 Web 容器的/app指针路径;不挂载相邻任务的可写 metadata; - 只精确挂载当前任务 worktree 到
/workspace,不挂载相邻任务、应用配置、两个 UDS 或 Docker socket; - 镜像、mount、network、runtime 和 Docker argv 全部由 sandboxd 固定,Backend/模型请求不能覆盖;
- timeout、取消、daemon shutdown 和异常路径都执行有界
kill/rm;重启只回收经 service、instance、request、workspace labels 证明属于当前实例的容器。
只有 sandboxd 专用容器挂载 /var/run/docker.sock。Web 与 runner 都不挂载该 socket。sandboxd 不是普通 Compose service,由 start.sh 独立管理:
sudo ./start.sh sandboxd status
sudo ./start.sh sandboxd restart
sudo ./start.sh sandboxd reinstall
sudo ./start.sh sandboxd stop生产 workspace 使用宿主 bind 目录(默认 /opt/sakura-ai/workplace),Web 内仍显示为 /app/workplace。SAKURA_SANDBOX_WORKSPACE_ROOT 是宿主路径身份,必须由 start.sh 计算和注入,不要手工改成容器路径。sandboxd 的稳定 instance ID、双镜像 digest、release version、固定 egress 网络和 workspace identity 保存在 .deploy/deployment.env;不要提交该文件。
Agent 网络访问由 WebUI 超级管理员配置 agent_team_network_policy 控制。offline 禁止 runner 出网,跳过自动依赖安装并拒绝显式出口请求。web_tools(默认)允许受控 search_web/fetch_url(继续服从既有开关与 SSRF 防护),普通 Shell 保持 network_mode=none;Dependency profile 隐式申请出口,run_command 可显式设置 network_capability=dependency_egress,使当前一次性执行使用 network_mode=egress。full_access 允许所有 runner 出网。
临时出口可访问任意公网目标,不设命令分类、命令/域名/IP/包仓库白名单;任意显式申请能力的 Shell 命令及包安装钩子、构建脚本、子进程均共享本次出口。执行结束即销毁容器,web_tools 下后续普通 Shell 仍离线。Python pip install、Node npm ci、Rust cargo test、Go go test ./... 和 JVM ./gradlew test/mvn test 的显式工具参数示例见配置文档。
sandboxd 将已授权的 egress 映射到部署侧固定的 SAKURA_SANDBOX_EGRESS_NETWORK,默认是 Docker 内置 bridge,因此全新 Docker 环境无需额外创建网络即可实际出网。若管理员需要独立出口,可配置一个预先管理的 named network;网络名本身不会提供域名白名单,例如:
docker network create sakura-ai-egress
sudo env SAKURA_SANDBOX_EGRESS_NETWORK=sakura-ai-egress ./start.sh --prod网络名只允许 bridge 或符合 sandboxd 校验的 named network(字母/数字、.、_、-,最长 63 个字符);host、container:*、ns:*、路径/选项字符串及空值均拒绝。脚本会将它持久化并纳入 sandboxd 容器 label/identity drift 检查;不存在的 named network 会使 sandboxd 启动失败。模型只能请求抽象执行能力,不能改变管理员策略、Docker 网络名或其他运行参数。旧版本的 SAKURA_SANDBOX_DEPENDENCY_NETWORK 仅作 deployment.env 迁移兼容,不应作为新配置入口。
源码开发只有在 SAKURA_DEPLOY_MODE=source、显式选择 agent_team_execution_backend=local 且网络策略为 full_access 时才允许本地执行,此模式使用宿主网络,不提供 OS 隔离或临时沙箱出口。image、production、unknown 或缺失部署模式均拒绝 local。macOS/Windows 的仅容器部署没有 Linux sandboxd,若启用 Agent 执行会明确失败,而不会降级到 Web 宿主进程。
WebUI 分别显示普通执行就绪与临时依赖出口可用;后者要求 sandboxd 就绪且提供 egress,仅策略授权不代表出口可用。local 显示授权模式不适用、临时依赖出口不可用,并单独提示宿主网络。
Agent 依赖环境只使用每个任务工作区内固定的 .venv/local 和 .venv/sandbox 路径。这两个目录是 Agent 内部的临时目录,不承载用户数据;切换执行后端时, 服务会在 runner admission 前删除非活动后端的目录,环境不完整时也会删除并重新创建。 清理仅针对当前 task worktree 下的这两个精确路径,并且不会跟随 symlink/reparse 到外部目标。
MySQL 低内存调优: compose 为 MySQL 8.4 显式设置了
performance-schema=OFF、innodb-buffer-pool-size=64M、innodb-redo-log-capacity=32M、max-connections=40并关闭 X Plugin,空闲内存约 200MB(默认配置约 500MB)。代价是sys/performance_schema监控表不可用;业务数据量增长到数十 MB 以上时可酌情调大缓冲池。应用侧连接池上限为 30(pool_size=10+max_overflow=20,见backend/models/database.py),40 连接仍有约 9 个余量。既有部署v3.1.1重新下载docker-compose.prod.yml后重跑sudo ./start.sh --prod即可生效,up -d只重建 mysql 容器,mysql_data数据卷保留。
macOS(仅容器,不包含 Host Updater):
mkdir sakura-ai && cd sakura-ai
mkdir -p docker .deploy workplace
curl -L https://raw.githubusercontent.com/Sakura520222/Sakura-AI/main/docker/docker-compose.prod.yml \
-o docker/docker-compose.prod.yml
umask 077
printf 'SAKURA_DEPLOY_MODE=image\nSAKURA_AI_IMAGE=ghcr.io/sakura520222/sakura-ai:latest\nCOMPOSE_PROJECT_NAME=sakura-ai\nSAKURA_DB_PASSWORD=%s\nSAKURA_SANDBOX_WORKSPACE_ROOT=%s\n' \
"$(openssl rand -hex 32)" "$(pwd)/workplace" > .deploy/deployment.env
docker compose --env-file .deploy/deployment.env --project-name sakura-ai -f docker/docker-compose.prod.yml up -dPowerShell(Windows):
New-Item -ItemType Directory -Force sakura-ai | Out-Null
Set-Location sakura-ai
New-Item -ItemType Directory -Force docker, .deploy, workplace | Out-Null
Invoke-WebRequest `
-Uri "https://raw.githubusercontent.com/Sakura520222/Sakura-AI/main/docker/docker-compose.prod.yml" `
-OutFile "docker/docker-compose.prod.yml"
$bytes = [Security.Cryptography.RandomNumberGenerator]::GetBytes(32)
$dbPassword = [Convert]::ToHexString($bytes).ToLowerInvariant()
$workspaceRoot = (Resolve-Path workplace).Path
@("SAKURA_DEPLOY_MODE=image", "SAKURA_AI_IMAGE=ghcr.io/sakura520222/sakura-ai:latest", "COMPOSE_PROJECT_NAME=sakura-ai", "SAKURA_DB_PASSWORD=$dbPassword", "SAKURA_SANDBOX_WORKSPACE_ROOT=$workspaceRoot") |
Set-Content -Encoding ascii .deploy/deployment.env
docker compose --env-file .deploy/deployment.env --project-name sakura-ai -f docker/docker-compose.prod.yml up -dmacOS、Windows 和其他仅容器部署可以自动显示新版本,但不能从 WebUI 执行更新,也不具备 Linux Agent OS 沙箱;请手动拉取目标镜像并重新运行 Compose。当前生产 Compose 需要 SAKURA_SANDBOX_WORKSPACE_ROOT 等由 start.sh 生成的部署身份,因此跨平台手工 Compose 仅适合 Agent 功能关闭的部署。Host Updater 当前仅支持 Linux amd64/arm64 宿主机;sandboxd 完整生命周期采用相同平台边界,且 Host Updater 要求 glibc ≥ 2.36(Debian 12+/Ubuntu 24.04+)。
首次启动后访问 http://localhost:8000/setup:数据库/Redis 连接串已自动预填,点击"测试连接"通过后即可继续 Setup Wizard(其余步骤与源码部署一致)。
1.2 仅运行 Web 镜像(MySQL/Redis 自备)
Linux / macOS:
docker run -d -p 8000:8000 \
-e DATABASE_URL=mysql+asyncmy://user:pass@host:3306/sakura_ai \
-e REDIS_URL=redis://host:6379/0 \
-v $(pwd)/config:/app/config \
ghcr.io/sakura520222/sakura-ai:latestPowerShell(Windows):
$ConfigPath = Join-Path (Get-Location) "config"
New-Item -ItemType Directory -Force $ConfigPath | Out-Null
docker run -d `
--name sakura-ai `
--restart unless-stopped `
-p 8000:8000 `
-e "DATABASE_URL=mysql+asyncmy://user:pass@host:3306/sakura_ai" `
-e "REDIS_URL=redis://host:6379/0" `
-v "${ConfigPath}:/app/config" `
ghcr.io/sakura520222/sakura-ai:latest1.3 固定版本部署(无需编辑 compose 文件)
Linux / macOS:
SAKURA_AI_IMAGE=ghcr.io/sakura520222/sakura-ai:v3.0.0 \
docker compose --env-file .deploy/deployment.env --project-name sakura-ai -f docker/docker-compose.prod.yml up -dPowerShell(Windows):
$env:SAKURA_AI_IMAGE = "ghcr.io/sakura520222/sakura-ai:v3.0.0"
docker compose --env-file .deploy/deployment.env --project-name sakura-ai -f docker/docker-compose.prod.yml up -d
Remove-Item Env:SAKURA_AI_IMAGE1.4 镜像与 Tag 说明
- 权威目录:WebUI 与 Host Updater 只读取 GHCR
ghcr.io/sakura520222/sakura-ai;Docker Hubsakura520222/sakura-ai仅是 best-effort 副本,同步失败不会阻塞 GHCR 发布。 - 正式通道:
latest是默认正式版,且必须与唯一对应的vX.Y.Zmanifest digest 对齐;正式镜像始终从 Release tag 构建。 - 开发通道:
edge是开发移动别名,同时每次developpush 产生不可变dev-<UTC timestamp>-vX.Y.Z-<40 位 SHA>tag。WebUI 的开发版目标只使用不可变 tag + digest,不会把edge写入部署状态。 - 跨通道切换可能回到较旧的正式版本,WebUI 会显示风险并要求明确确认;同通道历史镜像仅供查看,不提供任意降级或回滚。
- 生产 compose 不再内置数据库密码:首次部署必须将强随机的 64 位十六进制
SAKURA_DB_PASSWORD保存到权限为 0600 的.deploy/deployment.env,并始终通过--env-file .deploy/deployment.env启动;文件缺失或变量缺失时 Compose 会 fail-closed。使用仓库中的./start.sh --prod会自动完成生成、持久化和复用,切勿提交该运行时文件。
1.5 config 卷与策略配置迁移
生产镜像的 config_data:/app/config 卷持久化 Setup 生成的 connection.json。审查策略与标签定义已迁移到数据库 app_config 节键(strategy.* / label.*):运行时按节与内置默认深度合并——管理员改动的叶子保留、升级新增的默认叶子自动出现——并随数据库卷持久化、纳入 WebUI 配置备份。全部非 AI 配置在全局配置页 /config 编辑(旧 /config/general|strategies|labels 页面自动重定向);包含已移除历史配置键的旧备份在恢复时会被宽容跳过。
镜像仍保留 packaged YAML 三路合并机制(/app/config-defaults 基线 + 卷内隐藏 baseline),但当前管理文件列表为空;旧部署卷内残留的 strategies.yaml / labels.yaml 不会被读取或修改,可在确认迁移完成后手动清理。
二、环境要求
- Linux 服务器(使用 Host Updater 自动更新要求 glibc ≥ 2.36,即 Debian 12+/Ubuntu 24.04+;仅容器部署无此限制)
- Docker 和 Docker Compose V2(镜像部署;旧版
docker-composeV1 不受支持)/ Python 3.14+(源码部署) - 公网 IP 和域名
- GitHub 账号
- DeepSeek API Key(或其他 OpenAI 兼容 API)
三、创建 GitHub App
- 访问 GitHub Apps 设置,点击 New GitHub App
- 填写名称、Homepage URL
- Repository permissions:Pull requests
Read and write,ContentsRead and write,ChecksRead and write,ActionsRead,IssuesRead and write(可选) - Webhook URL:
https://your-domain.com:8000/api/webhook/github,填写 Webhook secret - Webhook events:勾选 Pull requests、Pull request reviews、Check runs、Workflow jobs、Issues(可选)、Issue comments(可选)
- 创建后,在 App 页面底部 Generate a private key,下载
.pem文件(Setup Wizard 中需粘贴完整私钥内容) - 点击左侧 Install App,选择要启用审查的仓库
OAuth App(WebUI 登录)
WebUI 登录需额外创建 OAuth App,回调地址设为 https://your-domain.com/auth/callback。
用户级 GitHub App 授权(仓库互助 / 授权中心,可选)
启用仓库互助或普通用户 GitHub App 授权中心时,需在该 GitHub App 设置中启用 Request user authorization (OAuth on behalf of users);仓库互助还需 Starring 写权限。两者共用回调地址 https://your-domain.com/star-aid/auth/callback。该 App 可复用审查主 App,也可在系统核心配置中独立配置;独立 App 必须填写 star_aid_github_app_slug,否则授权中心不展示“安装到其他账户/组织”链接。授权中心基于 GitHub 官方 /user/installations 接口,只显示当前登录 GitHub 用户可访问的安装与仓库;安装与仓库发现的总超时由 star_aid_github_app_discovery_timeout_seconds 控制,默认 45 秒,部署时应低于反向代理/网关超时。
四、准备数据库(源码部署 / 自备存储)
在宿主机安装并启动 MySQL 和 Redis:
sudo apt update && sudo apt install mysql-server redis-server -y
sudo systemctl start mysql && sudo systemctl start redis
sudo mysql -e "CREATE DATABASE IF NOT EXISTS \`sakura_ai\` CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;"
sudo mysql -e "CREATE USER IF NOT EXISTS 'root'@'%' IDENTIFIED BY 'your_password';"
sudo mysql -e "GRANT ALL PRIVILEGES ON *.* TO 'root'@'%';"
sudo mysql -e "FLUSH PRIVILEGES;"Docker 全量部署无需此步,compose 会自动拉起 MySQL 与 Redis。
五、源码部署 / 开发模式
git clone https://github.com/Sakura520222/Sakura-AI.git
cd Sakura-AI开发 Compose(挂载源码,只启动 Web 服务):
mkdir -p workplace
docker compose -f docker/docker-compose.yml up -d --build开发 Compose 不要求预先导出 SAKURA_SANDBOX_WORKSPACE_ROOT:未设置时安全地使用 仓库根目录下的 workplace/。它只启动 Web,不会替代独立的 sandboxd。普通非 root 源码启动、显式 local 后端或已禁用 Agent 时,start.sh 不会无条件创建 root-owned sandboxd;如果要在源码环境启用 OS 沙箱,请由管理员显式执行 sudo ./start.sh sandboxd start,并使用 sandbox 后端。sandboxd 无法通过 root/身份/健康 检查时,Agent 请求保持 fail-closed,不会降级到 Web 进程执行。
本地直接运行:
源码开发平台:Windows 11 x86_64、Linux x86_64/arm64(glibc ≥ 2.28,非 musl;Alpine 不支持)或 Apple Silicon macOS 14+;Intel Mac、macOS ≤13、musl/Alpine 与 glibc <2.28 因上游 onnxruntime 未发布对应 Python 3.14 wheel(且无 sdist)无法安装依赖,pip 方式同样受限。
uv 方式(推荐):
uv sync # 自动创建 .venv 并安装全部依赖(含 updater)
uv run python -m backend.mainWindows PowerShell 开发与测试:安装 Git for Windows、uv 后,在仓库根目录执行:
uv sync --locked
uv run pytest -q
uv run ruff check .
uv run python -m backend.main上述流程使用 Windows 原生 Python 3.14,不依赖 WSL/Git Bash。测试使用模拟数据库、Redis、GitHub 和 AI 服务;实际启动后端时需要准备 MySQL/Redis,再通过 Setup Wizard 配置连接。Windows CI 运行完整 pytest 与 Ruff;POSIX Bash、systemd、Linux Landlock/seccomp 和真实 Linux 容器隔离用例按平台能力明确跳过,Linux CI 保留这些检查。符号链接测试按当前账户的实际权限判断;不要求管理员运行 pytest,可选开启 Windows 开发者模式增加这部分覆盖。
Windows 支持 Agent 工作区跨进程读写锁,以及安全的普通文件、仓库规则和 Skill 读取。Host Updater 的 systemd 生命周期、sandboxd 和本地只读 Git/grep 的 Landlock/seccomp 隔离仍需 Linux,相关生产部署边界保持上述说明。
传统 pip 方式(无 uv):
python -m pip install -r requirements-dev.txt
python -m backend.main首次启动将进入 Bootstrap 模式,访问
http://localhost:8000/setup通过 Setup Wizard 完成配置。也可通过
./start.sh(开发模式)或./start.sh --prod(生产镜像模式)启动。
调试 Setup Wizard
只想在本地调试首次部署 / Setup Wizard 流程时,使用独立的 dev 配置文件启动:
py scripts/dev_bootstrap.py该脚本使用 .sakura/dev/connection.json,不会覆盖正式的 config/connection.json,并跳过 Telegram、SSE、扫描、配额等后台任务。需要重新从第 0 步调试时:
py scripts/dev_bootstrap.py --reset六、Setup Wizard 引导配置
首次启动后访问 https://your-domain.com/setup,Setup Wizard 将分步引导完成所有配置(支持断点续配)。
安全验证
首次启动生成随机验证 Token,访问 /setup/verify 时输入。Token 不进入任何日志;本机管理员读取 config/.setup-token(Linux 权限 0600,Windows 在创建文件时设置仅允许进程用户访问的受保护 ACL,要求文件系统支持 ACL),或由 start.sh 在部署成功后读取并显示:
docker compose --env-file .deploy/deployment.env --project-name sakura-ai \
-f docker/docker-compose.prod.yml exec web cat /app/config/.setup-token每次进程启动会原子替换该文件,旧 Token 失效;Setup 完成后立即撤销内存凭据并尝试删除文件。文件被占用时记录清理警告,配置完成与重启仍正常进行;本机管理员解除占用后可清理残留文件,其内容已不能用于验证。源码部署用 cat config/.setup-token;PowerShell 用 Get-Content config/.setup-token。设置 SAKURA_CONNECTION_CONFIG_PATH 时,Token 文件位于该连接配置旁。保护配置目录的本机访问权限。
配置步骤
验证通过后进入向导,分步完成:
- 数据库配置:填写连接地址,检查数据库并测试 Redis;需要时授权自动修复后继续
- GitHub App 配置:填写 App ID、私钥和 Webhook Secret,自动验证 App 连接
- AI 模型与通知:配置 AI API(支持自动获取模型列表)和 Telegram Bot Token
- 管理员与 OAuth:设置管理员账户、应用域名和 GitHub OAuth 凭证
Setup Wizard 内置 RAG 嵌入与重排序模型配置(可折叠),可跳过后续在 WebUI 中配置。
MySQL 安装能力检测失败时,先查看结果区的错误码、binlog 参数和 Guard 状态。 Windows 源码、Docker MySQL、远程独立实例使用同一条预检与恢复流程: 权限允许时自动安装;1419 或缺少 TRIGGER 时,可在结果区使用一次性的管理员 会话自动建表、安装并验证账本 Guard、按需授予应用账号表级 TRIGGER,再重新 检测。管理员凭据提交后清空,不保存到配置或日志;请使用持续有效的账号, 该账号将成为触发器 DEFINER。
共享/托管 MySQL 无足够管理员权限时,复制或下载当前数据库的修复 SQL 交给 DBA/服务商。应用不自动修改实例全局参数、不授予 SUPER、不重建数据库。 正确预装 Guard 后无需再次取得创建权限;修复后可以直接重试当前步骤, 无需重填其他配置。MySQL 已提交的部分 DDL 会保留,失败不会写 Setup 完成标记。 详细权限与清理说明见计费文档 · MySQL 账本触发器预安装。
七、验证部署
curl http://your-domain.com:8000/health
# {"status":"healthy","service":"sakura-ai"}WebUI:https://your-domain.com/
八、查看运行日志
应用使用 Loguru 输出日志。控制台和文件共同遵循 Settings / WebUI log_level,保存后立即生效,无需重启或创建新日志文件。生产默认 INFO;未显式配置级别的本地开发环境默认 DEBUG;已有数据库配置始终优先。两种环境均关闭异常局部变量诊断、统一脱敏,保留文件、函数、行号、异常链与错误类型。
start.sh 主菜单提供两个直接入口:
- 查看容器当前日志:可选 Web、MySQL、Redis 或 Agent sandboxd,只显示该容器本次启动后的日志,默认回放最近 200 行并持续跟随。
- 查看往期运行日志:按时间从新到旧列出
app_*.log,选中后显示文件最后 1000 行。生产镜像部署会以只读方式读取logs_data命名卷,即使 Web 容器已停止也可回溯。
日志文件
- 源码部署:项目根目录
logs/app_<启动时间戳>_pid<PID>.log - Docker 部署:容器内
/app/logs/,对应生产 Compose 的logs_data命名卷 - 每次进程启动新建一个以「时间戳 + PID」命名的文件;单文件达到 50 MB 自动轮转;启动和轮转时清理超过 10 天 的文件,并按最旧优先将历史文件压至 500 MiB;当前写入文件最多额外占一个轮转段
- 新文件为 JSON Lines,每行包含
text和结构化record;旧文本文件保留至正常到期。异常文本位于record.extra.exception,不会序列化原始异常或帧内变量。 - HTTP 凭据、OAuth 参数、API Key、已配置密钥和 Provider 调用凭据在输出前脱敏。业务信息、路径等仍可能敏感,分享前检查范围。
- HTTP 响应返回服务器生成的
X-Request-ID。日志中的request_id、task_id、Activitysession_id/invocation_id/work_unit_id、logical_call_id、attempt_id和tool_call_id贯通调用链。Agent 旧会话使用agent:<id>,避免和 Activity 会话混淆;无 Activity 的直接 Provider 请求使用send-<uuid>attempt。 - 超级管理员可在 Activity 会话点“近期日志”,读取当前实例最多 4 MiB 中最新 200 条匹配记录。权限仍校验会话范围,响应不缓存;不提供跨副本或过期日志搜索。多副本请用关联 ID 在各实例日志或既有日志采集系统查询。
- Compose 为 Web / MySQL / Redis,以及 start.sh 管理的 sandboxd 与任务 runner 启用 Docker
json-file轮转:每份50m、最多3份,约 150 MB/容器。更新配置后需重新创建容器;Docker 自动淘汰旧段,不要直接删除活跃的 Docker 日志文件。旧容器日志在旧容器删除时回收,避免同时保留大量已停止容器。
实时跟踪控制台
# 源码部署:直接运行会在当前终端实时输出
python -m backend.main
# Docker:跟踪 web 容器输出(在 /opt/sakura-ai 下)
docker compose --env-file .deploy/deployment.env --project-name sakura-ai \
-f docker/docker-compose.prod.yml logs -f --tail=200 webPowerShell:
Set-Location C:\path\to\sakura-ai
docker compose --env-file .deploy/deployment.env --project-name sakura-ai `
-f docker/docker-compose.prod.yml logs -f --tail=200 web查看落盘结构化日志
需要 DEBUG 细节时先在 WebUI 设置日志级别。历史详情可读取文件;可用 jq -r .text 将新 JSON Lines 日志还原为堆栈文本。跟踪最新一次启动的文件:
# 源码部署
tail -f "$(ls -t logs/app_*.log | head -n1)"
# Docker:进入 web 容器查看
docker compose --env-file .deploy/deployment.env --project-name sakura-ai \
-f docker/docker-compose.prod.yml exec web \
sh -c 'tail -f "$(ls -t /app/logs/app_*.log | head -n1)"'
# 容器已停止时,直接从命名卷读取
docker run --rm -v sakura-ai_logs_data:/logs alpine \
sh -c 'tail -f "$(ls -t /logs/app_*.log | head -n1)"'过滤错误与读取首次部署 Token
# 统一设置 compose 调用(在 /opt/sakura-ai 下执行)
COMPOSE="docker compose --env-file .deploy/deployment.env --project-name sakura-ai -f docker/docker-compose.prod.yml"
# 只看错误与异常
$COMPOSE logs --tail=1000 web | grep -iE "error|exception|critical|traceback"
# 提取 Setup Wizard 首次部署验证 Token(每次启动重新生成)
$COMPOSE exec web cat /app/config/.setup-tokenWebUI 的「审查日志」(
/logs) 与「操作日志」(/logs/actions) 存于数据库,分别记录 PR 审查历史和管理员审计操作,与本节的应用运行日志文件不同。
九、Host Updater 守护进程
Host updater 是一个独立的 Linux 宿主守护进程。Backend 会定期检查新 Release;超级管理员在 WebUI 版本管理器中确认稳定版更新后,Host Updater 同时读取严格 v1 update-manifest.json 和同版本 agent-sandbox-manifest.json,预检并拉取 Web、sandboxd、runner 三个不可变镜像,原子更新部署状态,先重建并验证 sandboxd,再激活 Web。任一步失败时会恢复三项旧镜像状态并收敛旧 sidecar/Web;legacy 部署没有旧 sandbox pair 时会先卸载本次 sidecar,只有确认成功后才恢复旧 Web。它不会无人值守安装更新。
运行环境要求:自 2026-08-21 起,updater 发布二进制在 Python 3.14 Bookworm(glibc 2.36)环境中构建,宿主机需要 glibc ≥ 2.36(Debian 12+、Ubuntu 24.04+)。更早版本基于 Bullseye(glibc 2.31)构建,可运行于更老的发行版;宿主机仍为 Ubuntu 20.04/22.04 或 Debian 11 等旧系统时,请勿升级到新二进制(自动更新确认前请先确认发行版满足要求),或改为仅容器部署并手动更新镜像。
通过本指南推荐的 sudo ./start.sh --prod 首次部署时,updater 会随应用自动完成 binary 安装,并渲染、启用和启动 sakura-ai-updater.service;无需再单独执行下面的管理命令。生产 binary 要求 Linux 宿主机的 PID 1 是可用的 systemd;容器、LXC/NAS 或其他不满足该条件的环境会明确失败,不会声称已配置重启自启。
管理命令
通过 start.sh 脚本管理 updater 守护进程:
./start.sh updater install|reinstall|uninstall|start|stop|statusaction 默认为 status,即 ./start.sh updater 等价于 ./start.sh updater status。
reinstall是推荐的同步命令:先确认没有后台部署,再通过 updater 内部锁原子关闭新任务提交并确认没有活动任务,然后在维护门禁后停止 systemd service、原子安装对应 Release 的 binary、重新启用并启动 unit,最后输出状态。安装或校验失败时会尝试用保留的安全 binary 恢复原 daemon。这样既避免检查任务与停止 daemon 之间的竞态,也避免后台start.sh --prod在手工stop/install/start之间重新拉起 daemon。- 不支持
/v1/lifecycle/prepare-stop的旧 daemon 无法提供原子任务门禁,reinstall会 fail-closed。升级这类旧版本时,应先在 WebUI 确认没有活动任务,再显式执行sudo ./start.sh updater stop,随后更新到支持service-install的 release;旧 binary 不认识该子命令时不会删除当前磁盘上的 binary,会明确报错并给出升级指引,不会假装已完成自启动迁移。 install在 daemon 已运行时保留 restart-required 语义:它会完成 binary 校验并报告“需要重启”,不会先 raw stop 正在处理任务的 daemon。需要切换正在运行的 inode 时使用reinstall,让维护门禁和 systemd stop 保持同一安全顺序。uninstall在存在已安装/已加载 unit 或残留 enable link 时,会先执行service-uninstall(systemd stop、backend 兜底 stop、disable、删除 unit 和 daemon-reload),确认 socket 已停止后才删除 binary;同一操作重复执行幂等。若 socket 仍由无法验证身份的监听者占用,会 fail-closed 并要求管理员先检查监听进程,不会盲目 kill。
systemd 自启动、验证与迁移
生产 binary 的 unit 固定为 /etc/systemd/system/sakura-ai-updater.service,由当前 updater binary 生成并使用同一份 --binary-path、--socket-path、--state-dir、Compose 和 deployment.env 参数。service-install 的顺序是写入 unit、daemon-reload、enable、start;因此宿主机重启后 systemd 会按 PIDFile 恢复 daemon。安装或部署完成后验证:
sudo systemctl is-enabled sakura-ai-updater.service
sudo systemctl is-active sakura-ai-updater.service
sudo systemctl status sakura-ai-updater.service --no-pager现有手动 daemon 迁移使用维护门禁后的单条命令:
cd /opt/sakura-ai
sudo ./start.sh updater reinstall如果 systemd 不可用,生产 install、reinstall 和生产启动都会明确失败;不会回退到手动 daemon 后宣称下次重启能够自启。显式 SAKURA_UPDATER_DEV=1 的源码/dev 模式继续使用手动 daemon,重启后需要管理员再次执行 sudo env SAKURA_UPDATER_DEV=1 ./start.sh updater start。卸载使用 sudo ./start.sh updater uninstall,会在删除 binary 前清理 service;没有 unit 的旧手动安装仍可安全重复卸载。若 unit 残留但 binary 已缺失,脚本会保守失败,需恢复匹配 release 后再清理。
WebUI 更新后同步 Host Updater
WebUI 版本管理器的稳定版事务会更新 Web、sandboxd 与 Agent runner,但不会替换或重启宿主机上的 Host Updater 二进制。预检中的“Updater 文件可用”只验证目标 Release 包含当前架构对应的 updater binary 与 SHA256SUMS,不代表更新任务会安装该 binary。因此,三镜像事务成功后,正在运行的 updater 仍可能是更新前的版本。
等待 WebUI 更新任务成功,并确认应用健康接口已经返回目标版本:
cd /opt/sakura-ai
curl --fail --silent --show-error http://localhost:8000/health只有人工确认上述响应中的 version 等于 WebUI 更新的目标版本后,才能重新安装 updater:
sudo ./start.sh updater reinstall
sudo curl --fail --silent --show-error \
--unix-socket /run/sakura-ai/updater.sock \
http://updater/v1/healthinstall 不会下载 latest updater,而是根据部署状态解析具体 Sakura AI 版本并下载同一 Release 的架构资产。它本身不提供应用健康门禁:当 deployment.env 已包含具体的 SAKURA_AI_IMAGE=:vX.Y.Z 时,安装器可以直接采用该版本,无需查询 /health。因此,“/health 成功返回预期目标版本”仍是管理员重新安装 updater binary 前必须手动完成的检查。三镜像应用更新本身则由当前 updater 事务执行 health 与 rollback 门禁。
生产首次安装
生产环境的 updater 二进制路径为 .deploy/updater/sakura-ai-updater。首次执行 install 时,即使宿主机没有 Python 且该 binary 尚不存在,也会由 start.sh 完成 binary acquisition,并交给 systemd 渲染、启用和启动 unit;生产路径不依赖宿主机 Python。install、start 和 service lifecycle 操作需要 root 权限,因为需要创建固定 GID 9472 的系统组、/run/sakura-ai 运行时目录和 /etc/systemd/system 下的 unit:
sudo ./start.sh updater install # 获取并校验当前版本 binary,安装并启用 systemd unit
sudo ./start.sh updater start # 确认/启动 systemd service安装严格绑定当前部署的 Sakura AI 版本,不下载 latest updater。版本解析是 deployment-mode-aware 的:
SAKURA_DEPLOY_MODE=image:优先使用deployment.env中SAKURA_AI_IMAGE=:vX.Y.Z(可带 digest)的镜像版本作为权威来源;镜像为:latest或无具体 tag 时,读取已健康运行服务的/health版本;服务尚未就绪时才回退到backend/__init__.py的__version__。镜像部署时实际运行版本始终优先于 host checkout 版本。SAKURA_DEPLOY_MODE=source:以backend/__init__.py的__version__ = "X.Y.Z"为权威来源。deployment.env缺失或SAKURA_DEPLOY_MODE不是image/source时 fail-closed,不猜测版本。
:latest 不是具体版本。以上来源都无法确定具体版本时 fail-closed。仅支持 Linux amd64 与 arm64,其他操作系统或架构会明确失败。
state directory 与 binary 校验:state directory 首次创建为 root-owned 0700。重复执行安装时,只要现有目录 owner 为 root 且 group/other 无写权限就会自动 harden 到 0700;owner 非 root、group/other 可写或目录是 symlink 时 fail-closed。binary 和 SHA256SUMS 从对应 GitHub Release 通过 HTTPS 获取,并严格校验目标 binary 的 SHA256 条目。binary 为 root-owned 0700;install lock 防止并发 acquisition;下载临时文件位于同一 state directory,校验、临时文件 fsync 和安全检查通过后以同文件系统 atomic rename 替换最终 binary。
安装失败保护(两个阶段):
- 下载、checksum、chmod、临时文件 fsync 或临时文件安全检查等 pre-commit 失败时,旧 binary 保持 byte-for-byte unchanged。
- atomic rename 之后,如果目录 metadata fsync 或 final safety confirmation 失败,则不得声称旧 binary 未变,必须提示新 inode 可能已经安装,且不会继续调用 backend install。只有 post-commit 检查成功后才完成 backend bootstrap。
Linux 原子替换 binary 后,已经运行的 daemon 会继续使用旧 inode,不会自动切换到新版本。单独 install 会保留 restart-required 语义,不会为了替换正在运行的 inode 而 raw stop;重复安装时推荐使用带竞态门禁的一体化命令:
sudo ./start.sh updater reinstall如果已经在 daemon 运行期间执行了 install,请改用 reinstall 完成安全迁移。只有显式源码/dev 模式才需要手动 stop/start;未设置该环境变量时,命令按生产 systemd 生命周期运行:
sudo env SAKURA_UPDATER_DEV=1 ./start.sh updater stop
sudo env SAKURA_UPDATER_DEV=1 ./start.sh updater start源码开发模式
开发环境可使用显式 Python override 运行 updater;这不是生产 fallback:
sudo env SAKURA_UPDATER_DEV=1 SAKURA_UPDATER_PYTHON=/path/to/python ./start.sh updater start安全边界
- Web 容器通过只读挂载
/run/sakura-ai目录(Unix Domain Socket)与 updater 通信,不挂载docker.sock - Web 容器通过另一个只读目录
/run/sakura-ai-sandbox与 sandboxd 通信;两个 UDS、GID、状态目录、协议与生命周期完全独立 - 只有 sandboxd 专用容器持有 Docker socket;sandboxd 请求协议不接受任意镜像、宿主路径、network、runtime 或 Docker argv
- 生产部署必须位于 root-owned、group/other 不可写的目录链中;推荐固定使用
/opt/sakura-ai。updater 启动时会对 binary、Compose 和deployment.env逐级lstat并 fail-closed,拒绝 symlink、非 root owner、共享写权限或非0600的部署状态 - 生产 updater 由
/etc/systemd/system/sakura-ai-updater.service自启,不依赖 cron;宿主机重启后由 systemd 恢复 daemon。若 PID 1 不是可用 systemd,生产启动会明确失败,不会声称已配置自启。显式SAKURA_UPDATER_DEV=1的源码/dev 模式保持手动 daemon 生命周期,重启后需要运行sudo env SAKURA_UPDATER_DEV=1 ./start.sh updater start;这只恢复更新服务,不会自动安装应用更新
十、卸载
默认卸载会停止仍在后台运行的部署 runner,确认没有活动 updater 更新任务,停止并删除经身份验证的 sandboxd,删除 Compose 容器/网络并卸载 Host Updater,但保留 MySQL、Redis、配置、ChromaDB、日志、工作区和 Skills 等数据,同时保留 .deploy/deployment.env,方便以后用原密码和原数据重新部署:
cd /opt/sakura-ai
sudo ./start.sh uninstall命令会要求输入 UNINSTALL。自动化环境必须显式传入 --yes,不会因为 stdin 非交互而默认确认。
完全清理必须显式使用 --purge 并输入 UNINSTALL:
sudo ./start.sh uninstall --purge--purge 会永久删除 Compose 数据卷(包括 MySQL/Redis 数据)、全部 Sakura AI 镜像及部署文件,无法由脚本恢复。在 /opt/sakura-ai 等独立安装目录中,清理后只保留 start.sh,便于重新部署;源码仓库模式会保护项目源码,只清理部署状态。可审计的非交互清理需要同时提供 --purge --yes。
生产部署的镜像拉取在后台 runner 中使用 Docker Compose 原生 TTY 进度渲染器。Ctrl+C 只退出 tail 查看,拉取与启动继续运行;重新连接后可用 ./start.sh --attach 继续查看,或用 ./start.sh --status 查看当前 pull/start/health 阶段。若宿主 Compose 版本不支持 --progress,脚本会明确警告并回退到普通拉取输出。
三镜像 deployment contract(Host Updater 0.3.0)
/v1/status、/v1/health 和 sakura-ai-updater --identity 返回 updater_version、protocol_version、build_revision、build_release 和 capabilities。正式二进制的构建身份在打包时写入;源码运行明确标记为 source。协议 1 只保证通信;image-mode 更新要求以下全部能力,未知附加能力不会阻止兼容:
three-image-transaction-v1deployment-reconcile-v1deployment-manifest-v1
Web 后端在 check/preflight/update 前查询正在运行的 daemon;WebUI 显示兼容状态及缺失能力。安装脚本在替换 binary 前检查候选文件的 --identity,因此缺少 development Release asset 时,stable fallback 必须同样兼容。不兼容时保留旧 binary 并拒绝危险更新。使用当前脚本执行 sudo ./start.sh updater reinstall;若选定 Release 尚未提供兼容 asset,必须先发布/提供兼容 Release,不能通过修改版本号或忽略能力检查绕过。尚未升级的旧 Web 无法得到新 Web 的保护,因此管理员应先同步脚本与 Updater,再进行应用更新。
development 的单一目标来源是 Web OCI image index 中的 com.sakura-ai.deployment.v1 JSON annotation。schema 1 包含 channel、完整 revision、version、canonical tag 以及可信 GHCR 仓库的 sandboxd_image/runner_image digest 引用;index 的平台 descriptors 和外部 digest 标识 Web 本身,避免自引用 digest。CI 先按 digest 发布全部镜像,验证每个平台的构建标签,再发布带 manifest 的 canonical index,回读验证并确认源仍为 develop head 后,最后推进 edge。失败构建不会进入目录;不带完整 manifest 的旧 development tag 不再是可选择目标。stable 继续使用现有 Release 的 update-manifest.json 和 agent-sandbox-manifest.json,并验证共同 revision,不改变 Release 文件格式。
check/preflight 比较三个目标 digest、共同 revision、deployment.env 以及实际 sandboxd/Runner 运行配置。缺失或漂移的 sandbox pair 是可修复状态,不会仅因为 Web 已到目标而报告无需更新。旧的 mixed deployment 可以选择当前目标正常更新;完整一致时则返回无需更新。直接重启遇到已 pin 但 revision 不一致的旧 development 状态时,也会改为解析完整 channel head 自愈。首次 development 安装也只消费完整 manifest,旧的无 manifest pin 无法作为新安装目标,应通过兼容 Updater 迁移到已完整发布的目标。
更新先验证三份远程镜像,再全部 pull 并检查本地不可变身份,之后才原子替换 deployment.env。激活后检查 Web、sandboxd 健康和实际三镜像身份,只有全部通过才提交事务并写入 deployment_verified=true。任一步失败则整体恢复旧部署;回滚失败明确记录 failed 和 rollback error,保留恢复 journal。进程中断后的 daemon 启动会先恢复旧 env 并重新收敛容器,再清除中断任务门禁;恢复失败保留 journal 并停止服务,避免继续部分更新。轮询中断或仅 Web /health 成功都不能替代完整部署成功凭证。
最后更新:2026-10-12 · 发现错误?提 Issue