Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions deploy/compose/compose.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# Release template. The publisher pins the initialization image to this release.
# Core and Web default to latest; OAC_IMAGE_* selects another reference.
# Release images are pinned; OAC_IMAGE_* selects another reference.
# Docker owns data permissions on every host platform.
x-ingress-image: &ingress-image ${OAC_IMAGE_INGRESS:-__OAC_INIT_IMAGE__}
services:
Expand Down Expand Up @@ -42,7 +42,7 @@ services:
retries: 30

core:
image: ${OAC_IMAGE_CORE:-ghcr.io/minimax-ai/openagentcore/core:latest}
image: ${OAC_IMAGE_CORE:-__OAC_CORE_IMAGE__}
user: "65532:65532"
restart: unless-stopped
read_only: true
Expand Down Expand Up @@ -89,7 +89,7 @@ services:
published: "${OAC_WEB_PORT:-8080}"
host_ip: "${OAC_HOST:-127.0.0.1}"
protocol: tcp
image: ${OAC_IMAGE_WEB:-ghcr.io/minimax-ai/openagentcore/web:latest}
image: ${OAC_IMAGE_WEB:-__OAC_WEB_IMAGE__}
user: "65532:65532"
restart: unless-stopped
read_only: true
Expand Down
4 changes: 3 additions & 1 deletion deploy/compose/test_compose.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ def rendered_compose(directory):
text = render_compose.render({
'REVISION': 'd' * 40,
'INIT_IMAGE': 'ghcr.io/minimax-ai/openagentcore/ingress@sha256:' + 'e' * 64,
'CORE_IMAGE': 'ghcr.io/minimax-ai/openagentcore/core@sha256:' + 'e' * 64,
'WEB_IMAGE': 'ghcr.io/minimax-ai/openagentcore/web@sha256:' + 'e' * 64,
})
path = Path(directory) / 'compose.yaml'
path.write_text(text)
Expand Down Expand Up @@ -58,7 +60,7 @@ def test_compose_uses_private_services_and_ordered_initialization(self):
self.assertNotIn('build', service)
if service is not services['web']:
self.assertNotIn('ports', service)
self.assertTrue(service['image'].endswith(':latest') or service['image'] == 'postgres:16-alpine' or service['image'].endswith('@sha256:' + 'e' * 64))
self.assertTrue(service['image'] == 'postgres:16-alpine' or service['image'].endswith('@sha256:' + 'e' * 64))
for volume in service.get('volumes', []):
self.assertNotIn('docker.sock', json.dumps(volume))
self.assertEqual(volume['type'], 'volume')
Expand Down
2 changes: 2 additions & 0 deletions deploy/install-source.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ def install(bundle, destination, host, port, public_url):
for name in files:
os.chmod(Path(root) / name, 0o644)
template = (bundle / 'compose.yaml.template').read_text().replace('__OAC_REVISION__', revision).replace('__OAC_INIT_IMAGE__', images['ingress'])
for name in ('core', 'web'):
template = template.replace('__OAC_' + name.upper() + '_IMAGE__', images[name])
override = {'services': {name: {'image': images[image]} for name, image in
(('core', 'core'), ('web', 'web'), ('init', 'ingress'), ('database', 'database'))}}
override['services']['web']['volumes'] = [{'type': 'bind', 'source': str(payload), 'target': '/node-payload', 'read_only': True}]
Expand Down
1 change: 1 addition & 0 deletions deploy/test_install_source.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ def install(self):

def test_complete_compose_preserves_secrets_and_serves_whole_payload(self):
self.install()
self.assertNotIn('__OAC_', (self.destination / 'compose.yaml').read_text())
config = json.loads(subprocess.check_output(['docker', 'compose', 'config', '--format', 'json'], cwd=self.destination, text=True))
services = config['services']
for name in ('core', 'web', 'database', 'init'):
Expand Down
2 changes: 1 addition & 1 deletion docs/getting-started/install-options.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ On Windows, download `install.ps1` and pass the same flags with `& ./install.ps1

## Docker Compose and hosting platforms

Use the `compose.yaml` from a release on any [supported Core host](./install.md#prerequisites). The release pins its initialization image and source revision in the [Compose template](https://github.com/MiniMax-AI/OpenAgentCore/blob/main/deploy/compose/compose.yaml). Core and Web use the `latest` images, and PostgreSQL uses `postgres:16-alpine`. It starts PostgreSQL, Core and Web. Web forwards `/v1` and `/api/v1` to Core. Data lives in a named Docker volume. The one-time initialization service generates random secrets there and prepares the node installer; Core applies database migrations when it starts. [Compose configuration](../configuration.md#compose-installations) owns the settings and the data directory.
Use the `compose.yaml` from a release on any [supported Core host](./install.md#prerequisites). The release pins its initialization, Core and Web images and source revision in the [Compose template](https://github.com/MiniMax-AI/OpenAgentCore/blob/main/deploy/compose/compose.yaml). PostgreSQL uses `postgres:16-alpine`. It starts PostgreSQL, Core and Web. Web forwards `/v1` and `/api/v1` to Core. Data lives in a named Docker volume. The one-time initialization service generates random secrets there and prepares the node installer; Core applies database migrations when it starts. [Compose configuration](../configuration.md#compose-installations) owns the settings and the data directory.

For a local trial, download `compose.yaml` from a release into an empty directory, then run:

Expand Down
2 changes: 1 addition & 1 deletion docs/maintainers.md
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ Distribution and Runtime archives use `pigz` level 6 with at most four compressi

### Container registry

Version releases and manual `build-<full SHA>` drafts publish `ghcr.io/minimax-ai/openagentcore/<component>:<version>`, where `<component>` is `core`, `web`, `runtime` or `ingress`. Core, Web and ingress indexes contain Linux amd64 and arm64 images; Runtime contains Linux amd64. Platform images use `<version>-<architecture>` tags and are loaded from the release archives. Existing version tags must match the release images and platform set. The publisher verifies every version index before updating `latest` for a stable release; prereleases and drafts leave `latest` unchanged. PostgreSQL uses its upstream image. SemVer build metadata uses `_` in place of `+` in container tags; version strings are limited to 128 characters. After verifying the images, the publisher uploads the release's `compose.yaml` and checksum list. Compose pins ingress by its index digest, and initialization checks its build revision against the Compose revision.
Version releases and manual `build-<full SHA>` drafts publish `ghcr.io/minimax-ai/openagentcore/<component>:<version>`, where `<component>` is `core`, `web`, `runtime` or `ingress`. Core, Web and ingress indexes contain Linux amd64 and arm64 images; Runtime contains Linux amd64. Platform images use `<version>-<architecture>` tags and are loaded from the release archives. Existing version tags must match the release images and platform set. The publisher verifies every version index before updating `latest` for a stable release; prereleases and drafts leave `latest` unchanged. PostgreSQL uses its upstream image. SemVer build metadata uses `_` in place of `+` in container tags; version strings are limited to 128 characters. After verifying the images, the publisher uploads the release's `compose.yaml` and checksum list. Compose pins Core, Web and ingress by their release index digests, and initialization checks its build revision against the Compose revision.

The combined build/publication job uses `GITHUB_TOKEN` with `packages: write`. On the first publication, GitHub creates each container package as private: a package administrator must change all four packages to **Public** in their package settings before users can pull anonymously. See [GitHub container visibility](https://docs.github.com/en/packages/working-with-a-github-packages-registry/working-with-the-container-registry). Verify an unauthenticated pull after changing visibility. Repository visibility alone does not make a new container package public.

Expand Down
4 changes: 2 additions & 2 deletions docs/zh/getting-started/install-options.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
---
title: "安装选项"
source: docs/getting-started/install-options.md
source_hash: 698909d30bf0ebdff2656deb6a6cb00c18181e835e2c1a7972de0d1e7ca47733
source_hash: 7423324720152cc6c58459f3e60b3cb61f5c97ae291ff33867f1e90172831e91
---

[默认安装](install.md)无需任何选项。本页介绍安装选项、Compose 部署和反向代理配置。
Expand All @@ -16,7 +16,7 @@ Windows 可下载 `install.ps1`,然后使用相同参数,例如 `& ./install

## Docker Compose 与托管平台 {#docker-compose-and-hosting-platforms}

在任一[支持的 Core 主机](install.md#prerequisites)上使用发行版中的 `compose.yaml`。发行流程会在 [Compose 模板](https://github.com/MiniMax-AI/OpenAgentCore/blob/main/deploy/compose/compose.yaml)中固定初始化镜像及源码版本。Core 和 Web 使用 `latest` 镜像,PostgreSQL 使用 `postgres:16-alpine`。它会启动 PostgreSQL、Core 和 Web。Web 把 `/v1` 和 `/api/v1` 转发到 Core。数据保存在 Docker 命名卷中。一次性初始化服务会在该目录中生成随机机密信息并准备节点安装程序;Core 启动时执行数据库迁移。[Compose 配置](../configuration.md#compose-installations)负责管理各项设置和数据目录。
在任一[支持的 Core 主机](install.md#prerequisites)上使用发行版中的 `compose.yaml`。发行流程会在 [Compose 模板](https://github.com/MiniMax-AI/OpenAgentCore/blob/main/deploy/compose/compose.yaml)中固定初始化、Core 和 Web 镜像及源码版本。PostgreSQL 使用 `postgres:16-alpine`。它会启动 PostgreSQL、Core 和 Web。Web 把 `/v1` 和 `/api/v1` 转发到 Core。数据保存在 Docker 命名卷中。一次性初始化服务会在该目录中生成随机机密信息并准备节点安装程序;Core 启动时执行数据库迁移。[Compose 配置](../configuration.md#compose-installations)负责管理各项设置和数据目录。

进行本地试用时,请将发行版的 `compose.yaml` 下载到一个空目录,然后运行:

Expand Down
4 changes: 2 additions & 2 deletions docs/zh/maintainers.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
---
title: "构建并发布 OpenAgentCore"
source: docs/maintainers.md
source_hash: e575ad6ef718ce7791f9b6b1ac05467a0a98923512e17b05d3ffab2e75fcfc74
source_hash: 402a990e859cb3fb0155e2b4e60421cd841de88f84a49b678eb918450b253114
---

本指南面向负责构建和发布 OpenAgentCore 的维护者。要安装 Core 和 Web,请使用 [安装指南](getting-started/install.md)。安装器代码遵循的规则见 [部署](https://github.com/MiniMax-AI/OpenAgentCore/blob/main/deploy/README.md) 和 [节点安装器](https://github.com/MiniMax-AI/OpenAgentCore/blob/main/deploy/node/README.md);必需检查见 [CONTRIBUTING](https://github.com/MiniMax-AI/OpenAgentCore/blob/main/CONTRIBUTING.md#required-checks)。
Expand Down Expand Up @@ -140,7 +140,7 @@ git push origin v1.2.3

### 容器注册表 {#container-registry}

版本发布和手动 `build-<full SHA>` 草稿使用 `ghcr.io/minimax-ai/openagentcore/<component>:<version>`,其中 `<component>` 为 `core`、`web`、`runtime` 或 `ingress`。Core、Web 和 ingress 索引包含 Linux amd64 和 arm64 镜像,Runtime 包含 Linux amd64。各平台镜像使用 `<version>-<architecture>` 标签,从发行归档加载。已有版本标签必须与发行镜像及平台集合一致。发布器校验全部版本索引后,才为稳定版更新 `latest`;预发布版和草稿保持 `latest` 不变。PostgreSQL 使用上游镜像。容器标签中的 SemVer 构建元数据用 `_` 替换 `+`,版本字符串上限为 128 个字符。镜像校验后,发布器上传该版本的 `compose.yaml` 和校验和清单。Compose 用索引摘要固定 ingress,初始化时检查其构建版本与 Compose 版本一致。
版本发布和手动 `build-<full SHA>` 草稿使用 `ghcr.io/minimax-ai/openagentcore/<component>:<version>`,其中 `<component>` 为 `core`、`web`、`runtime` 或 `ingress`。Core、Web 和 ingress 索引包含 Linux amd64 和 arm64 镜像,Runtime 包含 Linux amd64。各平台镜像使用 `<version>-<architecture>` 标签,从发行归档加载。已有版本标签必须与发行镜像及平台集合一致。发布器校验全部版本索引后,才为稳定版更新 `latest`;预发布版和草稿保持 `latest` 不变。PostgreSQL 使用上游镜像。容器标签中的 SemVer 构建元数据用 `_` 替换 `+`,版本字符串上限为 128 个字符。镜像校验后,发布器上传该版本的 `compose.yaml` 和校验和清单。Compose 用对应发行版的索引摘要固定 Core、Web 和 ingress,初始化时检查其构建版本与 Compose 版本一致。

合并的构建/发布作业使用具有 `packages: write` 权限的 `GITHUB_TOKEN`。首次发布时,GitHub 会将每个容器软件包创建为私有:软件包管理员必须先在各自的软件包设置中将全部四个软件包改为 **Public**,用户才能匿名拉取。请参阅 [GitHub container visibility](https://docs.github.com/en/packages/working-with-a-github-packages-registry/working-with-the-container-registry)。更改可见性后,请验证未认证拉取。仅更改仓库可见性并不会使新的容器软件包变为公开。

Expand Down
2 changes: 2 additions & 0 deletions scripts/compose-smoke.py
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,8 @@ def main():
rendered.write_text(render_compose.render({
'REVISION': pins['revision'],
'INIT_IMAGE': 'ghcr.io/minimax-ai/openagentcore/ingress@sha256:' + '0' * 64,
'CORE_IMAGE': 'ghcr.io/minimax-ai/openagentcore/core@sha256:' + '0' * 64,
'WEB_IMAGE': 'ghcr.io/minimax-ai/openagentcore/web@sha256:' + '0' * 64,
}))
override = directory / 'offline-init.json'
images = build_images(directory, project.removeprefix('oac-smoke-'))
Expand Down
2 changes: 2 additions & 0 deletions scripts/publish-core-release.py
Original file line number Diff line number Diff line change
Expand Up @@ -302,6 +302,8 @@ def upload(path):
compose_files = render_compose.write_assets(assets, {
"REVISION": revision,
"INIT_IMAGE": images["ingress"]["digest"],
"CORE_IMAGE": images["core"]["digest"],
"WEB_IMAGE": images["web"]["digest"],
})
expected.update({path.name: path.stat().st_size for path in compose_files})
parallel_each(upload, compose_files)
Expand Down
15 changes: 15 additions & 0 deletions scripts/publish-core-release.test.py
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,21 @@ def test_version_tag_publishes_complete_fixed_id(self):
self.assertEqual(self.api.call_args.args[1:],
("releases/7", "--method", "PATCH", "-F", "draft=false"))

def test_compose_defaults_use_published_images_for_every_release_mode(self):
for tag, mode in (("v1.2.3", "publish"), ("v1.2.3-rc.1", "publish"),
("build-" + self.revision, "draft")):
with self.subTest(tag=tag):
# Each publication starts with the original build assets.
for name in ("compose.yaml", "compose-sha256sums.txt"):
(self.assets / name).unlink(missing_ok=True)
self.publish(tag=tag, mode=mode)
compose = (self.assets / "compose.yaml").read_text()
for name in ("core", "web", "ingress"):
self.assertIn("${OAC_IMAGE_" + name.upper() + ":-" +
self.images.return_value[name]["digest"] + "}", compose)
self.assertNotIn(":latest", compose)
self.assertNotIn("__OAC_", compose)

def test_repository_rename_uses_current_identity_before_writes(self):
self.context_repository = "MiniMax-AI/previous-name"
self.publish()
Expand Down
9 changes: 5 additions & 4 deletions scripts/render-compose.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#!/usr/bin/env python3
"""Fill the Compose template with one release's node metadata.

The template is deploy/compose/compose.yaml. The initialization image is pinned; Core and Web default to latest. A release publishes the rendered file; this script does not run Docker.
The template is deploy/compose/compose.yaml. Initialization, Core and Web images are pinned to the release. A release publishes the rendered file; this script does not run Docker.
"""
import hashlib
import pathlib
Expand All @@ -10,7 +10,7 @@

ROOT = pathlib.Path(__file__).resolve().parents[1]
TEMPLATE = ROOT / "deploy/compose/compose.yaml"
TOKENS = ("REVISION", "INIT_IMAGE")
TOKENS = ("REVISION", "INIT_IMAGE", "CORE_IMAGE", "WEB_IMAGE")


def render(values):
Expand All @@ -20,8 +20,9 @@ def render(values):
raise ValueError("Missing Compose values: " + ", ".join(missing))
if not re.fullmatch(r"[0-9a-f]{40}", values["REVISION"]):
raise ValueError("REVISION must be a full source commit SHA")
if not re.fullmatch(r"ghcr\.io/[a-z0-9._/-]+@sha256:[0-9a-f]{64}", values["INIT_IMAGE"]):
raise ValueError("INIT_IMAGE must be an immutable GHCR image reference")
for name in TOKENS[1:]:
if not re.fullmatch(r"ghcr\.io/[a-z0-9._/-]+@sha256:[0-9a-f]{64}", values[name]):
raise ValueError(name + " must be an immutable GHCR image reference")
text = TEMPLATE.read_text()
for name in TOKENS:
token = "__OAC_" + name + "__"
Expand Down
Loading