From 0de7d1a0c89b12435e0149f47227b7d1bb6d76d4 Mon Sep 17 00:00:00 2001 From: DJJ Date: Sat, 19 Sep 2026 01:40:32 +0800 Subject: [PATCH 1/6] =?UTF-8?q?=E8=AE=A9=E9=BB=98=E8=AE=A4=20Compose=20?= =?UTF-8?q?=E9=83=A8=E7=BD=B2=E6=97=A0=E9=9C=80=E6=BA=90=E7=A0=81=E5=B9=B6?= =?UTF-8?q?=E4=BF=9D=E7=95=99=E6=98=BE=E5=BC=8F=E6=9C=AC=E5=9C=B0=E6=9E=84?= =?UTF-8?q?=E5=BB=BA=E5=85=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 根 Compose 改用与发布清单一致的固定 GHCR 镜像,既有源码部署更新配置后默认改为运行发布镜像;开发者通过 build override 继续构建三个应用服务。同步双语单文件安装说明和 CI 合并检查,避免用户为自托管克隆并编译仓库。 --- .github/workflows/ci.yml | 1 + README.en.md | 15 ++++++++++++--- README.md | 15 ++++++++++++--- docker-compose.build.yml | 14 ++++++++++++++ docker-compose.yml | 5 +---- package.json | 3 ++- 6 files changed, 42 insertions(+), 11 deletions(-) create mode 100644 docker-compose.build.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 51298762..cf7b2440 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -166,3 +166,4 @@ jobs: docker compose config --quiet docker compose -f deploy/compose/docker-compose.yml config --quiet docker compose --profile replicas config --quiet + docker compose -f docker-compose.yml -f docker-compose.build.yml config --quiet diff --git a/README.en.md b/README.en.md index 6b1bab87..55e116ef 100644 --- a/README.en.md +++ b/README.en.md @@ -52,14 +52,15 @@ The tree brings four concerns together: ## Quick start: run a gateway locally -The default Docker Compose stack includes the app, PostgreSQL, and S3-compatible object storage. Docker with Compose is required; credentials are generated by the installer. +The default Docker Compose stack uses a prebuilt app image from GHCR and includes PostgreSQL and S3-compatible object storage. Install Docker with Compose and download a single Compose file; no source checkout or local build is required. Credentials are generated by the installer. ### 1. Start and pair the instance ```sh -git clone https://github.com/TokenRollAI/tool-bridge.git +mkdir -p tool-bridge cd tool-bridge -docker compose up -d --build +curl -fsSL https://raw.githubusercontent.com/TokenRollAI/tool-bridge/main/docker-compose.yml -o docker-compose.yml +docker compose up -d docker compose exec -T app node /app/dist/admin.js pair ``` @@ -67,6 +68,14 @@ Open [http://127.0.0.1:8787/ui/setup](http://127.0.0.1:8787/ui/setup), enter the Prefer a hosted deployment? Follow the [Railway quick start](#railway). +To build from source, clone this repository and run the following from its root: + +```sh +docker compose -f docker-compose.yml -f docker-compose.build.yml up -d --build +``` + +Both the root Compose file and [`deploy/compose/docker-compose.yml`](deploy/compose/docker-compose.yml) default to a pinned GHCR image. Source builds require the explicit [`docker-compose.build.yml`](docker-compose.build.yml) override. + ### 2. Log in, discover, and invoke with the CLI ```sh diff --git a/README.md b/README.md index ae816584..fbef34c0 100644 --- a/README.md +++ b/README.md @@ -52,14 +52,15 @@ Agent / CLI / Dashboard / MCP client ## 快速开始:本地运行一个网关 -默认 Docker Compose 栈包含应用、PostgreSQL 和 S3 兼容对象存储。需要安装 Docker(含 Compose);安装器会自动生成基础设施凭证。 +默认 Docker Compose 栈使用 GHCR 预构建应用镜像,包含 PostgreSQL 和 S3 兼容对象存储。只需安装 Docker(含 Compose)并下载一份 Compose 文件,无需克隆源码或本地构建;安装器会自动生成基础设施凭证。 ### 1. 启动并配对实例 ```sh -git clone https://github.com/TokenRollAI/tool-bridge.git +mkdir -p tool-bridge cd tool-bridge -docker compose up -d --build +curl -fsSL https://raw.githubusercontent.com/TokenRollAI/tool-bridge/main/docker-compose.yml -o docker-compose.yml +docker compose up -d docker compose exec -T app node /app/dist/admin.js pair ``` @@ -67,6 +68,14 @@ docker compose exec -T app node /app/dist/admin.js pair 希望直接托管到云上?跳到 [Railway 快速部署](#railway)。 +需要从源码构建时,克隆本仓库并在仓库根目录运行: + +```sh +docker compose -f docker-compose.yml -f docker-compose.build.yml up -d --build +``` + +根目录与 [`deploy/compose/docker-compose.yml`](deploy/compose/docker-compose.yml) 均默认使用固定版本的 GHCR 镜像;源码构建需要显式叠加 [`docker-compose.build.yml`](docker-compose.build.yml)。 + ### 2. 用 CLI 登录、发现和调用 ```sh diff --git a/docker-compose.build.yml b/docker-compose.build.yml new file mode 100644 index 00000000..76b8b4df --- /dev/null +++ b/docker-compose.build.yml @@ -0,0 +1,14 @@ +# 源码开发时显式叠加:docker compose -f docker-compose.yml -f docker-compose.build.yml up -d --build +x-local-build: &local-build + image: tool-bridge:local + build: + context: . + dockerfile: Dockerfile + +services: + init: + <<: *local-build + init-bucket: + <<: *local-build + app: + <<: *local-build diff --git a/docker-compose.yml b/docker-compose.yml index 94e5134b..7c017b09 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,10 +1,7 @@ name: tool-bridge x-app-image: &app-image - image: tool-bridge:local - build: - context: . - dockerfile: Dockerfile + image: ghcr.io/tokenrollai/tool-bridge:0.22.0 services: init: diff --git a/package.json b/package.json index e737148a..06b6c290 100644 --- a/package.json +++ b/package.json @@ -19,7 +19,8 @@ "test:integration": "pnpm --filter @tool-bridge/app --filter @tool-bridge/server --if-present test", "test": "turbo run test && pnpm test:package-release && pnpm test:dockerfile && pnpm test:deploy-ci && pnpm test:compose-snapshot", "verify": "pnpm typecheck && pnpm lint && pnpm test", - "compose:up": "docker compose up -d --build", + "compose:up": "docker compose up -d", + "compose:build": "docker compose -f docker-compose.yml -f docker-compose.build.yml up -d --build", "compose:smoke": "docker compose exec -T app node -e \"fetch('http://127.0.0.1:8787/readyz').then(r=>process.exit(r.ok?0:1),()=>process.exit(1))\"", "compose:down": "docker compose down --remove-orphans", "compose:reset": "docker compose --profile replicas down -v --remove-orphans", From 68aa3fc8d6b8ff3336231d4144dea84ee2b5b7de Mon Sep 17 00:00:00 2001 From: DJJ Date: Sat, 19 Sep 2026 01:40:48 +0800 Subject: [PATCH 2/6] =?UTF-8?q?docs:=20=E5=9B=BA=E5=AE=9A=20GHCR=20?= =?UTF-8?q?=E9=BB=98=E8=AE=A4=E9=83=A8=E7=BD=B2=E4=B8=8E=E6=98=BE=E5=BC=8F?= =?UTF-8?q?=E6=BA=90=E7=A0=81=E6=9E=84=E5=BB=BA=E8=BE=B9=E7=95=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- llmdoc/hosts-deploy/node-docker-and-helm.mdx | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/llmdoc/hosts-deploy/node-docker-and-helm.mdx b/llmdoc/hosts-deploy/node-docker-and-helm.mdx index dedb6487..e253b8ad 100644 --- a/llmdoc/hosts-deploy/node-docker-and-helm.mdx +++ b/llmdoc/hosts-deploy/node-docker-and-helm.mdx @@ -1,5 +1,5 @@ --- -description: Node/Compose/Railway/Helm 自托管部署:零 env 安装、PG/S3 持久卷、探针与响应流排空、受限 deployment agent 与 Redis 多副本路由。 +description: Node/Compose/Railway/Helm 自托管部署:GHCR 单文件部署与显式源码构建、零 env 安装、PG/S3 持久卷、探针与响应流排空、受限 deployment agent 与 Redis 多副本路由。 kind: guide relations: related: @@ -32,6 +32,7 @@ code: - Dockerfile - Dockerfile.railway - docker-compose.yml + - docker-compose.build.yml - deploy/compose/docker-compose.yml - deploy/helm/tool-bridge/values.yaml - deploy/helm/tool-bridge/templates/deployment.yaml @@ -48,7 +49,9 @@ code: ## Compose 与镜像 -根 `docker-compose.yml` 用于本地构建,`deploy/compose/docker-compose.yml` 使用已发布镜像。默认栈包含独立 init、PG、SeaweedFS、init-bucket 与 app;镜像版本/摘要以清单为准,不在知识里手抄。init 自动生成应用/管理员数据库凭证和 S3 installer/应用凭证,最小权限文件分别只挂到需要的服务。app 只拿 bootstrap 卷,不挂 Docker socket;对象字节只在对象服务的数据卷。 +根 `docker-compose.yml` 与 `deploy/compose/docker-compose.yml` 都默认使用 GHCR 已发布镜像,单独下载清单即可部署,不依赖源码或宿主构建产物。源码开发须显式叠加 `docker-compose.build.yml`,让 app、init 与 init-bucket 使用同一本地构建镜像,避免应用与安装器版本混用;默认启动命令不触发源码构建。 + +默认栈包含独立 init、PG、SeaweedFS、init-bucket 与 app;镜像版本/摘要以清单为准,不在知识里手抄。init 自动生成应用/管理员数据库凭证和 S3 installer/应用凭证,最小权限文件分别只挂到需要的服务。app 只拿 bootstrap 卷,不挂 Docker socket;对象字节只在对象服务的数据卷。 首次启动检查 init 完成、PG/S3 可用、受保护配对、setup ready 与业务授权调用。`/healthz` 在安装态仍能成功,这是为了让安装面存活;不能把 Docker HEALTHCHECK healthy 当作安装已经完成。首次安装、重新构建应用和重启 PG/S3 是不同验收,必须分别证明身份、配置和对象字节仍可恢复。`down` 与删卷重置不同,清空卷必须是明确的数据丢弃操作。 From 6508b78a34d9c35bd5e7ff5b3b44c3fe1aef16e0 Mon Sep 17 00:00:00 2001 From: DJJ Date: Sat, 19 Sep 2026 01:40:51 +0800 Subject: [PATCH 3/6] chore(llmdoc): refresh fingerprints --- llmdoc/meta.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/llmdoc/meta.json b/llmdoc/meta.json index 02f1301f..4726d8a2 100644 --- a/llmdoc/meta.json +++ b/llmdoc/meta.json @@ -30,7 +30,7 @@ "validatedRevision": "b7c8bc5f595b8e1c781a92f8a1d95bfda78a17dc" }, "hosts-deploy/node-docker-and-helm.mdx": { - "validatedRevision": "fca74657f159c6a41b0a58abceb44243f025af5d" + "validatedRevision": "68aa3fc8d6b8ff3336231d4144dea84ee2b5b7de" }, "hosts-deploy/state-store-decision.mdx": { "validatedRevision": "fca74657f159c6a41b0a58abceb44243f025af5d" From 583d894b82967ce339798156516ee190e50de596 Mon Sep 17 00:00:00 2001 From: DJJ Date: Sat, 19 Sep 2026 01:51:52 +0800 Subject: [PATCH 4/6] =?UTF-8?q?=E4=BD=BF=E7=94=A8=E5=AE=9E=E9=99=85?= =?UTF-8?q?=E5=B7=B2=E5=8F=91=E5=B8=83=E9=95=9C=E5=83=8F=E5=B9=B6=E7=AD=89?= =?UTF-8?q?=E5=BE=85=E5=9F=BA=E7=A1=80=E8=AE=BE=E6=96=BD=E5=B0=B1=E7=BB=AA?= =?UTF-8?q?=E4=BB=A5=E9=81=BF=E5=85=8D=E5=AE=89=E8=A3=85=E5=A4=B1=E8=B4=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 本地实测原 GHCR 0.22.0 不存在,改用已发布的 0.24.0。默认 app 现在等待 PostgreSQL 健康与对象桶初始化完成,既有部署更新 Compose 后启动时序随之变化。记录先停应用再重启基础设施的流程,避免并发重启时进入 recovery。已验证空卷首次安装、鉴权、Store 字节读写和有序重启持久性;verify 与全仓 build 通过。 --- README.en.md | 10 ++++++++++ README.md | 10 ++++++++++ deploy/compose/docker-compose.yml | 6 +++++- docker-compose.yml | 6 +++++- 4 files changed, 30 insertions(+), 2 deletions(-) diff --git a/README.en.md b/README.en.md index 55e116ef..6170b153 100644 --- a/README.en.md +++ b/README.en.md @@ -76,6 +76,16 @@ docker compose -f docker-compose.yml -f docker-compose.build.yml up -d --build Both the root Compose file and [`deploy/compose/docker-compose.yml`](deploy/compose/docker-compose.yml) default to a pinned GHCR image. Source builds require the explicit [`docker-compose.build.yml`](docker-compose.build.yml) override. +To restart the full stack, use the following sequence so the app waits for a healthy PostgreSQL service and completed bucket initialization. Restarting all services simultaneously can put the app into recovery mode while the database is still starting: + +```sh +docker compose stop app +docker compose stop postgres objects +docker compose up -d +``` + +To restart only the app, use `docker compose restart app`. If the app entered recovery mode during dependency startup, restart it after the dependencies are ready to reconnect to the existing instance. + ### 2. Log in, discover, and invoke with the CLI ```sh diff --git a/README.md b/README.md index fbef34c0..29e83c38 100644 --- a/README.md +++ b/README.md @@ -76,6 +76,16 @@ docker compose -f docker-compose.yml -f docker-compose.build.yml up -d --build 根目录与 [`deploy/compose/docker-compose.yml`](deploy/compose/docker-compose.yml) 均默认使用固定版本的 GHCR 镜像;源码构建需要显式叠加 [`docker-compose.build.yml`](docker-compose.build.yml)。 +重启整套服务时,使用以下顺序,让应用在 PostgreSQL 健康、对象桶初始化完成后启动;直接同时 `restart` 全部服务可能使应用因数据库尚未就绪进入恢复态: + +```sh +docker compose stop app +docker compose stop postgres objects +docker compose up -d +``` + +仅重启应用可用 `docker compose restart app`。如果依赖服务启动期间应用已进入恢复态,待依赖就绪后重启应用即可重新连接原实例。 + ### 2. 用 CLI 登录、发现和调用 ```sh diff --git a/deploy/compose/docker-compose.yml b/deploy/compose/docker-compose.yml index 7c017b09..5707d9cf 100644 --- a/deploy/compose/docker-compose.yml +++ b/deploy/compose/docker-compose.yml @@ -1,7 +1,7 @@ name: tool-bridge x-app-image: &app-image - image: ghcr.io/tokenrollai/tool-bridge:0.22.0 + image: ghcr.io/tokenrollai/tool-bridge:0.24.0 services: init: @@ -63,6 +63,10 @@ services: depends_on: init: condition: service_completed_successfully + postgres: + condition: service_healthy + init-bucket: + condition: service_completed_successfully ports: - '127.0.0.1:8787:8787' volumes: diff --git a/docker-compose.yml b/docker-compose.yml index 7c017b09..5707d9cf 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,7 +1,7 @@ name: tool-bridge x-app-image: &app-image - image: ghcr.io/tokenrollai/tool-bridge:0.22.0 + image: ghcr.io/tokenrollai/tool-bridge:0.24.0 services: init: @@ -63,6 +63,10 @@ services: depends_on: init: condition: service_completed_successfully + postgres: + condition: service_healthy + init-bucket: + condition: service_completed_successfully ports: - '127.0.0.1:8787:8787' volumes: From 8ee80df623c5e8917dd1f0235fca4e026be72a1a Mon Sep 17 00:00:00 2001 From: DJJ Date: Sat, 19 Sep 2026 01:52:14 +0800 Subject: [PATCH 5/6] =?UTF-8?q?docs:=20=E8=A6=81=E6=B1=82=E6=A0=B8?= =?UTF-8?q?=E9=AA=8C=E9=95=9C=E5=83=8F=E4=BA=A7=E7=89=A9=E5=B9=B6=E6=98=8E?= =?UTF-8?q?=E7=A1=AE=E4=BE=9D=E8=B5=96=E9=87=8D=E5=90=AF=E8=BE=B9=E7=95=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- llmdoc/hosts-deploy/node-docker-and-helm.mdx | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/llmdoc/hosts-deploy/node-docker-and-helm.mdx b/llmdoc/hosts-deploy/node-docker-and-helm.mdx index e253b8ad..06127eb1 100644 --- a/llmdoc/hosts-deploy/node-docker-and-helm.mdx +++ b/llmdoc/hosts-deploy/node-docker-and-helm.mdx @@ -55,6 +55,8 @@ code: 首次启动检查 init 完成、PG/S3 可用、受保护配对、setup ready 与业务授权调用。`/healthz` 在安装态仍能成功,这是为了让安装面存活;不能把 Docker HEALTHCHECK healthy 当作安装已经完成。首次安装、重新构建应用和重启 PG/S3 是不同验收,必须分别证明身份、配置和对象字节仍可恢复。`down` 与删卷重置不同,清空卷必须是明确的数据丢弃操作。 +正常 `docker compose up` 在 PostgreSQL 健康、init 与 init-bucket 成功完成后才启动 app。整组重启须先完整停止 app,使 runtime 登记和租约在 PG 可达时释放,再停止 PG/S3,最后通过 `up` 恢复依赖顺序。不能从这些启动闸门推导任意并发 `restart` 或 Docker daemon 重启都能自动恢复:应用启动失败会进入 recovery,不会自动重试 launch;依赖就绪后须重启 app,并重新核验原实例身份、权限、配置与对象字节。 + 正式镜像同时携带应用、Dashboard 和官方 PG dump/restore 客户端,运行用户无 root 权限;installer 的初始化容器才执行所需 owner 设置。镜像构建不得依赖宿主已存在 dist,Node 二进制与运行基础镜像也必须匹配。runtime 基于 Node slim,安装官方 PGDG client 工具,不继承数据库 server 镜像及其隐式 VOLUME。 ## 探针、反向代理与关停 @@ -108,4 +110,6 @@ Node DeviceHub 保有本副本活 socket,DeviceRouter 通过 Redis 路由到 ## 部署验证 +预构建镜像部署须以 Registry 的实际产物核验所选标签存在且支持目标平台,通过检查 manifest 或实际拉取取得证据。Compose 配置解析、源码测试与发布 workflow 成功记录都不能替代产物核验;拉取成功仍须分别验收初始化、业务功能与持久性,不能据此宣称部署闭环完成。 + `pnpm verify` 与 `pnpm turbo run build` 是工程底线,不能替代生命周期验收:关停设置用真实子进程 SIGTERM 与未结束请求验证;维护从实际编码/别名 HTTP 入口进入,并与阻塞写入、并发 SIGTERM 组合验证写入完成和最终登记清空;真实慢响应验证 body 完成/取消/错误前的计数与背压;可选目录清空核对实际 Compose mount 与镜像内 UI。后端测试使用隔离本地 PG/S3/Redis,先完成 server.close 再删除 schema,不能为错误 teardown 顺序削弱生产租约 guard;缺 env 不静默跳过;部署还需验证持久性和失败回滚。真实平台验证遵守授权与每轮一次资源约束,证据留在验收记录,不把运行 URL、资源 ID 或测试次数写入知识。 From af6d907c6085992c066a9c8f6f86cfb2d0507609 Mon Sep 17 00:00:00 2001 From: DJJ Date: Sat, 19 Sep 2026 01:52:17 +0800 Subject: [PATCH 6/6] chore(llmdoc): refresh fingerprints --- llmdoc/meta.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/llmdoc/meta.json b/llmdoc/meta.json index 4726d8a2..74824ea1 100644 --- a/llmdoc/meta.json +++ b/llmdoc/meta.json @@ -30,7 +30,7 @@ "validatedRevision": "b7c8bc5f595b8e1c781a92f8a1d95bfda78a17dc" }, "hosts-deploy/node-docker-and-helm.mdx": { - "validatedRevision": "68aa3fc8d6b8ff3336231d4144dea84ee2b5b7de" + "validatedRevision": "8ee80df623c5e8917dd1f0235fca4e026be72a1a" }, "hosts-deploy/state-store-decision.mdx": { "validatedRevision": "fca74657f159c6a41b0a58abceb44243f025af5d"