
Onyx Sandbox 容器鏡像全解析構建、部署與運行時內幕【免費下載鏈接】danswerOpen Source AI Platform - AI Chat with advanced features that works with every LLM項目地址: https://gitcode.com/GitHub_Trending/da/danswer本文聚焦 Onyx原 DanswerCraft 功能的沙箱容器鏡像Sandbox Container Image以backend/onyx/server/features/build/sandbox/image/目錄為核心系統講解鏡像的構建方式CI 與本地兩種路徑、應用版本對齊的部署策略、鏡像內預置的全部組件Next.js 模板、Python venv、OpenCode CLI、快照守護進程等、會話運行時目錄結構并結合 Dockerfile、entrypoint、防火墻初始化腳本與 sidecar 守護進程源碼深入揭示鏡像內部的啟動流程、出口網絡封鎖與快照持久化機制。讀完本文你將具備獨立構建、發布、排查 Onyx 沙箱鏡像的完整能力。一、鏡像在 Onyx 架構中的位置Onyx 的 Craft 功能為每個用戶提供一個隔離的沙箱環境用于運行 OpenCode 編碼 AgentAgent 在其中構建 Web 應用、執行 Python 代碼并訪問知識庫文件。這些沙箱的運行載體Kubernetes Pod 或 Docker 容器完全由本目錄產出的容器鏡像承載。Kubernetes 模式下每個用戶一個 Pod由api_server通過 Kubernetes API 驅動 Pod 生命周期與kubectl exec見 kubernetes_sandbox_manager.pyDocker 模式下api_server掛載/var/run/docker.sock調用 Docker Engine API見 docker_sandbox_manager.py。兩種后端共享同一份鏡像其源碼與構建產物全部位于 backend/onyx/server/features/build/sandbox/image。二、鏡像目錄結構速覽image/ ├── Dockerfile # 主容器鏡像定義多階段構建 ├── .dockerignore # 裁剪構建上下文 ├── entrypoint.sh # 容器啟動腳本opencode serve 重啟循環 ├── sidecar-entrypoint.sh # sidecar 守護進程啟動腳本 ├── firewall-init.sh # 出口防火墻 CA 信任初始化腳本 ├── browser-cli.sh # agent-browser 的 PATH 包裝器 ├── sandbox_daemon/ # 沙箱內 push/快照守護進程烘焙進鏡像 ├── opencode-plugins/ # 按會話打出口代理標簽的插件烘焙進鏡像 ├── templates/ │ └── outputs/ # Web 應用腳手架模板Next.js ├── initial-requirements.in # 沙箱預裝 Python 包清單 └── initial-requirements.txt # 全量鎖定的 Python 依賴一個容易被忽視的設計原則內置技能skills并不在鏡像中。它們存放在 backend/onyx/skills/builtin 目錄由 API Server 在會話建立時推送到沙箱絕不會被烘焙進鏡像。鏡像只預裝技能運行所需的運行時工具LibreOffice、poppler、字體等。三、構建鏡像CI 優先本地兜底3.1 通過 CI 發布推薦路徑應用發布流水線會將沙箱鏡像與應用鏡像打上相同標簽例如應用 tagv4.1.2對應onyxdotapp/sandbox:v4.1.2。CI 的工作機制如下.github/workflows/deployment.yml中的沙箱任務以本目錄內容計算一個內容標簽ctx-hash若ctx-hash已存在部署流水線只為既有 manifest 追加應用 tag/別名不重復構建若不存在則做一次多架構構建并推送ctx-hash隨后再補加應用對齊標簽。該工作流僅在需要回填或修復某個應用 tag時手動觸發。不要為新建構建發布v0.1.x這類僅沙箱的 tag也不要發布 Docker Hub 的onyxdotapp/sandbox:devtag本地開發仍可構建onyxdotapp/sandbox:dev并直接加載進 kind 集群。3.2 本地構建集群運行在 x86_64 節點上因此沙箱鏡像必須構建為 amd64 架構。僅構建 amd64最快cd backend/onyx/server/features/build/sandbox/image docker build --platform linux/amd64 -t onyxdotapp/sandbox:dev .回填或修復時的多架構構建docker buildx build --platform linux/amd64,linux/arm64 \ -t onyxdotapp/sandbox:app-tag \ --push .3.3 構建參數Build ARG與關鍵取舍從 Dockerfile 可以看到鏡像構建是高度參數化的多階段構建構建參數默認值說明BASE_IMAGE_REGISTRYdocker.io基礎鏡像倉庫前綴CI 會覆蓋為 ECR pull-through 緩存以避免 Docker Hub 限流ENABLE_SKILLStrue置為false可跳過技能運行時依賴LibreOffice、poppler、字體、pptxgenjs省約 700 MBENABLE_BROWSERtrue是否打入 Chromium 引擎與agent-browserCLIOPENCODE_VERSION1.18.19OpenCode CLI 版本AGENT_BROWSER_VERSION0.31.1agent-browser CLI 版本NPM_VERSION11.17.0Node 鏡像階段內升級的 npm 版本GH_CLI_VERSION2.94.0GitHub CLI 版本獨立階段下載并用 sha256 校驗和驗證值得注意的源碼細節基礎鏡像最終鏡像基于python:3.13-slimDebian 系Node.js 24 從node:24-trixie-slim階段拷貝二進制bun 則從oven/bun:1.3.14階段拷貝。npm 符號鏈接由于只拷貝了node與node_modules需要手動建立npm、npx、corepack的符號鏈接。Chromium 獨立分層大的、少變的 Chromium 引擎單獨一層后續僅升級AGENT_BROWSER_VERSION時只重拉小體積 CLI 層。不要執行agent-browser install它會抓取 Chrome-for-Testing無 arm64 構建鏡像改用系統 Chromium 并通過AGENT_BROWSER_EXECUTABLE_PATH指定。uid/gid 1000 歸一化構建腳本會把基礎鏡像中已有 uid/gid 1000 的用戶重命名為sandbox保證非 root 運行身份統一。Bun 緩存預熱構建期在/workspace/templates/outputs/web執行bun install --frozen-lockfile后刪除node_modules從而預暖 Bun 的 tarball 緩存使每次會話啟動的安裝命中本地存儲。四、部署新版本鏡像與應用版本對齊部署匹配的應用 tag 即可部署面會自動從應用版本推導沙箱鏡像Docker composeonyxdotapp/sandbox:${IMAGE_TAG}遵循普通應用鏡像的IMAGE_TAG行為含默認latestHelmonyxdotapp/sandbox:${global.version}。Kubernetes 部署應優先使用不可變的應用發布 tag除非刻意選擇移動 tagmoving tags。SANDBOX_CONTAINER_IMAGE是內部逃生艙口僅供本地測試、staging、云端及應急操作使用。其默認值定義在 configs.pySANDBOX_CONTAINER_IMAGE ( os.environ.get(SANDBOX_CONTAINER_IMAGE, ).strip() or onyxdotapp/sandbox:latest )五、鏡像內烘焙了什么鏡像預置內容與文檔一致且均能在 Dockerfile 中逐一找到證據組件位置說明基礎系統python:3.13-slimDebian 系Node.js 24 從node:24-trixie-slim拷貝Web 模板/workspace/templates/outputs/Next.js 應用腳手架COPY --exclude.next --excludenode_modules拷貝Python venv/workspace/.venv/由initial-requirements.txt全量鎖定并--only-binary:all:安裝OpenCode CLI/home/sandbox/.opencode/bin/以 sandbox 用戶身份安裝指定版本、--no-modify-pathonyx-cli/usr/local/bin/onyx-cliOnyx CLI用于搜索快照 sidecar 守護進程/workspace/sandbox_daemon/與/opt/sandbox_daemon/打包/恢復會話文件持久化由 api_server 經 Onyx FileStore 負責出口標簽插件/workspace/opencode-plugins/按會話打代理標簽瀏覽器封裝/usr/local/bin/browseragent-browser 包裝器見下文鏡像內不烘焙技能API Server 在會話建立時把技能推送到/workspace/managed/skills/。5.1 Python 依賴清單initial-requirements.in是精選清單initial-requirements.txt是其全量鎖定版本。前者內容如下cryptography defusedxml fastapi lxml matplotlib matplotlib-inline numpy onyx-cli openpyxl pandas pdfplumber pillow pydantic python-docx python-pptx requests uvicorn[standard]覆蓋數據處理pandas/numpy/matplotlib、文檔解析pdfplumber/python-docx/python-pptx/openpyxl、HTTPrequests與 Web 服務fastapi/uvicorn等場景。5.2 鏡像暴露的端口與入口Dockerfile 末尾暴露三個端口并指定入口# 3000: Next.js dev server, 4096: opencode serve, 8731: push daemon EXPOSE 3000 4096 8731 ENTRYPOINT [/workspace/entrypoint.sh]3000Next.js 開發服務器4096OpenCode 服務8731push 守護進程端口見 contract.py。六、運行時目錄結構一次會話如何鋪開創建會話時Pod 內會搭建如下結構/workspace/ ├── managed/skills/ # 會話建立時推送內置 自定義技能 ├── opencode-data/ # Kubernetes 下的沙箱級全局 opencode 數據 ├── templates/ # 烘焙進鏡像 └── sessions/ └── $session_id/ ├── .opencode/ │ └── skills # 符號鏈接 → /workspace/managed/skills ├── outputs/ # 從模板拷貝內含 Web 應用 ├── attachments/ # 用戶上傳文件 ├── AGENTS.md # 給 AI Agent 的指令 └── opencode.json # OpenCode 配置關鍵設計點技能通過符號鏈接暴露給每個會話避免重復拷貝outputs/從烘焙的模板拷貝保證每個會話有干凈的初始工程AGENTS.md由 util/agent_instructions.py 基于AGENTS.template.md動態填充opencode.json由 util/opencode_config.py 動態生成含 MCP 支持與工具權限。七、啟動鏈路源碼剖析7.1 entrypoint.shopencode serve 重啟循環entrypoint.sh 是容器主進程職責包括opencode 歷史恢復根據OPENCODE_DATA_HOMEKubernetes 下由 sidecar 恢復后指向沙箱級共享卷設置XDG_DATA_HOME放寬 bash 工具超時OPENCODE_EXPERIMENTAL_BASH_DEFAULT_TIMEOUT_MS默認 180000ms180s避免圖片生成等合法慢工具被 opencode 120s 默認超時掐斷代理 CA 導入通過certutil把出口代理的 MITM CA 逐條導入 Chromium 的 NSS 數據庫保證瀏覽器 HTTPS 可用失敗不阻塞啟動重啟循環opencode serve --hostname 0.0.0.0 --port 4096 --print-logs崩潰后按指數退避1s → 最大 30s自動重啟并妥善處理 SIGTERM/SIGINT 信號。7.2 firewall-init.sh出口網絡封鎖與 CA 信任firewall-init.sh 是沙箱安全的關鍵支持兩種引導模式initcontainerK8s initContainer執行完步驟后退出 0entrypointdocker-compose 入口執行完步驟后用setpriv降權到 UID 1000 再 exec 真正的入口。它完成三步安裝代理 CA把SANDBOX_PROXY_CA_BUNDLE_SRC默認/sandbox-ca/ca.crt裝入系統信任庫并生成SANDBOX_PROXY_CA_BUNDLE_DST默認/etc/ssl/sandbox/ca-bundle.crtiptables 出口封鎖清空 OUTPUT 鏈、默認策略DROP僅放行lo、已建立的 conntrack 連接以及到SANDBOX_PROXY_HOST:SANDBOX_PROXY_PORT的 TCPIPv6 同步全封鎖部分封鎖即安全回歸自校驗檢查 OUTPUT 鏈默認策略確為DROP、存在代理放行規則與 conntrack 規則失敗即退出。entrypoint模式下還修復了 Docker 卷掛載點/workspace/sessions的屬主chown 1000:1000并用setpriv --bounding-set-all清除能力邊界集后降權。注意它顯式設置HOME/home/sandbox USERsandbox——setpriv 不會刷新環境變量繼承HOME/root會導致降權后的 Agent 因/root/.cache的 EACCES 而啟動失敗。7.3 sidecar 守護進程簽名保護的 push 與快照sidecar-entrypoint.sh 以無限重啟循環方式運行/workspace/.venv/bin/python -m sandbox_daemon.server。其核心實現位于 server.py是一個 FastAPI 服務提供文件系統列舉/filesystem/list帶路徑穿越防護輸出 manifest/outputs/manifestpush/push流式接收 tar.gz 并校驗 SHA-256 與大小上限后安全解包、原子替換快照創建/恢復/snapshot/create無內容時返回 204與/snapshot/restoreopencode 歷史創建、恢復、標記恢復三組端點。所有寫操作都要求X-Push-Signature與X-Push-Timestamp頭使用 Ed25519 公鑰來自環境變量注入僅 sidecar 持有驗證{timestamp}|{path}|{sha256}簽名并檢查 60 秒時間戳漂移防止未授權的數據寫入。7.4 browser 包裝器與會話標簽插件browser-cli.sh 把agent-browser包裝成 PATH 上的browser可執行文件剝除代理 URL 中的用戶信息代理按源 IP 授權、自動追加--no-sandbox --proxy-server... --proxy-bypass-list127.0.0.1;localhost等參數并把當前會話 ID從 cwd 的/sessions/uuid解析傳給agent-browser --session讓瀏覽器實例與會話一一對應。opencode-plugins/session-proxy-tag.ts 是 OpenCode 插件在會話初始化時從?directory捕獲會話 ID將其編碼進HTTP(S)_PROXY的 userinfo形如https://session-id:xproxy使出口代理能把審批卡片精確路由到對應會話。HTTPS 下該信息隨 CONNECT 的 Proxy-Authorization 傳遞hop-by-hop不會到達源站。該插件路徑與 kubernetes_sandbox_manager.py 中的_OPENCODE_SESSION_TAG_PLUGIN_PATH /workspace/opencode-plugins/session-proxy-tag.ts嚴格對應。八、會話啟動后的完整時序綜合上述腳本一次沙箱會話的啟動鏈路為Pod/容器創建K8s 下先運行 initContainerfirewall-init 的initcontainer模式完成 CA 安裝、iptables 封鎖與自校驗compose 下由 entrypoint 模式完成同樣步驟后setpriv降權sidecar 啟動K8s原生可重啟 init sidecar 運行sandbox_daemon.server恢復 opencode 歷史并等待 API Server 就緒探測主進程啟動entrypoint.sh導入代理 CA 到 Chromium NSS 后循環拉起opencode serve端口 4096會話鋪開API Server 推送技能到/workspace/managed/skills/、從模板拷貝outputs/、掛載附件并注入AGENTS.md與opencode.jsonWeb 預覽Agent 在會話目錄執行bun install --frozen-lockfile命中鏡像預暖緩存bun run devNext.js 開發服務器監聽 3000 端口經 Service/DNS 或橋接網絡代理對外提供預覽快照與恢復sidecar 經簽名 API 打包/恢復會話文件持久化由 api_server 通過 Onyx FileStore 完成沙箱與 sidecar 均不持有存儲憑據。九、故障排查速查9.1 驗證鏡像是否存在于 Docker Hubcurl -s https://hub.docker.com/v2/repositories/onyxdotapp/sandbox/tags | jq .results[].name9.2 查看 Pod 實際使用的鏡像kubectl get pod pod-name -n onyx-sandboxes -o jsonpath{.spec.containers[?(.namesandbox)].image}9.3 常見故障與排查要點癥狀排查要點Pod 停滯在PROVISIONINGK8skubectl logs -n onyx-sandboxes sandbox-{id}查主容器、-c sidecar查 sidecar 日志核對代理 host/CA 配置與 ServiceAccount 是否存在容器停滯在PROVISIONINGDockerapi_server是否掛載了/var/run/docker.sockonyx_craft_sandbox橋接網絡是否存在docker logs sandbox-id8確認ONYX_SERVER_URL在橋接網絡內可達且含 API 路徑前綴Next.js 預覽打不開查容器日志確認bun install成功kubectl exec ... -- ls /workspace/outputs/web確認模板已拷貝瀏覽器 HTTPS 異常確認代理 CA 已導入 Chromium NSSentrypoint 啟動日志會打印導入結果十、安全設計小結從鏡像構建到運行時安全貫穿始終沙箱容器以uid/gid 1000 非 root運行K8s 下使用受限 security contextDocker 下--security-opt no-new-privileges、--cap-drop ALL并通過setpriv --bounding-set-all清空能力集出口網絡強制走代理iptables 默認丟棄所有 OUTPUT僅放行代理端點瀏覽器/CLI 的流量全部經由 egress proxy 審計與路由沙箱與 sidecar 均不持有 FileStore/S3/MinIO 憑據快照數據經簽名 API 流式傳給 api_server 持久化并按租戶隔離存儲路徑寫路徑全部要求Ed25519 簽名 時間戳防重放 SHA-256 完整性校驗Docker 模式下沙箱僅加入專用onyx_craft_sandbox橋接網絡compose 的 postgres/redis/minio/模型服務對沙箱不可達EC2 上的 IMDS169.254.169.254需在宿主機強制 IMDSv2 或加DOCKER-USERiptables 規則阻斷安裝器不會自動處理應用層無兜底。十一、相關資源沙箱系統總覽架構、環境變量、K8s/Docker 映射sandbox/README.md鏡像定義image/Dockerfile配置項與默認值build/configs.py內置技能會話建立時推送不入鏡像backend/onyx/skills/builtin沙箱配置與解析的單元測試test_sandbox_backend_parsing.py、test_docker_manager_config.pyHelm 沙箱相關測試test_pod_spec.py、test_sandbox_image_prepuller.py【免費下載鏈接】danswerOpen Source AI Platform - AI Chat with advanced features that works with every LLM項目地址: https://gitcode.com/GitHub_Trending/da/danswer創作聲明:本文部分內容由AI輔助生成(AIGC),僅供參考