Files
ocdp-go/README.md
Ivan087 33ddaf97db fix: scale replicas in response, K8s metrics client, quota precheck, auth tests
- Add GetMetrics method to MetricsClient interface and implement cluster metrics API
- Add QuotaPrecheck service for validating resource quotas before deployment
- Add auth DTO with role/permission models and auth handler tests
- Add instance diagnostics: mounted NFS volumes, labels, annotations in pod diagnostics
- Update workspace handler with GetWorkspace endpoint and shared-user list
- Fix monitoring handler to use correct service method name
- Add tail_lines fallback in instance handler for snake_case query params
- Update nginx config for SSE log streaming support (no buffering)
- Add comprehensive test coverage: auth_service_test, auth_handler_test,
  auth_dto_test, metrics_client_test, quota_precheck_test
- Update error messages for quota validation and instance operations
- ModifyModal: fix YAML lineWidth:0, modified keys summary, delta-only submit
- InstanceCard: correctly disable scale-minus when replicas <= 0
- SidebarLayout: add hover transition for sidebar items
- Update todo.md and lessons.md with latest fixes
2026-05-20 16:56:29 +08:00

288 lines
12 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# OCDP - One Click Deployment Platform
OCDP 是一个面向 Kubernetes 的大模型推理部署平台。当前核心场景是:用户在页面选择 Harbor 中的 `vllm-serve` Helm Chart填写实例名称、命名空间和 values 后,后端从 Harbor 拉取封装好的 OCI Helm Chart并通过 Helm SDK 部署到已配置好的 Kubernetes 集群。
## 当前能力
- Registry 管理:保存 Harbor / OCI Registry 地址与凭据,敏感字段加密入库。
- Artifact 浏览:通过 Harbor v2.0 API 浏览当前凭据可见的项目、repositories 和 chart tags避免依赖 `/v2/_catalog` 全局 catalog 权限。
- 一键部署:从前端发起实例创建,后端拉取 Chart 并在目标集群执行 Helm install/upgrade/uninstall。
- 集群管理:保存 Kubernetes API Server、CA、客户端证书或 token用于后端连接集群。
- 实例管理查看部署状态、Helm revision、Service/Ingress 入口信息。
- 认证:内置 JWT 登录,首次启动可通过 bootstrap 注入管理员账号。
## 技术栈
- 后端Go 1.24Gorilla MuxHexagonal ArchitecturePostgreSQLORAS SDKHelm SDKKubernetes client-go。
- 前端React 18TypeScriptViteTailwindCSS。
- 部署Docker ComposeNginx 静态文件与 `/api` 反向代理PostgreSQL 持久化。
## 项目结构
```text
ocdp-go/
├── backend/ # Go 后端
│ ├── cmd/api/ # API 入口
│ ├── internal/adapter/input/ # HTTP REST handlers / DTO
│ ├── internal/adapter/output/ # PostgreSQL / ORAS / Helm / K8s 实现
│ ├── internal/domain/ # Entity / Repository interface / Service
│ └── internal/bootstrap/ # 首次启动数据注入
├── frontend/ # React + Vite 前端
├── infra/nginx/ # Nginx 网关配置和 TLS 证书
├── docker-compose.yml # 本地完整部署入口PostgreSQL + Backend + 前端 build job + Nginx
├── backend/docker-compose.yml # PostgreSQL + Backend + pgAdmin
├── Makefile # 推荐入口up / restart / stop / logs / ps
└── tasks/ # Agent 工作记录
```
## 后端部署链路
1. 前端调用 `POST /api/v1/clusters/{clusterId}/instances`,提交 `name``namespace``registryId``repository``tag` 和可选 `values`
2. 后端 `InstanceService.CreateInstance` 校验集群、Registry 和实例名唯一性,创建 pending 记录。
3. Chart 浏览使用 Harbor v2.0 API实际部署时后端使用 ORAS SDK 访问 Harbor将指定 repository/tag 的 Helm Chart layer 下载到 `/tmp/charts/{chart}-{version}.tgz`
4. 后端用数据库中保存的集群凭据生成临时 kubeconfig。
5. Helm SDK 加载本地 chart 包,并对目标集群执行 `install`;后续通过 Helm status 同步实例状态。
6. 删除、升级和回滚实例同样通过 Helm SDK 操作目标集群。
## 部署前准备
需要本机已安装:
- Docker
- Docker Compose v2 或更高版本
- Make可选没有 Make 时可直接执行 Compose 命令
根目录 `.env` 用于开发环境启动时注入端口、数据库、初始账号、Harbor 和 Kubernetes 集群。它是开发/测试 bootstrap 数据,不是长期配置中心;系统启动后建议在页面里维护 Registry 和 Cluster。不要提交真实 `.env`
关键变量如下,实际值以你的 `.env` 为准:
```dotenv
# 登录账号 bootstrap
BOOTSTRAP_ADMIN_USER=admin
BOOTSTRAP_ADMIN_PASS=change-me
BOOTSTRAP_ADMIN_EMAIL=admin@example.com
# Harbor bootstrap
BOOTSTRAP_REGISTRY_NAME=harbor
BOOTSTRAP_REGISTRY_URL=https://harbor.example.com
BOOTSTRAP_REGISTRY_DESC=Harbor Registry
# 推荐使用 Harbor robot 账号,只授予目标项目 pull/read 权限
BOOTSTRAP_REGISTRY_ROBOT_USER='robot$project+ocdp'
BOOTSTRAP_REGISTRY_ROBOT_PASS='robot-token'
# 可选 fallback未配置 ROBOT 变量时才会使用
BOOTSTRAP_REGISTRY_USER=admin-or-user
BOOTSTRAP_REGISTRY_PASS=change-me
BOOTSTRAP_REGISTRY_INSECURE=false
# Kubernetes 集群 bootstrap名称列表用逗号分隔
BOOTSTRAP_CLUSTERS=cluster1,cluster2
BOOTSTRAP_CLUSTER_CLUSTER1_HOST=https://x.x.x.x:6443
BOOTSTRAP_CLUSTER_CLUSTER1_DESC=GPU Cluster 1
BOOTSTRAP_CLUSTER_CLUSTER1_CA=base64-ca-data
BOOTSTRAP_CLUSTER_CLUSTER1_CERT=base64-client-cert-data
BOOTSTRAP_CLUSTER_CLUSTER1_KEY=base64-client-key-data
# 如使用 token可配置 TOKENCERT/KEY 可按实际鉴权方式留空
BOOTSTRAP_CLUSTER_CLUSTER2_HOST=https://x.x.x.x:6443
BOOTSTRAP_CLUSTER_CLUSTER2_TOKEN=token-value
# 服务端口,默认使用高位端口避免和本机其他项目冲突
WEB_HTTP_PORT=18080
WEB_HTTPS_PORT=18443
BACKEND_PORT=18081
POSTGRES_PORT=15432
# 安全与数据库
JWT_SECRET=replace-with-a-strong-secret
ENCRYPTION_KEY=replace-with-32-byte-key
POSTGRES_DB=ocdp
POSTGRES_USER=postgres
POSTGRES_PASSWORD=replace-me
# 可选Docker 构建后端时使用的 Go module proxy。
# 国内网络建议保留默认值;如公司网络要求,也可改回 https://proxy.golang.org,direct。
GOPROXY=https://goproxy.cn,direct
GOSUMDB=sum.golang.google.cn
```
说明:
- `BOOTSTRAP_CONFIG_JSON` 优先级最高,适合把完整 bootstrap 配置作为 JSON 注入。
- 没有 `BOOTSTRAP_CONFIG_JSON` 时,后端会读取 `BOOTSTRAP_*` 变量生成初始账号、Registry 和 Cluster。
- 没有任何显式 bootstrap 配置时后端不会预注入用户、Registry 或 Cluster代码中不再保留真实 Harbor、admin 或集群 fallback。
- 初始管理员必须显式配置 `BOOTSTRAP_ADMIN_USER``BOOTSTRAP_ADMIN_PASS`。如果只配置 Registry/Cluster 而未配置管理员账号,系统不会自动创建默认账号。
- Registry bootstrap 凭据优先级为 `BOOTSTRAP_REGISTRY_ROBOT_USER/PASS`,然后才是 `BOOTSTRAP_REGISTRY_USER/PASS`。Harbor robot 账号需要能访问目标项目的 repositories 和 artifacts。
- Harbor robot 用户名通常包含 `$`。本项目 Compose 已使用 raw `env_file` 传给后端;如果你在 shell 里临时 `export BOOTSTRAP_REGISTRY_ROBOT_USER=...`,请用单引号包住值,避免 shell 展开 `$project`
- 已存在同名用户、Registry 或 Cluster 时bootstrap 会跳过,不会覆盖数据库里的记录。
- `ENCRYPTION_KEY` 用于加密保存 Harbor 密码和集群凭据;生产环境首次启动后不要随意更换,否则旧数据无法解密。
## 推荐部署流程
当前只有一个推荐启动入口:在项目根目录执行 `make up`。它会启动同一套完整 Docker Compose 栈:
- `postgres`:数据库,常驻服务。
- `backend`Go API常驻服务宿主机默认端口 `18081`
- `frontend-build`:一次性构建任务,构建完成后退出是正常现象。
- `nginx`:统一 Web 入口,常驻服务,宿主机默认端口 `18080`;前端静态文件和 `/api/*` 都从这里访问。
所以看到 `frontend-build` 处于 `Exited (0)` 不代表前端没运行;前端由 `nginx` 服务。正常运行时至少应看到 `postgres``backend``nginx` 三个容器为 `Up`
```bash
# 1. 在根目录检查 .env
ls .env
# 2. 如果默认高位端口被其他项目占用,先换端口;不要杀其他项目进程
export WEB_HTTP_PORT=18080
export WEB_HTTPS_PORT=18443
export BACKEND_PORT=18081
export POSTGRES_PORT=15432
# 3. 构建并后台启动完整平台
make up
# 4. 查看服务postgres/backend/nginx 应为 Upfrontend-build Exited(0) 正常
make docker-ps
```
访问地址:
- 前端入口http://localhost:${WEB_HTTP_PORT:-18080}
- 后端健康检查http://localhost:${BACKEND_PORT:-18081}/health
- Swagger UIhttp://localhost:${BACKEND_PORT:-18081}/api/docs
- Nginx 健康检查http://localhost:${WEB_HTTP_PORT:-18080}/healthz
兼容旧文档的命令仍可用,但只是 `make up` 的别名:
```bash
make run-2
make docker-dev
make docker-prod
make docker-up
```
没有 Make 时,直接用根目录 Compose 文件:
```bash
docker compose up --build -d
docker compose ps -a
```
代码、Dockerfile、前端资源变更后都建议使用 `make up``docker compose up --build -d`,避免复用旧镜像或旧前端静态资源。
## 验证部署
```bash
# 健康检查
curl http://localhost:${BACKEND_PORT:-18081}/health
curl http://localhost:${WEB_HTTP_PORT:-18080}/healthz
# 登录,返回 token。把 password 替换成 .env 里的 BOOTSTRAP_ADMIN_PASS。
curl -s -X POST http://localhost:${BACKEND_PORT:-18081}/api/v1/auth/login \
-H "Content-Type: application/json" \
-d '{"username":"admin","password":"<BOOTSTRAP_ADMIN_PASS>"}'
# 查看 bootstrap 是否生效,需要带 Bearer token
curl http://localhost:${BACKEND_PORT:-18081}/api/v1/registries \
-H "Authorization: Bearer <token>"
curl http://localhost:${BACKEND_PORT:-18081}/api/v1/clusters \
-H "Authorization: Bearer <token>"
```
页面验证:
1. 打开前端入口并登录。
2. 进入 Chart Browser确认能看到 Harbor 中的 `vllm-serve` 或 nginx chart repository。当前默认只展示可部署 Helm chart。
3. 选择 chart tag点击 Launch。
4. 选择目标集群、命名空间,填写实例名和 values。values 支持 schema 表单或 YAMLYAML 会在前端校验,并由后端解析为 Helm values map。
5. 提交后到实例页面查看状态;后端会异步安装并同步 Helm 状态。
命令行 smoke test
```bash
# 只验证登录、Registry health、Harbor chart 浏览和 values schema
BASE_URL=http://localhost:${BACKEND_PORT:-18081}/api/v1 \
ADMIN_USER="${BOOTSTRAP_ADMIN_USER:-admin}" \
ADMIN_PASS="<BOOTSTRAP_ADMIN_PASS>" \
./test/current-platform-smoke.sh
# 允许真实部署时,会创建测试 release 并在结束后调用平台删除
RUN_DEPLOY_TEST=true \
TEST_NAMESPACE=ocdp-smoke \
TEST_RELEASE=ocdp-smoke-nginx \
BASE_URL=http://localhost:${BACKEND_PORT:-18081}/api/v1 \
ADMIN_PASS="<BOOTSTRAP_ADMIN_PASS>" \
./test/current-platform-smoke.sh
```
## 常用运维命令
```bash
# 一条命令启动/更新完整平台
make up
# 强制重建并重启完整平台
make restart
# 查看当前状态;需要关注 postgres/backend/nginx 是否 Up
make docker-ps
docker compose ps -a
# 查看日志
make docker-logs
# 只重启后端
docker compose restart backend
# 只重启 Web 网关
docker compose restart nginx
# 停止本项目服务,保留数据库和前端构建卷
make stop
# 清理本项目容器和数据卷,谨慎使用,会删除 PostgreSQL 数据
make clean
```
## 本地开发与测试
后端:
```bash
cd backend
go test ./...
go run cmd/api/main.go
```
前端:
```bash
cd frontend
npm ci
npm run build
```
Mock 后端仍可通过 `backend/docker-compose.yml``mock` profile 启动:
```bash
docker compose -f backend/docker-compose.yml --profile mock up -d backend-mock
```
## 注意事项
- 不要为了端口冲突停止其他项目;优先通过 `WEB_HTTP_PORT``WEB_HTTPS_PORT``BACKEND_PORT``POSTGRES_PORT` 换端口。当前默认端口已经是 `18080/18443/18081/15432`
- `frontend-build` 是一次性构建任务,退出码 `0` 是正常状态;前端页面由 `nginx` 容器提供。若只看到 backend/postgres 在运行,请执行 `make up``docker compose up --build -d` 恢复完整栈。
- 如果旧文档提到 `make docker-dev``make docker-prod`,现在这些命令仍可用,都会调用 `make up` 启动同一套 Docker 栈。
- 如果之前用旧配置启动失败过PostgreSQL 卷里可能残留旧的加密数据,表现为 `/api/v1/clusters``/api/v1/registries` 解密失败。开发/重装环境可执行 `make clean-2 && make docker-dev` 重新初始化;生产环境不要直接删卷,应先备份数据库。
- `vllm-serve` 必须以 Helm Chart OCI artifact 的形式存在于 Harbor 中;后端会寻找 Helm Chart layer 并保存为 `.tgz`
- Harbor 浏览使用 `/api/v2.0/projects`、project repositories 和 artifacts API。若 robot 账号无法列项目或 artifacts页面会显示明确错误请检查 Harbor 项目成员/robot 权限,而不是给普通用户开放全局 catalog。
- values YAML 已按 YAML 解析;顶层必须是 mapping例如 `replicaCount: 1`
- Nginx 默认同时监听 HTTP 和 HTTPS证书位于 `infra/nginx/certs/`,生产环境应替换为正式证书。
- `make clean-2` 会删除本项目 Compose 卷,包括 PostgreSQL 数据;只想停服务时使用 `docker compose ... down --remove-orphans`
## API 文档
- OpenAPI YAML[backend/docs/openapi.yaml](./backend/docs/openapi.yaml)
- 运行后 Swagger UI`/api/docs`