Skip to content

Commit 2f15e6f

Browse files
committed
docs: archive container image delivery change
1 parent 5ea2eb3 commit 2f15e6f

8 files changed

Lines changed: 79 additions & 3 deletions

File tree

openspec/changes/build-and-push-container-images/.openspec.yaml renamed to openspec/changes/archive/2026-07-27-build-and-push-container-images/.openspec.yaml

File renamed without changes.

openspec/changes/build-and-push-container-images/design.md renamed to openspec/changes/archive/2026-07-27-build-and-push-container-images/design.md

File renamed without changes.

openspec/changes/build-and-push-container-images/proposal.md renamed to openspec/changes/archive/2026-07-27-build-and-push-container-images/proposal.md

File renamed without changes.

openspec/changes/build-and-push-container-images/specs/container-image-delivery/spec.md renamed to openspec/changes/archive/2026-07-27-build-and-push-container-images/specs/container-image-delivery/spec.md

File renamed without changes.

openspec/changes/build-and-push-container-images/specs/production-ops/spec.md renamed to openspec/changes/archive/2026-07-27-build-and-push-container-images/specs/production-ops/spec.md

File renamed without changes.

openspec/changes/build-and-push-container-images/tasks.md renamed to openspec/changes/archive/2026-07-27-build-and-push-container-images/tasks.md

File renamed without changes.
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
# container-image-delivery Specification
2+
3+
## Purpose
4+
TBD - created by archiving change build-and-push-container-images. Update Purpose after archive.
5+
## Requirements
6+
### Requirement: GitHub Actions 构建并推送生产容器镜像
7+
8+
系统 MUST 使用 GitHub Actions 在 GitHub runner 上构建 cnode-next 生产容器镜像,并推送到 GitHub Container Registry。workflow MUST 只负责镜像构建和推送,不得连接生产服务器执行部署。
9+
10+
#### Scenario: API 镜像发布到 GHCR latest
11+
- **WHEN** GitHub Actions 在主分支运行容器镜像发布 workflow
12+
- **THEN** workflow MUST 使用 `apps/api/Dockerfile` 构建 API 镜像
13+
- **AND** workflow MUST 推送 `ghcr.io/cnodejs/cnode-api:latest`
14+
15+
#### Scenario: Web 镜像发布到 GHCR latest
16+
- **WHEN** GitHub Actions 在主分支运行容器镜像发布 workflow
17+
- **THEN** workflow MUST 使用 `apps/web/Dockerfile` 构建 Web 镜像
18+
- **AND** workflow MUST 推送 `ghcr.io/cnodejs/cnode-web:latest`
19+
20+
#### Scenario: Workflow 不部署远程服务器
21+
- **WHEN** GitHub Actions 完成镜像推送
22+
- **THEN** workflow MUST NOT SSH 登录生产服务器
23+
- **AND** workflow MUST NOT 执行远程 `docker compose pull` 或 `docker compose up`
24+
25+
### Requirement: 生产服务器只拉取并运行镜像
26+
27+
生产 docker-compose 编排 MUST 只引用已发布镜像,服务器部署流程 MUST 通过 `pull` 和 `up --no-build` 启动服务,避免在同机运行的 nodeclub、PostgreSQL、Redis 旁边执行镜像构建。
28+
29+
#### Scenario: Compose 不包含本地构建定义
30+
- **WHEN** 运维查看 `docker-compose.prod.yml`
31+
- **THEN** `api`、`web`、`worker`、`migrate-schema`、`migrate-data`、`reconcile` 服务 MUST NOT 包含 `build:` 配置
32+
- **AND** 这些服务 MUST 使用 `image:` 引用 GHCR 镜像
33+
34+
#### Scenario: 手动部署拉取最新镜像
35+
- **WHEN** 运维在生产服务器部署新版本
36+
- **THEN** 运维 MUST 执行 `docker compose -f docker-compose.prod.yml pull api web worker`
37+
- **AND** 运维 MUST 执行 `docker compose -f docker-compose.prod.yml up -d --no-build api web worker`
38+
- **AND** 该流程 MUST NOT 在服务器上执行 Docker build
39+
40+
#### Scenario: Migration 任务使用 API 镜像
41+
- **WHEN** 运维执行 `migrate-schema`、`migrate-data` 或 `reconcile`
42+
- **THEN** 这些一次性任务 MUST 使用 `CNODE_API_IMAGE` 指向的 API 镜像
43+
- **AND** 这些任务 MUST NOT 在服务器上通过 compose build migration target
44+
45+
### Requirement: Web 镜像使用运行时 API 配置
46+
47+
Web 镜像 MUST 不依赖构建时 API base URL。SSR 侧和浏览器侧 API 请求都 MUST 根据服务器运行时环境变量决定 API 地址。
48+
49+
#### Scenario: SSR 使用内部 API 地址
50+
- **WHEN** React Router loader 在 Web 容器服务端执行 API 请求
51+
- **THEN** 系统 MUST 优先使用 `APP_API_INTERNAL_BASE_URL`
52+
- **AND** 在生产 compose 中该值 MUST 指向 `http://api:3001`
53+
54+
#### Scenario: 浏览器使用公开 API 地址
55+
- **WHEN** 浏览器侧交互调用 `apiFetch` 或上传客户端请求 API
56+
- **THEN** 系统 MUST 使用从服务器运行时 `.env` 注入到页面的 `APP_API_BASE_URL`
57+
- **AND** 浏览器侧 MUST NOT 依赖 `VITE_APP_API_BASE_URL` 或其他构建时变量决定 API base URL
58+
59+
#### Scenario: 同一 Web 镜像可复用到不同运行环境
60+
- **WHEN** 同一个 `ghcr.io/cnodejs/cnode-web:latest` 镜像在不同服务器环境启动
61+
- **THEN** 浏览器侧 API base MUST 随该环境的 `.env` 变化
62+
- **AND** 不得要求为不同 API 域名重新构建 Web 镜像
63+

‎openspec/specs/production-ops/spec.md‎

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,10 @@
33
## Purpose
44

55
定义 cnode-next 作为 nodeclub 线上行为完全替代品之前必须通过的 URL、API、写入副作用和生产 smoke 验收矩阵。
6-
76
## Requirements
8-
97
### Requirement: nodeclub 线上替代验收矩阵
108

11-
系统 SHALL 在切换线上流量前通过 nodeclub online replacement 验收矩阵,证明公开 URL、API 契约、业务副作用和生产周边行为均可替代旧站。
9+
系统 SHALL 在切换线上流量前通过 nodeclub online replacement 验收矩阵,证明公开 URL、API 契约、业务副作用、生产周边行为和容器运行方式均可替代旧站。由于 legacy `nodeclub/`、MongoDB、Redis 和 cnode-next 服务同机运行,生产验收 MUST 确认 cnode-next 部署不会在服务器上执行镜像构建。
1210

1311
#### Scenario: URL parity smoke
1412

@@ -36,3 +34,18 @@
3634
- **THEN** 审计验证 score、topic_count、reply_count、collect_topic_count、reply_count、message count 与操作结果一致
3735
- **AND** 验证 Redis 限流 key 和 headers 可观测
3836
- **AND** 验证邮件发送路径可在测试 SMTP 或 stub transporter 下观测
37+
38+
#### Scenario: production image source audit
39+
40+
- **WHEN** 运维执行生产部署验收
41+
- **THEN** `api`、`web` 和 `worker` MUST 运行来自 `ghcr.io/cnodejs/*:latest` 的镜像
42+
- **AND** `docker-compose.prod.yml` MUST NOT 为生产服务定义 `build:`
43+
- **AND** 部署命令 MUST 使用 `docker compose pull` 和 `docker compose up -d --no-build`
44+
45+
#### Scenario: runtime API configuration audit
46+
47+
- **WHEN** 运维验证 Web 容器生产配置
48+
- **THEN** SSR API 请求 MUST 使用 `.env` 或 compose environment 提供的 `APP_API_INTERNAL_BASE_URL`
49+
- **AND** 浏览器侧 API 请求 MUST 使用 `.env` 提供的 `APP_API_BASE_URL`
50+
- **AND** Web 镜像 MUST NOT 因 API 域名变化而重新构建
51+

0 commit comments

Comments
 (0)