diff --git a/AGENTS.md b/AGENTS.md index b12acd1e..deb3b292 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -8,6 +8,8 @@ OpenAgentCore is protocol-first and modular. Core orchestrates operations that p OpenAgentCore is infrastructure. Change a boundary only when the existing protocol cannot express the behavior, and make that the smallest change that leaves the design intact. Hold the code to the standard of a careful, widely used open-source service. +Keep it concise. Write elegant code that reuses existing code and standard SDKs as far as possible, and avoid redundant code. Expose nothing that does not need to be exposed: no port, route, command or setting without a caller. + ### Protocols at every boundary - Each boundary between components has exactly one protocol: one code file (interface, wire types and validators) and one document. A protocol change edits both and every implementation in one change, reviewed on its own. diff --git a/deploy/compose/ports.yaml b/deploy/compose/ports.yaml index b64424fe..7dff93ba 100644 --- a/deploy/compose/ports.yaml +++ b/deploy/compose/ports.yaml @@ -1,9 +1,6 @@ -# Host installation publishes Web and Core's loopback admin API for scripts on -# the host. Hosting platforms omit this file and route to web:8080 themselves. +# Host installation publishes Web. Hosting platforms omit this file and route +# to web:8080 themselves. services: web: ports: - "${OAC_HOST:-127.0.0.1}:${OAC_WEB_PORT:-8080}:8080" - core: - ports: - - "127.0.0.1:8091:8091" diff --git a/deploy/compose/test_compose.py b/deploy/compose/test_compose.py index acefbaaa..29bb780d 100644 --- a/deploy/compose/test_compose.py +++ b/deploy/compose/test_compose.py @@ -83,14 +83,14 @@ def test_public_url_can_be_configured_after_initial_startup(self): {service: [item.get('target') for item in spec.get('volumes', [])] for service, spec in self.compose['services'].items()}) - def test_host_ports_publish_web_and_loopback_core(self): + def test_host_ports_publish_only_web(self): env = dict(os.environ, OAC_DATA_DIR='/tmp/oac-compose-fixture', OAC_HOST='0.0.0.0') hosted = json.loads(subprocess.check_output( ['docker', 'compose', '--env-file', os.devnull, '-f', str(self.compose_file), '-f', str(ROOT / 'deploy/compose/ports.yaml'), 'config', '--format', 'json'], env=env)) published = {name: [(port.get('host_ip'), port['published']) for port in service.get('ports', [])] for name, service in hosted['services'].items() if service.get('ports')} - self.assertEqual(published, {'web': [('0.0.0.0', '8080')], 'core': [('127.0.0.1', '8091')]}) + self.assertEqual(published, {'web': [('0.0.0.0', '8080')]}) def test_platform_network_injection_keeps_the_file_valid(self): # Dokploy isolated deployments attach a project network to every service. diff --git a/deploy/install.dev.sh b/deploy/install.dev.sh index d52433a3..e6355526 100755 --- a/deploy/install.dev.sh +++ b/deploy/install.dev.sh @@ -103,11 +103,8 @@ pins = json.loads((root / "deploy/compose/smoke-pins.json").read_text()) "RELEASE_BASE": pins["release_base"], "ARCHIVE_CHECKSUM": pins["archive_checksum"], })) -# The release ports.yaml also publishes Core on 127.0.0.1:8091. A local trial -# reaches Core through Web, so only Web is published. -(dest / "ports.yaml").write_text( - "services:\n web:\n ports:\n - \"${OAC_HOST:-127.0.0.1}:${OAC_WEB_PORT:-8080}:8080\"\n") PY +cp "$repo_root/deploy/compose/ports.yaml" "$install_dir/ports.yaml" umask 077 cat >"$install_dir/.env" </dev/null 2>&1 || true + ( + cd "$install_dir" + docker compose down --remove-orphans + # Containers own data/; remove it from a container as well. + if [[ -d data ]]; then docker compose run --rm --no-deps --entrypoint find init /data -mindepth 1 -delete; fi + ) >/dev/null 2>&1 || true rm -rf "$install_dir" fi } @@ -104,7 +109,6 @@ umask 077 docker compose pull docker compose create core docker compose cp core:/usr/local/bin/oac ./oac - chmod 755 ./oac docker compose up -d --wait ) kept=1 diff --git a/docs/api/index.md b/docs/api/index.md index e970b8dc..5bef473e 100644 --- a/docs/api/index.md +++ b/docs/api/index.md @@ -12,7 +12,7 @@ Core serves three namespaces. Each has one kind of caller and its own credential A credential used in another namespace gets 401: a Project API key on `/core/v1` or `/api/v1`, the Core key on `/v1` or `/api/v1`. How Projects and keys behave is in [Projects own assets](../concepts.md#projects-own-assets). -**Routing.** Web forwards `/v1`, `/api/v1` and `/docs` to Core unchanged ([console server](../web/console-server.md)). A signed-in browser reaches `/core/v1` through Web, which adds the Core key. Operator scripts call `/core/v1` on `127.0.0.1:8091` ([script the Core API](../getting-started/operations.md#script-the-core-api)). +**Routing.** Web forwards `/v1`, `/api/v1` and `/docs` to Core unchanged ([console server](../web/console-server.md)). A signed-in browser reaches `/core/v1` through Web, which adds the Core key. Operator scripts call `/core/v1` inside Core's network namespace on the Core host ([script the Core API](../getting-started/operations.md#script-the-core-api)). **API reference.** Core serves a read-only Swagger UI of the three namespaces at `/docs`, and the documents at `/docs/openapi.yaml`, `/docs/core.openapi.yaml` and `/docs/runtime.openapi.yaml`. No credential is required, and the page sends no API requests. Open it on the console origin, for example `http://localhost:8080/docs`. The browser loads Swagger UI from `unpkg.com`. diff --git a/docs/configuration.md b/docs/configuration.md index 1b7ece19..68fe9c88 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -46,7 +46,7 @@ To change it, point the reverse proxy at the new address first, then edit `OAC_P | `OAC_PUBLIC_URL` | `http://localhost:8080` | Origin applications, nodes, sandboxes and self-hosted executors use. Managed domain setup writes the HTTPS origin and recreates Core and Web | | `OAC_HOST` | `127.0.0.1` | Address published by `ports.yaml`. `install.sh` sets `0.0.0.0` | | `OAC_WEB_PORT` | `8080` | Host port of Web | -| `COMPOSE_FILE` | `compose.yaml:ports.yaml` | The Compose files. `ports.yaml` publishes Web and Core's loopback admin API; hosting platforms omit it | +| `COMPOSE_FILE` | `compose.yaml:ports.yaml` | The Compose files. `ports.yaml` publishes Web; hosting platforms omit it | | `OAC_LOG_LEVEL` | `info` | `debug`, `info`, `warn` or `error` | | `OAC_LOG_FORMAT` | `auto` | `auto`, `text` or `json` | | `OAC_LOG_ADD_SOURCE` | unset | `1` adds source locations | @@ -135,7 +135,7 @@ The installer creates the installation directory, `~/.oac/core` by default, with | `data/state/` | Private Provider state, including E2B receipts | Core | | `.oac.lock` | The installation lock | Mutating `oac` commands | -The Compose project is named `oac-<10 hex digits>`. Its services are `init`, `database`, `core` and `web`. Core applies database migrations when it starts. `web` serves the console and forwards `/v1` and `/api/v1` to Core, and it is the only service that publishes `OAC_WEB_PORT`. Host installs also publish Core's admin API on `127.0.0.1:8091`. No service receives a Docker socket. Apart from Docker's storage, nothing is written outside the installation directory. +The Compose project is named `oac-<10 hex digits>`. Its services are `init`, `database`, `core` and `web`. Core applies database migrations when it starts. `web` serves the console and forwards `/v1` and `/api/v1` to Core, and it is the only service with a published port, `OAC_WEB_PORT`. No service receives a Docker socket. Apart from Docker's storage, nothing is written outside the installation directory. ## Appendix: Core environment without the installer diff --git a/docs/getting-started/install-options.md b/docs/getting-started/install-options.md index 98820b38..f939a441 100644 --- a/docs/getting-started/install-options.md +++ b/docs/getting-started/install-options.md @@ -70,7 +70,7 @@ The installer saves no sandbox backend. After signing in, open **System** → ** ## Listeners and access -The default installation publishes Web on `--web-port` (8080) at `--host 0.0.0.0`. Core's admin API stays on `127.0.0.1:8091`. PostgreSQL stays private. `--host` is an IPv4 or IPv6 address, without a port, scheme or zone. Use a concrete server IP in the browser, not a wildcard. +The default installation publishes Web on `--web-port` (8080) at `--host 0.0.0.0`. Core and PostgreSQL stay private. `--host` is an IPv4 or IPv6 address, without a port, scheme or zone. Use a concrete server IP in the browser, not a wildcard. `--public-url` sets `OAC_PUBLIC_URL`, the origin applications, nodes and executors use. Set it to the HTTPS origin your reverse proxy serves. diff --git a/docs/getting-started/install.md b/docs/getting-started/install.md index 6fb9d670..51074514 100644 --- a/docs/getting-started/install.md +++ b/docs/getting-started/install.md @@ -19,7 +19,7 @@ This page follows the default path. Every flag, existing reverse proxies and off - Linux amd64 and curl. - Docker Engine with Docker Compose 2.26.0 or newer (`docker compose version`). - An account that can run `docker` and write to its home directory. Ordinary users and root both work; the installer never calls sudo. -- Free port 8080 for Web. Core's admin API uses `127.0.0.1:8091`. See [ports](./install-options.md#ports). Docker must be able to publish them; the installer does not change host policy. +- Free port 8080 for Web. See [ports](./install-options.md#ports). Docker must be able to publish it; the installer does not change host policy. - For anything off this machine, the origin in `OAC_PUBLIC_URL` must be the address browsers, nodes and executors use. You can sign in on this machine first. The Core host needs no KVM; nodes that run microsandbox do. @@ -40,7 +40,7 @@ The script downloads that release's Compose files, checks their SHA-256, and: 1. checks Linux amd64, Docker Compose 2.26 or newer, and that the ports it will publish are free; 2. creates the [installation directory](../configuration.md#installation-directory), `~/.oac/core`, writes `.env`, and copies the `oac` command out of the Core image; -3. starts the services with Docker Compose. Web serves the console on port 8080 and forwards `/v1`, `/api/v1` and `/docs` to Core. Core's admin API stays on `127.0.0.1:8091`. PostgreSQL is not published. +3. starts the services with Docker Compose. Web serves the console on port 8080 and forwards `/v1`, `/api/v1` and `/docs` to Core. Core and PostgreSQL are not published. It saves no sandbox backend, adds no node, creates no Project or key and makes no model request. It ends by printing the console address and how to read the Core key. diff --git a/docs/getting-started/operations.md b/docs/getting-started/operations.md index 82e64d9f..3f8b6537 100644 --- a/docs/getting-started/operations.md +++ b/docs/getting-started/operations.md @@ -20,7 +20,7 @@ docker compose -f ~/.oac/core/compose.yaml ps | `oac apply` | Runs `oac-core check-config`, then `docker compose up -d --wait`. A failed check changes no service | | `oac core-key [--show]` | Prints the Core key path, or the key itself with `--show` | | `oac rotate-core-key` | Replaces the Core key and restarts Core and Web | -| `docker compose down --rmi all` | Removes the containers and images. Delete the installation directory afterwards | +| `docker compose down` | Removes the containers. Data is kept; to delete it, [uninstall](#uninstall) | For a second installation, use its directory, such as `~/.oac/second`. @@ -70,14 +70,15 @@ Keep it private. Web reads `data/secrets/web/core.key`. Core reads only its SHA- ### Script the Core API -Run scripts on the Core host against Core's loopback port. This helper reads the key from its file, keeping it off the command line: +Core publishes no host port. On the Core host, this helper runs `curl` in Core's network namespace and passes the key on stdin, keeping it off the command line: ```sh -core() { # core METHOD PATH [JSON body] - curl -fsS -X "$1" "http://127.0.0.1:8091/core/v1$2" \ - -H @<(printf 'Authorization: Bearer %s\n' "$(~/.oac/core/oac core-key --show)") \ - -H 'Content-Type: application/json' ${3:+-d "$3"} -} +core() ( # core METHOD PATH [JSON body] + cd ~/.oac/core + ./oac core-key --show | sed 's/^/Authorization: Bearer /' | + docker run -i --rm --network "container:$(docker compose ps -q core)" curlimages/curl \ + -fsS -X "$1" "http://127.0.0.1:8091/core/v1$2" -H @- -H 'Content-Type: application/json' ${3:+-d "$3"} +) ``` | Task | Command | @@ -136,11 +137,14 @@ Never prune Docker volumes or delete native harness history to make a retry pass ## Uninstall ```sh -docker compose -f ~/.oac/core/compose.yaml down --rmi all --remove-orphans -rm -rf ~/.oac/core +cd ~/.oac/core +docker compose down --remove-orphans +docker compose run --rm --no-deps --entrypoint find init /data -mindepth 1 -delete +docker compose down --rmi all +cd && rm -rf ~/.oac/core ``` -`down` removes the containers and images. `rm` removes the installation directory. Do the first only when you mean to delete the data. +The containers own `data/`, so the `init` image deletes its contents; then `down --rmi all` removes the images and `rm` removes the installation directory. Run these only when you mean to delete the data. All data goes with it: Projects and API keys, Session history, stored credentials and the Core key. To keep the data, stop the installation with `docker compose stop` instead, or [back it up](#back-up) first. @@ -183,7 +187,7 @@ Mutating `oac` commands hold `.oac.lock`. If another command holds it, retry aft | Listener | Host installation | Behind a reverse proxy | | --- | --- | --- | | Web and the API | Web publishes `OAC_WEB_PORT` (8080) on `OAC_HOST` | Web publishes `OAC_WEB_PORT` on `OAC_HOST`. Your proxy should use `127.0.0.1` | -| Core admin API | `127.0.0.1:8091`. Web forwards `/v1`, `/api/v1` and `/docs` | `127.0.0.1:8091`. Web forwards `/v1`, `/api/v1` and `/docs` | +| Core | No published port. Web forwards `/v1`, `/api/v1` and `/docs` | No published port. Web forwards `/v1`, `/api/v1` and `/docs` | | PostgreSQL | No published port | No published port | Web signs administrators in with the Core key, checks the origin of every request, and forwards signed-in `/core/v1` requests to Core with the Core key, which stays on the server. It forwards `/v1` and `/api/v1` to Core unchanged, with the caller's own credential, serves only the non-secret node payload at `/node-install/`, and has no Docker or KVM access. Machine routes under `/api/v1` use their own enrollment and connection credentials. No service receives a Docker socket. diff --git a/docs/zh/api/index.md b/docs/zh/api/index.md index 3fb10387..21b217dc 100644 --- a/docs/zh/api/index.md +++ b/docs/zh/api/index.md @@ -1,7 +1,7 @@ --- title: "API 命名空间和凭据" source: docs/api/index.md -source_hash: 922ad1d9b3ea7549aa6b845847f8e0278a637a1b986d41b264b9cf892429a8df +source_hash: 11df05084e85f1bc05650e11c2c744318b92ba7ac90280207956fce712335122 --- Core 提供三个命名空间。每个命名空间都有一种调用方及其独立凭据,凭据只能在其所属命名空间中使用。 @@ -14,7 +14,7 @@ Core 提供三个命名空间。每个命名空间都有一种调用方及其独 在其他命名空间中使用凭据会返回 401:在 `/core/v1` 或 `/api/v1` 上使用 Project API key,或者在 `/v1` 或 `/api/v1` 上使用 Core key。有关 Project 和密钥的行为,请参阅 [Project 自有资产](../concepts.md#projects-own-assets)。 -**路由。** Web 把 `/v1`、`/api/v1` 和 `/docs` 原样转发到 Core([控制台服务器](../web/console-server.md))。已登录的浏览器通过 Web 访问 `/core/v1`,由 Web 附上 Core key。操作员脚本在 `127.0.0.1:8091` 调用 `/core/v1`([编写 Core API 脚本](../getting-started/operations.md#script-the-core-api))。 +**路由。** Web 把 `/v1`、`/api/v1` 和 `/docs` 原样转发到 Core([控制台服务器](../web/console-server.md))。已登录的浏览器通过 Web 访问 `/core/v1`,由 Web 附上 Core key。操作员脚本在 Core 主机上从 Core 的网络命名空间内调用 `/core/v1`([编写 Core API 脚本](../getting-started/operations.md#script-the-core-api))。 **API 参考。** Core 在 `/docs` 提供三个命名空间的只读 Swagger UI,文档位于 `/docs/openapi.yaml`、`/docs/core.openapi.yaml` 和 `/docs/runtime.openapi.yaml`。不需要凭据,页面也不发送 API 请求。在控制台源地址打开,例如 `http://localhost:8080/docs`。浏览器从 `unpkg.com` 加载 Swagger UI。 diff --git a/docs/zh/configuration.md b/docs/zh/configuration.md index 3adf643e..fb742b5d 100644 --- a/docs/zh/configuration.md +++ b/docs/zh/configuration.md @@ -1,7 +1,7 @@ --- title: "配置参考" source: docs/configuration.md -source_hash: 610b3a85b453d00b575f9fb4d42c87ec89dc3803bb238fd4c36ef734aba6c7e2 +source_hash: 62ad7f6c64329e0d3e9bda9b4936f5c13281eb18a1011b057b2f6288ddad35cc --- Core 安装的每项设置都恰好只有一个归属位置。共有两类: @@ -50,7 +50,7 @@ Web 的 **System** 页面显示该安装的地址、默认模型和沙箱配置 | `OAC_PUBLIC_URL` | `http://localhost:8080` | Origin applications, nodes, sandboxes and self-hosted executors use. Managed domain setup writes the HTTPS origin and recreates Core and Web | | `OAC_HOST` | `127.0.0.1` | Address published by `ports.yaml`. `install.sh` sets `0.0.0.0` | | `OAC_WEB_PORT` | `8080` | Host port of Web | -| `COMPOSE_FILE` | `compose.yaml:ports.yaml` | The Compose files. `ports.yaml` publishes Web and Core's loopback admin API; hosting platforms omit it | +| `COMPOSE_FILE` | `compose.yaml:ports.yaml` | Compose 文件。`ports.yaml` 发布 Web;托管平台省略它 | | `OAC_LOG_LEVEL` | `info` | `debug`, `info`, `warn` or `error` | | `OAC_LOG_FORMAT` | `auto` | `auto`, `text` or `json` | | `OAC_LOG_ADD_SOURCE` | unset | `1` adds source locations | @@ -139,7 +139,7 @@ Web 的 **System** 页面显示该安装的地址、默认模型和沙箱配置 | `data/state/` | 私有 Provider 状态,包括 E2B 回执 | Core | | `.oac.lock` | 安装锁 | 会修改安装状态的 `oac` 命令 | -Compose 项目名为 `oac-<10 hex digits>`。服务包括 `init`、`database`、`core` 和 `web`。Core 启动时执行数据库迁移。`web` 提供控制台并把 `/v1` 和 `/api/v1` 转发到 Core,是唯一发布 `OAC_WEB_PORT` 的服务。主机安装还把 Core 的管理 API 发布在 `127.0.0.1:8091`。没有服务持有 Docker 套接字。除 Docker 存储外,不会向安装目录之外写入任何内容。 +Compose 项目名为 `oac-<10 hex digits>`。服务包括 `init`、`database`、`core` 和 `web`。Core 启动时执行数据库迁移。`web` 提供控制台并把 `/v1` 和 `/api/v1` 转发到 Core,是唯一发布端口(`OAC_WEB_PORT`)的服务。没有服务持有 Docker 套接字。除 Docker 存储外,不会向安装目录之外写入任何内容。 ## 附录:没有安装程序时的 Core 环境 {#appendix-core-environment-without-the-installer} diff --git a/docs/zh/getting-started/install-options.md b/docs/zh/getting-started/install-options.md index a5ddaf3a..11bd0df5 100644 --- a/docs/zh/getting-started/install-options.md +++ b/docs/zh/getting-started/install-options.md @@ -1,7 +1,7 @@ --- title: "安装选项与高级部署" source: docs/getting-started/install-options.md -source_hash: f9a5aae96ce8789030eda5cb399eac7c2e6bc6bd4d9bcce18138373c97cb0e96 +source_hash: be5e1a127f654e75611c7b670fba9fc10cb3b78165590a7f6616eb1b79dd2f14 --- [默认安装](install.md)无需任何选项。使用本页可以在现有反向代理后运行,或者在无法访问互联网时进行安装。 @@ -74,7 +74,7 @@ docker compose -f compose.yaml exec web oac-web core-key ## 监听器与访问 {#listeners-and-access} -默认安装在 `--host 0.0.0.0` 的 `--web-port`(8080)上发布 Web。Core 的管理 API 留在 `127.0.0.1:8091`。PostgreSQL 保持私有。`--host` 是不含端口、协议或区域的 IPv4 或 IPv6 地址。请在浏览器中使用服务器的具体 IP,而不是通配地址。 +默认安装在 `--host 0.0.0.0` 的 `--web-port`(8080)上发布 Web。Core 和 PostgreSQL 保持私有。`--host` 是不含端口、协议或区域的 IPv4 或 IPv6 地址。请在浏览器中使用服务器的具体 IP,而不是通配地址。 `--public-url` 设置 `OAC_PUBLIC_URL`,即应用、节点和执行器使用的源地址。把它设为反向代理提供的 HTTPS 源地址。 @@ -91,12 +91,6 @@ docker compose -f compose.yaml exec web oac-web core-key 请用 `--host 127.0.0.1` 安装,并把反向代理指向 Web,默认是 `127.0.0.1:8080`。Web 把 `/v1`、`/api/v1` 和 `/docs` 转到 Core,其余由自己提供。 -| 路径 | 目标 | 调用方 | -| --- | --- | --- | -| `/v1`、`/v1/*` | Core,默认为 `127.0.0.1:8091` | 应用程序,使用 Project API 密钥 | -| `/api/v1/*` | Core,`127.0.0.1:8091` | 节点、沙箱和自托管机器。使用 WebSockets | -| 其他所有路径 | Web,默认为 `127.0.0.1:8080` | 浏览器,以及通过 `/node-install/*` 访问的节点安装程序 | - 反向代理必须: - **保留 Host。** Web 仅接受 `OAC_PUBLIC_URL` 中的主机。 diff --git a/docs/zh/getting-started/install.md b/docs/zh/getting-started/install.md index 519ab41d..7f4c148a 100644 --- a/docs/zh/getting-started/install.md +++ b/docs/zh/getting-started/install.md @@ -1,7 +1,7 @@ --- title: "安装 Core 和 Web" source: docs/getting-started/install.md -source_hash: 3493948d1e7111fb5c26a134c0f8848d8984b68fd135559903e0729c25832643 +source_hash: 63db48e9ac2b0f64b773b7271511c95dc44121ff29f303a738f124ec8c76c8a3 --- 一条命令即可在 Linux 主机上安装 Core、Web 控制台和 PostgreSQL。用 Core 密钥登录 Web,设置默认模型并签发 Project API 密钥。应用使用这些密钥调用 Core。Session 在你添加的节点上的沙箱中运行,也可以在 E2B 上运行。 @@ -21,7 +21,7 @@ source_hash: 3493948d1e7111fb5c26a134c0f8848d8984b68fd135559903e0729c25832643 - Linux amd64 和 curl。 - Docker Engine 和 Docker Compose 2.26.0 或更高版本(`docker compose version`)。 - 能运行 `docker` 并向自己的主目录写入文件的账号。普通用户和 root 均可;安装程序不会调用 sudo。 -- Web 的 8080 端口空闲。Core 的管理 API 使用 `127.0.0.1:8091`。参阅[端口](install-options.md#ports)。Docker 必须能发布这些端口;安装程序不会修改主机策略。 +- Web 的 8080 端口空闲。参阅[端口](install-options.md#ports)。Docker 必须能发布该端口;安装程序不会修改主机策略。 - 本机以外的访问要求 `OAC_PUBLIC_URL` 就是浏览器、节点和执行器使用的地址。可以先在本机登录。 Core 主机不需要 KVM;运行 microsandbox 的节点需要。 @@ -42,7 +42,7 @@ curl -fsSL https://github.com/MiniMax-AI/OpenAgentCore/releases/latest/download/ 1. 检查 Linux amd64、Docker Compose 2.26 或更高版本,以及将要发布的端口是否空闲; 2. 创建[安装目录](../configuration.md#installation-directory) `~/.oac/core`,写入 `.env`,并从 Core 镜像复制 `oac` 命令; -3. 用 Docker Compose 启动服务。Web 在 8080 端口提供控制台,并把 `/v1`、`/api/v1` 和 `/docs` 转发到 Core。Core 的管理 API 留在 `127.0.0.1:8091`。PostgreSQL 不发布端口。 +3. 用 Docker Compose 启动服务。Web 在 8080 端口提供控制台,并把 `/v1`、`/api/v1` 和 `/docs` 转发到 Core。Core 和 PostgreSQL 不发布端口。 安装程序不保存沙箱后端,不添加节点,不创建 Project 或密钥,也不发起模型请求。完成后输出控制台地址,以及如何读取 Core 密钥。 diff --git a/docs/zh/getting-started/operations.md b/docs/zh/getting-started/operations.md index 3473cc47..4a3755df 100644 --- a/docs/zh/getting-started/operations.md +++ b/docs/zh/getting-started/operations.md @@ -1,7 +1,7 @@ --- title: "管理你的安装" source: docs/getting-started/operations.md -source_hash: 83db2aebab621e41ab45ad92fc74ec562c54bf0f6a5a4cd845b5ffe8da50cf89 +source_hash: e87c7a1e577b8732929bb1c1fead1d54abfe6b607d8c4aed43faf38dca405ed5 --- 安装运维人员负责 Core 主机、存储和可用性。节点主机运行各自的服务;参阅[节点](nodes.md)。设置见[配置参考](../configuration.md)。 @@ -22,7 +22,7 @@ docker compose -f ~/.oac/core/compose.yaml ps | `oac apply` | 先运行 `oac-core check-config`,再执行 `docker compose up -d --wait`。校验失败时不改动任何服务 | | `oac core-key [--show]` | 打印 Core 密钥路径;加上 `--show` 时打印密钥本身 | | `oac rotate-core-key` | 替换 Core 密钥并重启 Core 和 Web | -| `docker compose down --rmi all` | 移除容器和镜像。然后删除安装目录 | +| `docker compose down` | 移除容器。数据保留;要删除数据,请[卸载](#uninstall) | 第二个安装使用自己的目录,例如 `~/.oac/second`。 @@ -72,14 +72,15 @@ Web 重启(包括 `oac apply` 引起的重启)会让所有控制台用户退 ### 用脚本调用 Core API {#script-the-core-api} -在 Core 主机上运行脚本,访问 Core 回环端口。此辅助函数从文件读取密钥,使其不进入命令行: +Core 不发布主机端口。在 Core 主机上,此辅助函数在 Core 的网络命名空间中运行 `curl`,并通过 stdin 传入密钥,使其不进入命令行: ```sh -core() { # core METHOD PATH [JSON body] - curl -fsS -X "$1" "http://127.0.0.1:8091/core/v1$2" \ - -H @<(printf 'Authorization: Bearer %s\n' "$(~/.oac/core/oac core-key --show)") \ - -H 'Content-Type: application/json' ${3:+-d "$3"} -} +core() ( # core METHOD PATH [JSON body] + cd ~/.oac/core + ./oac core-key --show | sed 's/^/Authorization: Bearer /' | + docker run -i --rm --network "container:$(docker compose ps -q core)" curlimages/curl \ + -fsS -X "$1" "http://127.0.0.1:8091/core/v1$2" -H @- -H 'Content-Type: application/json' ${3:+-d "$3"} +) ``` | 任务 | 命令 | @@ -139,11 +140,14 @@ Core 记录每次公开资源写入所使用的密钥;历史保留策略为 [` ## 卸载 {#uninstall} ```sh -docker compose -f ~/.oac/core/compose.yaml down --rmi all --remove-orphans -rm -rf ~/.oac/core +cd ~/.oac/core +docker compose down --remove-orphans +docker compose run --rm --no-deps --entrypoint find init /data -mindepth 1 -delete +docker compose down --rmi all +cd && rm -rf ~/.oac/core ``` -`down` 移除容器和镜像。`rm` 删除安装目录。只有确定要删数据时才执行第一条。 +`data/` 归容器所有,因此由 `init` 镜像删除其内容;随后 `down --rmi all` 移除镜像,`rm` 删除安装目录。只有确定要删数据时才执行这些命令。 全部数据随之删除:Project 和 API 密钥、Session 历史、存储的凭据和 Core 密钥。要保留数据,请用 `docker compose stop` 停止安装,或先[备份](#back-up)。 @@ -186,7 +190,7 @@ rm -rf ~/.oac/core | 监听器 | 主机安装 | 反向代理之后 | | --- | --- | --- | | Web 和 API | Web 在 `OAC_HOST` 上发布 `OAC_WEB_PORT`(8080) | Web 在 `OAC_HOST` 上发布 `OAC_WEB_PORT`。反向代理应使用 `127.0.0.1` | -| Core 管理 API | `127.0.0.1:8091`。Web 转发 `/v1`、`/api/v1` 和 `/docs` | `127.0.0.1:8091`。Web 转发 `/v1`、`/api/v1` 和 `/docs` | +| Core | 不发布端口。Web 转发 `/v1`、`/api/v1` 和 `/docs` | 不发布端口。Web 转发 `/v1`、`/api/v1` 和 `/docs` | | PostgreSQL | 不发布端口 | 不发布端口 | Web 使用 Core 密钥让管理员登录,检查每个请求来源,并用保留在服务器上的 Core 密钥将已登录的 `/core/v1` 请求转发到 Core。它把 `/v1` 和 `/api/v1` 原样转发给 Core,使用调用方自己的凭据;Web 仅在 `/node-install/` 提供不含密钥的节点文件,没有 Docker 或 KVM 访问权限。`/api/v1` 机器路由使用独立注册和连接凭据。没有服务持有 Docker 套接字。 diff --git a/services/core/cmd/oac/init.go b/services/core/cmd/oac/init.go index 07fd9a70..3d9f3a68 100644 --- a/services/core/cmd/oac/init.go +++ b/services/core/cmd/oac/init.go @@ -302,24 +302,3 @@ func randomBytes(n int) []byte { } func randomHex(n int) string { return hex.EncodeToString(randomBytes(n)) } - -// healthcheck reports the installation healthy once Core, Web and Web's own -// listener answer. -func healthcheck(ctx context.Context) error { - client := &http.Client{Timeout: 3 * time.Second, Transport: &http.Transport{Proxy: nil}} - for _, host := range []string{"core:8091", "127.0.0.1:8080"} { - request, err := http.NewRequestWithContext(ctx, http.MethodGet, "http://"+host+"/healthz", nil) - if err != nil { - return err - } - response, err := client.Do(request) - if err != nil { - return err - } - response.Body.Close() - if response.StatusCode != http.StatusOK { - return fmt.Errorf("%s returned HTTP %d", host, response.StatusCode) - } - } - return nil -} diff --git a/services/core/cmd/oac/main.go b/services/core/cmd/oac/main.go index f660bb33..f18683d9 100644 --- a/services/core/cmd/oac/main.go +++ b/services/core/cmd/oac/main.go @@ -32,15 +32,13 @@ func main() { var buildRevision = "development" func usage() { - fmt.Fprintf(os.Stderr, "oac (%s)\nUsage: oac apply|core-key|rotate-core-key|init|healthcheck\n", buildRevision) + fmt.Fprintf(os.Stderr, "oac (%s)\nUsage: oac apply|core-key|rotate-core-key|init\n", buildRevision) } func run(ctx context.Context, command string, args []string) error { switch command { case "init": return initCommand(ctx) - case "healthcheck": - return healthcheck(ctx) } root, err := installDir() if err != nil {