diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..68129b8 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,29 @@ +# CLAUDE.md + +## MVP 实现阶段指南 + +在 MVP 实现阶段,解决问题时请遵循以下阅读优先级: + +### 1. 优先阅读文档 + +1. **MVP 方案文档** (`docs/mvp-skeleton-plan.md`) + - 项目骨架结构、模块划分、接口定义 + - 技术实现要点和代码规范 + +2. **原型文档** (`docs/ref/xinfra-prototype.v3.html`) + - 完整的页面交互流程和 UI 规范 + - 组件行为、状态管理、API 调用时机 + - 异常处理和用户体验细节 + +### 2. 理解优先级 + +- **先读文档,再看代码**:理解设计意图后再动手实现 +- **原型优先**:当实现细节与原型冲突时,以原型为准 +- **MVP 文档优先**:当架构决策有疑问时,以 MVP 文档为准 + +### 3. 实现原则 + +- 严格遵循 MVP 文档中定义的目录结构和模块划分 +- 参考原型文档中的交互流程和状态管理 +- 保持代码简洁,聚焦 MVP 核心功能 +- 遵循项目既定的技术栈和编码规范 diff --git a/docs/mvp-skeleton-plan.md b/docs/mvp-skeleton-plan.md new file mode 100644 index 0000000..4474221 --- /dev/null +++ b/docs/mvp-skeleton-plan.md @@ -0,0 +1,1006 @@ +# MVP 方案文档 + +## 概述 + +本文档定义 XINFRA MVP 阶段的代码骨架结构、模块划分、接口定义和技术实现要点。 + +**技术栈锁定**: +- **后端**: Go 1.21+ / Gin +- **前端**: Vue 3.3+ / Element Plus / Vite +- **数据库**: MySQL 8.0 +- **缓存**: Redis +- **部署**: K8s + Nginx + +**MVP 范围**: +1. 认证(LDAP + SAML + OAuth 2.0) +2. 统一子系统导航(卡片展示 + OAuth 2.0 跳转) +3. 审计面板(登录审计 + 主系统 Ansible 运维操作审计) +4. 子系统对接(仅 OAuth 2.0 跳转,主系统后端向前端返回 Mock 数据) +5. Ansible 调度基础模块 + +> 前端 MVP 参考平台需求文档 #30,无需在 MVP 中实现后端 +--- + +## 项目目录结构 + +``` +xinfra/ +├── frontend/ # 前端 Vue 3 项目,提供用户界面和交互 +│ ├── src/ +│ │ ├── api/ # 封装后端 API 请求,统一处理请求/响应和错误 +│ │ │ ├── auth.ts # 认证相关接口:登录、登出、获取用户信息 +│ │ │ ├── audit.ts # 审计相关接口:查询登录审计、运维操作审计 +│ │ │ ├── subsystem.ts # 子系统相关接口:获取子系统列表、SSO 跳转 URL +│ │ │ └── request.ts # Axios 实例封装:请求拦截器(Token 注入)、响应拦截器(错误处理) +│ │ ├── components/ # 可复用的 UI 组件,按功能模块组织 +│ │ │ ├── Layout/ # 页面布局组件:定义整体页面骨架结构 +│ │ │ │ ├── AppHeader.vue # 顶部导航栏:显示 Logo、用户名、退出登录 +│ │ │ │ ├── AppSidebar.vue # 侧边菜单栏:导航菜单项(仪表盘、子系统、审计) +│ │ │ │ └── AppMain.vue # 主内容区:包裹路由视图的容器 +│ │ │ ├── SubsystemCard.vue # 子系统卡片:展示子系统图标、名称、状态,点击触发 SSO 跳转 +│ │ │ └── AuditLogTable.vue # 审计日志表格:展示审计记录列表,支持分页和筛选 +│ │ ├── composables/ # Vue 3 组合式函数,封装可复用的业务逻辑 +│ │ │ └── useAuth.ts # 认证状态管理:登录、登出、Token 校验、路由守卫 +│ │ ├── layouts/ # 页面布局定义,不同页面可使用不同布局 +│ │ │ └── DefaultLayout.vue # 默认布局:包含顶栏 + 侧边栏 + 内容区 +│ │ ├── router/ # 前端路由配置,定义页面路由映射和导航规则 +│ │ │ └── index.ts # 路由实例:路由表定义、路由守卫(未登录重定向) +│ │ ├── stores/ # Pinia 状态管理,跨组件共享全局状态 +│ │ │ ├── auth.ts # 认证状态:存储 Token、用户信息,提供登录/登出 actions +│ │ │ └── user.ts # 用户信息状态:缓存当前登录用户的详细信息 +│ │ ├── views/ # 页面视图组件,一个文件对应一个完整页面 +│ │ │ ├── auth/ # 认证相关页面 +│ │ │ │ └── Login.vue # 登录页:用户名密码表单、LDAP 认证入口 +│ │ │ ├── dashboard/ # 仪表盘页面 +│ │ │ │ └── Index.vue # 首页仪表盘:系统概览、快捷入口 +│ │ │ ├── subsystem/ # 子系统导航页面 +│ │ │ │ └── Navigation.vue # 子系统导航页:6 个子系统卡片网格展示 +│ │ │ └── audit/ # 审计面板页面 +│ │ │ ├── LoginAudit.vue # 登录审计页:查询登录记录、按时间/IP/结果筛选 +│ │ │ └── OpsAudit.vue # 运维操作审计页:查询操作记录、按类型/状态筛选 +│ │ ├── utils/ # 通用工具函数,不依赖业务逻辑 +│ │ │ └── auth.ts # 认证工具:Token 解析、过期校验、本地存储读写 +│ │ ├── App.vue # 根组件:挂载路由视图,全局样式和 Provider +│ │ └── main.ts # 入口文件:初始化 Vue 应用、注册插件(Pinia、Router、Element Plus) +│ ├── public/ # 静态资源目录,构建时原样复制到 dist +│ ├── index.html # HTML 入口模板,Vite 注入构建后的 JS/CSS +│ ├── vite.config.ts # Vite 构建配置:插件、别名、代理、构建选项 +│ ├── tsconfig.json # TypeScript 配置:编译选项、路径映射 +│ └── package.json # 依赖管理:项目依赖列表、脚本命令 +│ +├── server/ # 后端 Go 项目,提供 RESTful API 服务 +│ ├── cmd/ # 程序入口目录 +│ │ └── server/ +│ │ └── main.go # 服务启动入口:初始化配置、数据库、路由,启动 HTTP 服务 +│ ├── internal/ # 内部包,不对外暴露,按分层架构组织 +│ │ ├── config/ # 配置管理模块 +│ │ │ └── config.go # 配置加载:读取 YAML 配置文件,支持环境变量覆盖 +│ │ ├── handler/ # HTTP 处理器层(Controller),接收请求、校验参数、调用 Service +│ │ │ ├── auth.go # 认证处理器:处理登录/登出/用户信息请求 +│ │ │ ├── audit.go # 审计处理器:处理登录审计/运维操作审计查询请求 +│ │ │ ├── subsystem.go # 子系统处理器:处理子系统列表/SSO URL 生成请求 +│ │ │ ├── task.go # 任务处理器:处理 Ansible 任务创建/状态查询请求 +│ │ │ └── response.go # 统一响应:定义标准 JSON 响应格式和错误码 +│ │ ├── middleware/ # HTTP 中间件,在请求处理前后执行通用逻辑 +│ │ │ ├── auth.go # 认证中间件:校验 JWT Token,注入用户信息到 Context +│ │ │ ├── logger.go # 日志中间件:记录请求方法、路径、耗时、状态码 +│ │ │ └── audit.go # 审计中间件:自动记录非 GET 请求的操作审计日志 +│ │ ├── model/ # 数据模型层,定义数据库表结构和业务实体 +│ │ │ ├── user.go # 用户模型:对应 users 表,定义用户字段和状态枚举 +│ │ │ ├── audit.go # 审计模型:对应 login_audit / ops_audit 表 +│ │ │ └── subsystem.go # 子系统模型:对应 subsystems 表,定义子系统信息 +│ │ ├── repository/ # 数据访问层(DAO),封装数据库 CRUD 操作 +│ │ │ ├── user.go # 用户仓储:用户查询、创建、更新、LDAP DN 映射 +│ │ │ └── audit.go # 审计仓储:审计记录插入、分页查询、条件筛选 +│ │ ├── service/ # 业务逻辑层,编排 Repository,实现核心业务 +│ │ │ ├── auth.go # 认证服务:LDAP 认证、本地降级认证、JWT 生成 +│ │ │ ├── ldap.go # LDAP 服务:封装 LDAP 连接、查询、认证逻辑 +│ │ │ ├── audit.go # 审计服务:记录登录审计、运维操作审计 +│ │ │ ├── subsystem.go # 子系统服务:子系统查询、OAuth 2.0 SSO URL 生成 +│ │ │ └── ansible.go # Ansible 调度服务:创建任务、执行 Playbook、推送日志 +│ │ ├── websocket/ # WebSocket 实时推送模块 +│ │ │ └── hub.go # WebSocket Hub:管理客户端连接,广播 Ansible 任务日志 +│ │ └── router/ # 路由注册模块 +│ │ └── router.go # 路由注册:定义 API 路由表,绑定 Handler 和 Middleware +│ ├── pkg/ # 可复用的公共包,可被外部项目引用 +│ │ ├── ldap/ # LDAP 客户端封装 +│ │ │ └── client.go # LDAP 客户端:连接管理、用户认证、属性查询 +│ │ ├── sso/ # SSO 协议处理 +│ │ │ ├── oauth2.go # OAuth 2.0 客户端:主系统↔子系统的 Authorization Code 流程 +│ │ │ └── saml.go # SAML 处理:主系统↔LDAP 的 SAML 断言生成和验证 +│ │ └── database/ # 数据库连接管理 +│ │ └── mysql.go # MySQL 连接池:初始化连接、健康检查、优雅关闭 +│ ├── migrations/ # 数据库迁移脚本,按版本管理表结构变更 +│ │ └── 001_init.sql # 初始化迁移:创建 users / subsystems / audit / ansible_tasks 表 +│ └── go.mod # Go 模块定义:模块路径、依赖版本管理 +│ +├── deploy/ # 部署配置,包含容器化和编排所需文件 +│ ├── docker/ # Docker 构建配置 +│ │ ├── Dockerfile.frontend # 前端镜像:基于 Node 构建 + Nginx 托管静态文件 +│ │ └── Dockerfile.server # 后端镜像:基于 Go 编译 + 运行时最小镜像 +│ └── k8s/ # Kubernetes 部署配置 +│ ├── frontend.yaml # 前端 Deployment:副本数、Service、环境变量配置 +│ ├── server.yaml # 后端 Deployment:副本数、Service、Secret 挂载 +│ └── ingress.yaml # Ingress 配置:域名路由规则、TLS 证书 +│ +├── docs/ # 项目文档目录 +│ └── mvp-skeleton-plan.md # MVP 方案文档:本文件,定义代码骨架和实现要点 +│ +├── .gitignore # Git 忽略规则:排除编译产物、依赖、环境配置 +├── Makefile # 构建脚本:定义 build / run / test / docker 等快捷命令 +└── README.md # 项目说明:项目介绍、快速启动、开发指南 +``` + + +--- + +## 模块划分与职责 + +### 后端模块 + +| 模块 | 职责 | 说明 | +|------|------|------| +| `cmd/server` | 服务启动入口 | 初始化配置、数据库、路由,启动 HTTP 服务 | +| `internal/config` | 配置管理 | 加载 YAML 配置,支持环境变量覆盖 | +| `internal/handler` | HTTP 处理器 | 处理请求,调用 Service 层,返回响应 | +| `internal/middleware` | 中间件 | 认证、日志、审计等中间件 | +| `internal/model` | 数据模型 | 定义数据库表结构和业务实体 | +| `internal/repository` | 数据访问层 | 封装数据库操作,实现 CRUD | +| `internal/service` | 业务逻辑层 | 核心业务逻辑,编排 Repository | +| `internal/websocket` | WebSocket 实时推送 | Ansible 任务日志实时推送 | +| `internal/router` | 路由配置 | 定义 API 路由和处理器映射 | +| `pkg/ldap` | LDAP 客户端 | 封装 LDAP 查询和认证 | +| `pkg/sso` | SSO 处理 | OAuth 2.0(主系统↔子系统)+ SAML(主系统↔LDAP) | +| `pkg/database` | 数据库连接 | MySQL 连接池管理 | + +### 前端模块 + +| 模块 | 职责 | 说明 | +|------|------|------| +| `api/` | API 请求 | 封装后端接口调用,统一错误处理 | +| `components/` | 通用组件 | 可复用的 UI 组件 | +| `composables/` | 组合式函数 | 封装可复用的逻辑(认证) | +| `layouts/` | 页面布局 | 定义页面整体布局结构 | +| `router/` | 路由配置 | 定义前端路由 | +| `stores/` | 状态管理 | Pinia 全局状态管理 | +| `views/` | 页面视图 | 具体页面实现 | +| `utils/` | 工具函数 | 通用工具函数 | + +--- + +## 错误码定义 + +### HTTP 状态码 + +| 状态码 | 说明 | +|--------|------| +| 200 | 成功 | +| 400 | 请求参数错误 | +| 401 | 未认证(Token 缺失或无效) | +| 403 | 无权限访问 | +| 404 | 资源不存在 | +| 500 | 服务器内部错误 | + +### 业务错误码 + +| 错误码 | 说明 | +|--------|------| +| 10001 | LDAP 认证失败 | +| 10002 | 用户名或密码错误 | +| 10003 | Token 已过期 | +| 10004 | 子系统未配置 SSO | +| 10005 | SSO 跳转生成失败 | +| 20001 | Ansible 任务创建失败 | +| 20002 | Ansible 任务执行超时 | + +### 错误响应格式 + +```json +{ + "code": 10001, + "message": "LDAP 认证失败", + "details": "连接 LDAP 服务器超时" +} +``` + +--- + +## 安全设计 + +### 敏感配置管理 + +| 配置项 | 存储方式 | 说明 | +|--------|----------|------| +| JWT Secret | K8s Secret | 通过环境变量注入 | +| LDAP Bind Password | K8s Secret | 通过环境变量注入 | +| DB Password | K8s Secret | 通过环境变量注入 | +| Redis Password | K8s Secret | 通过环境变量注入 | +| OAuth2 Client Secret | K8s Secret | 各子系统的 OAuth2 密钥 | + +### 安全措施 + +- **传输加密**:所有 API 通信强制 HTTPS +- **Token 安全**:JWT 使用 RS256 签名,过期时间 1 小时 +- **密码策略**:LDAP 统一管理,本地账户密码 bcrypt 加密 +- **审计日志**:所有敏感操作记录审计日志 + +--- + +## 接口定义 + +### 1. 认证模块 API + +#### POST /api/v1/auth/login +```go +// 请求 +{ + "username": "string", // 用户名 + "password": "string" // 密码 +} + +// 响应 +{ + "code": 0, + "message": "success", + "data": { + "token": "string", // JWT Token + "expires_in": 3600, // 过期时间(秒) + "user": { + "id": 1, + "username": "string", + "display_name": "string", + "email": "string", + "business_line": "kodo" // 业务线 + } + } +} +``` + +#### POST /api/v1/auth/logout +```go +// 请求头 +Authorization: Bearer + +// 响应 +{ + "code": 0, + "message": "success" +} +``` + +#### GET /api/v1/auth/userinfo +```go +// 请求头 +Authorization: Bearer + +// 响应 +{ + "code": 0, + "message": "success", + "data": { + "id": 1, + "username": "string", + "display_name": "string", + "email": "string", + "business_line": "kodo" + } +} +``` + +### 2. 子系统模块 API + +#### GET /api/v1/subsystems +```go +// 响应 +{ + "code": 0, + "message": "success", + "data": [ + { + "id": 1, + "name": "Wayne", + "description": "多集群容器管理平台", + "icon": "wayne.svg", + "url": "https://wayne.qiniu.com", + "status": "integrated", // integrated / integrating + "sso_enabled": true + }, + { + "id": 2, + "name": "CloudDM", + "description": "数据库管理与SQL审核", + "icon": "clouddm.svg", + "url": "https://clouddm.qiniu.com", + "status": "integrated", + "sso_enabled": true + }, + { + "id": 3, + "name": "CacheCloud", + "description": "Redis 云管理平台", + "icon": "cachecloud.svg", + "url": "https://cachecloud.qiniu.com", + "status": "integrated", + "sso_enabled": true + }, + { + "id": 4, + "name": "Apollo", + "description": "配置中心", + "icon": "apollo.svg", + "url": "https://apollo.xinfra.internal", + "status": "integrated", + "sso_enabled": true + }, + { + "id": 5, + "name": "qpass", + "description": "密码管理平台", + "icon": "qpass.svg", + "url": "https://qpass.xinfra.internal", + "status": "integrated", + "sso_enabled": true + }, + { + "id": 6, + "name": "Grafana", + "description": "监控可视化平台", + "icon": "grafana.svg", + "url": "https://grafana.xinfra.internal", + "status": "integrated", + "sso_enabled": true + } + ] +} +``` + +#### GET /api/v1/subsystems/:id/sso-url +```go +// 响应 +{ + "code": 0, + "message": "success", + "data": { + "sso_url": "https://wayne.qiniu.com/sso/callback?code=xxx&state=yyy", + "expires_in": 300 + } +} +``` + +### 3. 审计模块 API + +#### GET /api/v1/audit/login +```go +// 查询参数 +?user_id=1&start_time=2024-01-01T00:00:00Z&end_time=2024-01-31T23:59:59Z&page=1&page_size=20 + +// 响应 +{ + "code": 0, + "message": "success", + "data": { + "total": 100, + "items": [ + { + "id": 1, + "user_id": 1, + "username": "zhangsan", + "login_time": "2024-01-15T10:30:00Z", + "source_ip": "10.0.0.1", + "target_system": "Wayne", + "status": "success" + } + ] + } +} +``` + +#### GET /api/v1/audit/operations +```go +// 查询参数 +?user_id=1&operation_type=ansible&page=1&page_size=20 + +// 响应 +{ + "code": 0, + "message": "success", + "data": { + "total": 50, + "items": [ + { + "id": 1, + "user_id": 1, + "username": "zhangsan", + "operation_type": "ansible", + "operation": "执行 playbook: node-join", + "target": "node-10.0.0.5", + "status": "success", + "created_at": "2024-01-15T10:35:00Z" + } + ] + } +} +``` + +### 4. Ansible 调度模块 API + +#### POST /api/v1/tasks/ansible/execute +```go +// 请求 +{ + "playbook": "node-join.yml", + "targets": ["node-10.0.0.5", "node-10.0.0.6"], + "extra_vars": { + "cluster": "prod" + } +} + +// 响应 +{ + "code": 0, + "message": "success", + "data": { + "task_id": "task-uuid-xxx", + "status": "running" + } +} +``` + +#### GET /api/v1/tasks/:id +```go +// 响应 +{ + "code": 0, + "message": "success", + "data": { + "task_id": "task-uuid-xxx", + "playbook": "node-join.yml", + "targets": ["node-10.0.0.5", "node-10.0.0.6"], + "status": "running", // pending / running / success / failed + "created_at": "2024-01-15T10:35:00Z", + "started_at": "2024-01-15T10:35:01Z", + "finished_at": null + } +} +``` + +#### WebSocket /ws/tasks/:id/logs +``` +// 实时推送 Ansible 执行日志 +// 消息格式: +{ + "type": "log", + "data": { + "timestamp": "2024-01-15T10:35:02Z", + "host": "node-10.0.0.5", + "task": "Gathering Facts", + "status": "ok", + "message": "ok: [node-10.0.0.5]" + } +} +``` + +--- + +## 数据库设计 + +### 核心表结构 + +```sql +-- 用户表 +CREATE TABLE users ( + id BIGINT AUTO_INCREMENT PRIMARY KEY, + username VARCHAR(64) NOT NULL UNIQUE, + display_name VARCHAR(128), + email VARCHAR(128), + password_hash VARCHAR(256), + business_line VARCHAR(32), + ldap_dn VARCHAR(256), + status ENUM('active', 'disabled') DEFAULT 'active', + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP +); + +-- 子系统表 +CREATE TABLE subsystems ( + id BIGINT AUTO_INCREMENT PRIMARY KEY, + name VARCHAR(64) NOT NULL, + description TEXT, + icon VARCHAR(128), + url VARCHAR(256), + status ENUM('integrated', 'integrating') DEFAULT 'integrating', + sso_enabled BOOLEAN DEFAULT FALSE, + sort_order INT DEFAULT 0, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP +); + +-- 登录审计表 +CREATE TABLE login_audit ( + id BIGINT AUTO_INCREMENT PRIMARY KEY, + user_id BIGINT, + username VARCHAR(64), + login_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + source_ip VARCHAR(64), + target_system VARCHAR(64), + status ENUM('success', 'failed') DEFAULT 'success', + INDEX idx_user_id (user_id), + INDEX idx_login_time (login_time) +); + +-- 运维操作审计表 +CREATE TABLE ops_audit ( + id BIGINT AUTO_INCREMENT PRIMARY KEY, + user_id BIGINT, + username VARCHAR(64), + operation_type VARCHAR(32), + operation TEXT, + target VARCHAR(256), + status ENUM('success', 'failed', 'running') DEFAULT 'running', + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + INDEX idx_user_id (user_id), + INDEX idx_created_at (created_at) +); + +-- Ansible 任务表 +CREATE TABLE ansible_tasks ( + id VARCHAR(64) PRIMARY KEY, + user_id BIGINT, + username VARCHAR(64), + playbook VARCHAR(128), + targets JSON, + extra_vars JSON, + status ENUM('pending', 'running', 'success', 'failed') DEFAULT 'pending', + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + started_at TIMESTAMP NULL, + finished_at TIMESTAMP NULL, + INDEX idx_user_id (user_id), + INDEX idx_status (status) +); +``` + +--- + +## 关键模块实现要点 + +### 1. 认证模块 (auth) + +**后端实现**: +```go +// internal/service/auth.go +type AuthService struct { + userRepo repository.UserRepository + ldapClient *ldap.Client + auditService *AuditService +} + +// Login 用户登录 +func (s *AuthService) Login(username, password string) (*LoginResponse, error) { + // 1. 尝试 LDAP 认证 + user, err := s.ldapClient.Authenticate(username, password) + if err != nil { + // 2. 降级到本地数据库认证 + user, err = s.userRepo.FindByUsername(username) + if err != nil { + return nil, err + } + if !s.checkPassword(password, user.PasswordHash) { + return nil, ErrInvalidCredentials + } + } + + // 3. 生成 JWT Token(无状态,不存储 session) + token, err := s.generateToken(user) + if err != nil { + return nil, err + } + + // 4. 记录登录审计 + s.auditService.RecordLogin(user.ID, username, "main", "success") + + return &LoginResponse{ + Token: token, + ExpiresIn: 3600, + User: user, + }, nil +} +``` + +**前端实现**: +```typescript +// frontend/src/composables/useAuth.ts +export function useAuth() { + const authStore = useAuthStore() + + const login = async (username: string, password: string) => { + const response = await authApi.login({ username, password }) + authStore.setToken(response.token) + authStore.setUser(response.user) + return response + } + + const logout = async () => { + await authApi.logout() + authStore.clearAuth() + router.push('/login') + } + + const checkAuth = () => { + const token = authStore.token + if (!token) { + router.push('/login') + return false + } + return true + } + + return { login, logout, checkAuth } +} +``` + +### 2. SSO 跳转模块(OAuth 2.0) + +**后端实现**: +```go +// internal/service/subsystem.go +type SubsystemService struct { + subsystemRepo repository.SubsystemRepository + oauth2Client *sso.OAuth2Client +} + +// GetSSOURL 获取子系统 SSO 跳转 URL(OAuth 2.0 Authorization Code) +func (s *SubsystemService) GetSSOURL(subsystemID int64, user *model.User) (string, error) { + subsystem, err := s.subsystemRepo.FindByID(subsystemID) + if err != nil { + return "", err + } + + if !subsystem.SSOEnabled { + return subsystem.URL, nil + } + + // 生成 OAuth 2.0 Authorization Code + code, state, err := s.oauth2Client.GenerateAuthCode(subsystem, user) + if err != nil { + return "", err + } + + // 构建 SSO 跳转 URL + ssoURL := fmt.Sprintf("%s/sso/callback?code=%s&state=%s", + subsystem.URL, code, state) + + // 记录 SSO 跳转审计 + s.auditService.RecordLogin(user.ID, user.Username, subsystem.Name, "success") + + return ssoURL, nil +} +``` + +**前端实现**: +```typescript +// frontend/src/components/SubsystemCard.vue + + + +``` + +### 3. Ansible 调度模块 + +**后端实现**: +```go +// internal/service/ansible.go +type AnsibleService struct { + taskRepo repository.TaskRepository + auditService *AuditService + wsHub *websocket.Hub +} + +// ExecutePlaybook 执行 Ansible Playbook +func (s *AnsibleService) ExecutePlaybook(req *ExecuteRequest, user *model.User) (*AnsibleTask, error) { + task := &AnsibleTask{ + ID: generateUUID(), + UserID: user.ID, + Username: user.Username, + Playbook: req.Playbook, + Targets: req.Targets, + ExtraVars: req.ExtraVars, + Status: "pending", + } + + if err := s.taskRepo.Create(task); err != nil { + return nil, err + } + + // 异步执行 Ansible + go s.runPlaybook(task) + + return task, nil +} + +// runPlaybook 异步执行并推送日志 +func (s *AnsibleService) runPlaybook(task *AnsibleTask) { + // 调用 ansible-playbook 命令 + // 通过 WebSocket 实时推送日志到前端 + // 更新任务状态 +} +``` + +**WebSocket Hub**: +```go +// internal/websocket/hub.go +type Hub struct { + clients map[string]map[*Client]bool + broadcast chan *Message + register chan *Client + unregister chan *Client +} + +// SubscribeTaskLogs 订阅任务日志 +func (h *Hub) SubscribeTaskLogs(taskID string, client *Client) { + h.register <- &Client{taskID: taskID, conn: client.conn} +} +``` + +### 4. 审计模块 + +**后端实现**: +```go +// internal/middleware/audit.go +func AuditMiddleware(auditService *service.AuditService) gin.HandlerFunc { + return func(c *gin.Context) { + // 记录请求开始 + startTime := time.Now() + + // 处理请求 + c.Next() + + // 记录操作审计 + if c.Request.Method != "GET" { + user, _ := c.Get("user") + if user != nil { + auditService.RecordOperation( + user.(*model.User).ID, + user.(*model.User).Username, + c.Request.Method, + c.Request.URL.Path, + c.ClientIP(), + c.Writer.Status(), + ) + } + } + + // 记录请求耗时 + duration := time.Since(startTime) + log.Printf("Method: %s, Path: %s, Duration: %v", + c.Request.Method, c.Request.URL.Path, duration) + } +} +``` + +--- + +## 配置文件 + +### 后端配置 (config.yaml) +```yaml +server: + host: "0.0.0.0" + port: 8080 + mode: "release" # debug / release / test + +database: + host: "mysql" + port: 3306 + username: "xinfra" + password: "${DB_PASSWORD}" + database: "xinfra" + max_open_conns: 100 + max_idle_conns: 10 + +redis: + host: "redis" + port: 6379 + password: "${REDIS_PASSWORD}" + db: 0 + +ldap: + host: "ldap.qiniu.com" + port: 389 + base_dn: "dc=qiniu,dc=com" + bind_dn: "cn=admin,dc=qiniu,dc=com" + bind_password: "${LDAP_PASSWORD}" + +jwt: + secret: "${JWT_SECRET}" + expires_in: 3600 + +subsystems: + - name: "Wayne" + url: "https://wayne.qiniu.com" + sso_enabled: true + - name: "CloudDM" + url: "https://clouddm.qiniu.com" + sso_enabled: true + - name: "CacheCloud" + url: "https://cachecloud.qiniu.com" + sso_enabled: true + - name: "Apollo" + url: "https://apollo.xinfra.internal" + sso_enabled: true + - name: "qpass" + url: "https://qpass.xinfra.internal" + sso_enabled: true + - name: "Grafana" + url: "https://grafana.xinfra.internal" + sso_enabled: true +``` + +### 前端配置 (vite.config.ts) +```typescript +import { defineConfig } from 'vite' +import vue from '@vitejs/plugin-vue' +import { resolve } from 'path' + +export default defineConfig({ + plugins: [vue()], + resolve: { + alias: { + '@': resolve(__dirname, 'src'), + }, + }, + server: { + port: 3000, + proxy: { + '/api': { + target: 'http://localhost:8080', + changeOrigin: true, + }, + }, + }, + build: { + outDir: 'dist', + sourcemap: false, + }, +}) +``` + +--- + +## MVP 验收标准 + +| # | 验收项 | 验收标准 | +|---|--------|----------| +| 1 | LDAP 登录 | 用户可通过 LDAP 账号密码登录主系统,登录成功后跳转首页 | +| 2 | 本地降级登录 | LDAP 不可用时,支持本地数据库账号密码登录 | +| 3 | 6 个子系统卡片展示 | 首页展示 Wayne、CloudDM、CacheCloud、Apollo、qpass、Grafana 6 个子系统卡片 | +| 4 | SSO 跳转 | 点击子系统卡片,通过 OAuth 2.0 跳转到子系统,免登录 | +| 5 | 登录审计 | 可查询所有用户的登录记录,包括时间、IP、目标系统、结果 | +| 6 | 运维操作审计 | 可查询运维操作记录,包括操作类型、目标、结果 | +| 7 | Ansible 调度基础 | 可执行 Ansible Playbook,实时查看执行日志 | +| 8 | API 错误处理 | 所有 API 返回标准错误码和错误信息 | + +--- + +## 开发任务清单 + +### Phase 1: 基础框架搭建 (2天) + +- [ ] 初始化前后端项目结构 +- [ ] 配置开发环境 (Makefile, docker-compose) +- [ ] 实现基础中间件 (Logger, Recovery) +- [ ] 配置数据库连接和迁移 +- [ ] 实现统一响应格式 +- [ ] 实现错误码定义 + +### Phase 2: 认证模块 (3天) + +- [ ] 实现 LDAP 客户端 +- [ ] 实现用户登录/登出 API +- [ ] 实现 JWT Token 生成和验证(无状态) +- [ ] 实现认证中间件 +- [ ] 实现 OAuth 2.0 + SAML SSO 协议 +- [ ] 实现前端登录页面 +- [ ] 实现前端路由守卫 + +### Phase 3: 子系统导航 (2天) + +- [ ] 实现子系统 CRUD API +- [ ] 实现 OAuth 2.0 Authorization Code 生成 +- [ ] 实现 SSO 跳转逻辑(6 个子系统) +- [ ] 实现子系统卡片组件 +- [ ] 实现子系统导航页面 + +### Phase 4: 审计模块 (1.5天) + +- [ ] 实现审计数据模型 +- [ ] 实现审计记录 API +- [ ] 实现审计查询 API +- [ ] 实现审计中间件 +- [ ] 实现登录审计页面 +- [ ] 实现运维操作审计页面 + +### Phase 5: Ansible 调度基础模块 + WebSocket (1天) + +- [ ] 实现 Ansible 调度服务 +- [ ] 实现任务 API +- [ ] 实现 WebSocket 日志推送 +- [ ] 实现任务执行日志前端展示 + +### Phase 6: 部署配置 + 测试 (0.5天) + +- [ ] 编写 Dockerfile +- [ ] 编写 Kubernetes 配置(含 Secret 管理) +- [ ] 编写部署文档 +- [ ] 集成测试 + +--- + +## 技术要点 + +### 1. 认证流程 + +``` +用户输入用户名密码 + ↓ +主系统后端接收请求 + ↓ +尝试 LDAP 认证 + ↓ (失败) +降级到本地数据库认证 + ↓ +生成 JWT Token(无状态,不存储 session) + ↓ +记录登录审计 + ↓ +返回 Token 给前端 + ↓ +前端存储 Token,跳转首页 +``` + +### 2. SSO 跳转流程(OAuth 2.0) + +``` +用户点击子系统卡片 + ↓ +前端请求 /api/v1/subsystems/:id/sso-url + ↓ +后端验证用户 Token + ↓ +生成 OAuth 2.0 Authorization Code + ↓ +记录 SSO 跳转审计 + ↓ +返回 SSO URL 给前端 + ↓ +前端打开新窗口跳转(子系统通过 Code 换取 Token) +``` + +**SSO 协议分工**: +- **主系统 ↔ 子系统**:OAuth 2.0 Authorization Code 流程 +- **主系统 ↔ LDAP**:SAML 协议 \ No newline at end of file diff --git a/docs/ref/xinfra-prototype.v3.html b/docs/ref/xinfra-prototype.v3.html new file mode 100644 index 0000000..3c0a488 --- /dev/null +++ b/docs/ref/xinfra-prototype.v3.html @@ -0,0 +1,1174 @@ + + + + +xinfra · 统一基础设施平台 + + + + +
+
+
xi
xinfra 统一基础设施平台
+ ● 生产环境 +
+ +
+
王
+
+
王晓东
+
LDAP · Kodo业务线
+
+
+
+ + + +
+ + +
+
+

资源大盘

跨机房 / 多云容器资源统一视图 · 最近更新于 12 秒前

+ +
+ +
+
RKE2 集群
3
3 机房在线
+
节点总数
128
↑ 6 本周新增
+
CPU 已分配
61%
2,048 / 3,360 核
+
组件实例
214
MySQL 38 · Redis 92 · 其他 84
+
进行中任务
2
1 个待关注
+
+ +
+
+

集群拓扑 · 按机房 / 业务线标签

node-label 调度视图
+
+
+
IDC-华北机房46节点
+
+
+
+
IDC-华东机房52节点
+
+
+
+
阿里云-华南30节点
+
+
+
+
+ Kodo业务线 + LAS业务线 + 灵矽业务线 + 空闲 +
+
+ +
+

最近任务

查看全部 →
+
+ + + + + + +
● 成功MySQL 主从部署2m14s
● 执行中RKE2 节点加入38s
● 成功Redis Cluster 部署3m02s
● 失败openresty 网关部署41s
● 成功业务线标签同步5s
+
+
+
+
+ + +
+
+

资源状态看板

物理机 / 虚机 / 基础服务状态汇总 · 夜莺(Nightingale)统一告警引擎对接 Zabbix + VictoriaMetrics · 最近更新于 18 秒前

+ +
+ +
+
物理机总数
186
186 / 186 监控覆盖
+
虚机总数(LAS)
512
↑ 14 本周新增
+
基础组件实例
214
MySQL 38 · Redis 92 · 其他 84
+
P0 / Disaster 告警
1
来自 VictoriaMetrics
+
P1 / High 告警
5
来自 Zabbix · 4 条 / VM · 1 条
+
+ +
+

告警来源接入 · 夜莺统一告警

Nightingale ← Zabbix / VictoriaMetrics
+
+
+
+
Zabbix 物理机 / 硬件层
+
IPMI · 温度 · 电源 · 风扇
+
网络设备 · 存储健康度
+
事件级别:disaster / high / average
+
+
+
VictoriaMetrics 虚机 / 容器 / 业务层
+
K8s / 容器 / 主机指标
+
基础服务可用性探活
+
告警级别:P0 / P1 / P2
+
+
+
夜莺 Nightingale 统一告警引擎
+
按 P0/P1 或 disaster/high/average 过滤聚合
+
去重 · 收敛 · 分级推送
+
下游:qpass 统一告警通道
+
+
+
+
+ +
+
+

物理机状态 · 按机房

数据源:Zabbix
+
+ + + + + + +
机房总数在线健康率状态
YZH 机房787898%● 正常
XS 机房646391%● 1 条告警
JF 机房2222100%● 正常
海外 IDC(4)222186%● 1 条严重
+
+
+ +
+

虚机状态 · LAS 资源池

数据源:VictoriaMetrics
+
+ + + + + + +
业务线虚机数CPU 均值状态
Kodo21864%● 正常
LAS16482%● 1 条告警
灵矽9657%● 正常
共享池 / 未分配3431%● 正常
+
+
+
+ +
+

基础服务状态汇总

MySQL / Redis / 中间件 · 探活数据源:VictoriaMetrics
+
+ + + + + + + +
服务类型实例数异常可用率状态
MySQL380100%● 正常
Redis(CacheCloud)92198.9%● 1 条告警
PostgreSQL120100%● 正常
openresty 网关260100%● 正常
其他中间件460100%● 正常
+
+
+ +
+

当前告警 · P0/P1(disaster / high / average)

夜莺聚合 · 已去重
+
+ + + + + + + + +
级别来源原始级别对象告警内容时间
P0VictoriaMetricsdisastersg-las-overseas-007磁盘只读 / IO 错误,节点不可写07:38:55
P1Zabbixhighyzh-las-014风扇转速低于阈值(FAN_6: 1920 RPM)07:35:12
P1Zabbixhighxs-bm-291电源冗余丢失(PSU2 离线)07:21:40
P1VictoriaMetricshighredis-ads-feature-cluster-02慢查询比例超阈值(>5%,持续5分钟)07:18:03
averageZabbixaverageoverseas-dallas-idc专线延迟抖动超基线(WireGuard ↔ AWS US)07:10:22
averageZabbixaveragejf-bm-118CPU 温度接近阈值(76℃ / 80℃)06:58:47
+
+
+
+ + + +
+
+

集群 / 节点

按机房切分的 RKE2 集群,Calico BGP 扁平网络

+ +
+
+
+ + + + + + + +
集群机房 / 区域状态节点CPU 使用RKE2 版本Calico
rke2-bj-prod-01华北 · IDC● 健康4664%v1.28.9+rke2r1BGP AS64512
rke2-sh-prod-01华东 · IDC● 健康5271%v1.28.9+rke2r1BGP AS64513
rke2-ali-sz-01阿里云 · 华南● 1 节点告警3083%v1.28.6+rke2r1BGP AS64514
+
+
+ +
+

rke2-bj-prod-01 · 节点列表(节选)

node-label 多租户隔离
+
+ + + + + + + + +
节点IP业务线标签污点 Taint规格CPU / Mem状态
bj-node-01410.21.4.14business-line=kodokodo:NoSchedule64C/256G58%● Ready
bj-node-01510.21.4.15business-line=kodokodo:NoSchedule64C/256G62%● Ready
bj-node-03110.21.4.31business-line=laslas:NoSchedule32C/128G88%● 资源告警
bj-node-04810.21.4.48未分配—32C/128G4%● Ready · 空闲
+
+
+
+ + +
+
+

业务线 / 配额

LDAP 部门信息自动同步生成,节点标签 + ResourceQuota 双重隔离

+
+
+
+ + + + + + + + + +
业务线LDAP 部门归属节点数CPU 配额已用命名空间负责人
kodo · Kodo业务线ou=kodo,dc=company,dc=com421,344 核58%ns-kodo-prod王晓东
las · LAS业务线ou=las,dc=company,dc=com381,216 核85%ns-las-prod李雯
lingxi · 灵矽业务线ou=lingxi,dc=company,dc=com26832 核47%ns-lingxi-prod张昊
ltoken · LTOKEN业务线ou=ltoken,dc=company,dc=com14448 核33%ns-ltoken-prod陈思
maas · MAAS业务线ou=maas,dc=company,dc=com8256 核21%ns-maas-prod赵帆
+
+
+
+ 隔离策略说明:节点标签(nodeAffinity + taints)决定 Pod 只能调度到归属业务线的物理节点上;ResourceQuota / LimitRange 在此基础上限制命名空间内的资源上限,二者结合避免单一业务线在自己的节点池内无限占用资源。 +
+
+ + +
+
+

基础服务目录

点击卡片,通过封装好的 ansible-playbook 一键部署标准化基础服务

+
+
+
+
My

MySQL

+
一主多从,自动注册进 open-cdm 数据源,支持 LDAP 账号统一审核 SQL 上线。
+
roles/mysql-deployv8.0.36
+
+
+
Rd

Redis

+
支持 Standalone / Sentinel / Cluster,部署完成后自动注册进 CacheCloud。
+
roles/redis-deployv7.2
+
+
+
Or

openresty

+
容器化部署在 K8s 内,作为业务边缘网关,支持灰度路由配置。
+
roles/openresty-deployv1.25
+
+
+
Dp

dpvs

+
四层负载均衡,直接管理宿主机网络命名空间,不纳入容器编排。
+
roles/dpvs-deployv1.9
+
+
+
Pg

PgSQL

+
流复制主从架构,规划中 · 第二期接入 open-cdm 统一审核体系。
+
roles/pgsql-deploy规划中
+
+
+
+

接入新服务

+
封装新的 ansible-playbook,注册进基础服务目录
+
+
+
+
+ + +
+
+

组件实例

所有基础组件实例的统一台账,关联 CMDB / 子系统注册状态

+
+
+
+ + + + + + + + + + +
实例类型业务线所在集群状态子系统注册
mysql-kodo-order-01MySQL 8.0 主从kodorke2-bj-prod-01● 运行中open-cdm ✓
redis-las-feature-clusterRedis Clusterlasrke2-sh-prod-01● 运行中CacheCloud ✓
redis-lingxi-sessionRedis Sentinellingxirke2-ali-sz-01● 同步中CacheCloud 同步中…
mysql-las-billing-01MySQL 8.0 主从lasrke2-sh-prod-01● 运行中open-cdm ✓
mysql-ltoken-account-01MySQL 8.0 主从ltokenrke2-bj-prod-01● 运行中open-cdm ✓
redis-maas-infer-cache-01Redis Standalonemaasrke2-ali-sz-01● 运行中CacheCloud ✓
+ +
+
+
+ + +
+
+

资源管理

统一纳管物理机与虚机资源 · 基础数据来自 SINA CMDB,云上虚机由阿里云 / AWS / 七牛 LAS 增量同步回写

+ +
+ +
+
资源总数
658
物理机 146 · 虚机 512
+
SINA CMDB
368
物理机 146 · 虚机 222
+
阿里云同步
154
ECS · 增量同步
+
AWS / 七牛 LAS 同步
136
AWS 58 · 七牛 LAS 78
+
最近一次同步
● 正常
07:39:10 · 新增 3 条
+
+ +
+ + + + + +
+ +
+

资源台账 · 物理机 / 虚机

SINA CMDB asset items + 云厂商同步增量
+
+ + + + + + + + + + + +
主机名资产编号类型机房 / 区域内网 IP规格业务线数据来源状态
xs291SERV00003502物理机华东·杭州下沙10.34.37.5220C/192G/13.52TkodoSINA CMDB● production
yzh-las-014SERV00004187虚机华北·YZH10.21.4.21432C/128G/4.0TlasSINA CMDB● production
jf-bm-118SERV00004290物理机华南·JF10.45.2.1816C/64G/2.0TlingxiSINA CMDB● production
ali-ecs-sz-0231—虚机阿里云·华南172.18.4.3116C/64G/500Gltoken阿里云同步● production
aws-us-i-0a13fe2—虚机AWS · 美国10.66.2.128C/32G/200GmaasAWS 同步● production
sg-las-007SERV00004511虚机七牛 LAS · 新加坡10.88.1.0716C/64G/2.0Tlas七牛 LAS 同步● idle
hk-bm-001SERV00004602物理机香港 IDC10.90.0.118C/32G/1.0T未分配SINA CMDB● production
+ +
+
+ +
+ 同步与去重策略:SINA CMDB 作为物理机 / 虚机的基础数据底座;阿里云、AWS、七牛 LAS 的虚机资源由各云 OpenAPI 定时增量同步回写。同步时先以唯一标识(资产编号 / 实例 ID / 内网 IP)查询数据库中是否已存在记录:已存在则跳过更新,保留 CMDB 侧人工维护的字段;不存在则新增记录并标记对应数据来源(SINA CMDB / 阿里云同步 / AWS 同步 / 七牛 LAS 同步),避免重复纳管与覆盖人工修正数据。 +
+
+ + +
+
+

服务管理

同步全部机房 Consul 注册中心服务目录,统一查看服务名 / 服务 IP / 业务标签 / 实例数

+ +
+ +
+
接入 Consul Datacenter
7
国内 3 · 海外 4
+
服务总数
186
去重后唯一服务名
+
服务实例总数
842
所有机房注册 IP 汇总
+
健康实例占比
98.6%
12 个实例 critical
+
最近同步
● 正常
07:41:05 · 间隔 30s
+
+ +
+ + + + +
+ +
+

服务台账 · 按 Consul Datacenter 同步

数据源:Consul Catalog API(/v1/catalog/services · /v1/health/service)
+
+ + + + + + + + + + + +
服务名机房 / Datacenter业务标签实例数健康实例示例 IP状态
kodo-gateway-svcYZHkodo1212 / 1210.21.4.51● 健康
kodo-upload-svcXSkodo1010 / 1010.34.37.66● 健康
las-search-apiXSlas1817 / 1810.34.37.20● 部分异常
las-order-svc达拉斯 IDClas55 / 510.66.2.20● 健康
lingxi-render-svcJFlingxi66 / 610.45.2.30● 健康
ltoken-wallet-svcYZHltoken88 / 810.21.4.88● 健康
maas-infer-svc新加坡 IDCmaas43 / 410.88.1.40● 部分异常
+ +
+
+ +
+ 同步方式:xinfra 定时调用各机房 Consul 集群的 Catalog API(/v1/catalog/services、/v1/health/service)按 Datacenter 维度拉取服务目录,汇总服务名、注册 IP、健康检查状态以及 Consul service tag 中携带的业务标签(kodo / las / lingxi / ltoken / maas),实现跨机房服务的统一查看与健康巡检,不改变各机房 Consul 自身的注册与发现链路。 +
+
+
+
+

监控 / 日志 / 告警

VictoriaMetrics 指标 · Zabbix 硬件状态 · ELK 日志中心 · 夜莺(Nightingale)统一告警引擎对接 qpass

+
+
+
+

VictoriaMetrics · 指标概览

K8s / 容器 / 业务指标
+
+ + + + + +
七机房采集节点数128
活跃时序数量42.6M
Prometheus 接口接入● 正常
Grafana 仪表盘数37
+
+
+
+

Zabbix · 硬件健康

IPMI / 温度 / 电源 / 风扇
+
+ + + + + +
物理机监控覆盖186 / 186
当前告警● 2 条(风扇转速异常)
网络设备健康● 正常
存储健康度● 正常
+
+
+
+
+

日志 + 统一告警

Filebeat → Kafka → ES → Kibana · VM + Zabbix → qpass
+
+
07:39:10CMDB 采集器同步完成:xs291 · 华东-杭州下沙机房
+
07:38:55[Zabbix] 告警:yzh-las-014 风扇转速低于阈值(FAN_6: 1920 RPM)
+
07:38:02[VictoriaMetrics] 七机房抓取任务全部正常
+
07:35:41[ELK] sg-las-007 应用日志接入 Kafka topic:las-sg-app
+
07:30:00[qpass] 告警已合并推送:1 条硬件告警 + 0 条业务告警
+
+
+
+ + +
+
+

任务中心

所有 ansible-playbook / Wayne 发布任务的执行记录与实时日志

+
+
+
+

任务列表

+
+ + + + + + + +
● 执行中RKE2 节点加入 · bj-node-061roles/rke2-node-join
● 成功MySQL 主从部署 · kodoroles/mysql-deploy
● 成功Redis Cluster 部署 · lasroles/redis-deploy
● 失败openresty 网关部署roles/openresty-deploy
● 成功业务线标签同步 · LDAPinternal/label-sync
● 成功MySQL 主从部署 · ltokenroles/mysql-deploy
+ +
+
+
+

实时日志 · RKE2 节点加入

WebSocket 流式输出
+
+
10:42:01PLAY [rke2-node-join] **********************
+
10:42:02TASK [初始化内核参数] ...
+
10:42:04ok: [bj-node-061]
+
10:42:05TASK [安装 containerd] ...
+
10:42:18ok: [bj-node-061]
+
10:42:19TASK [写入 RKE2 node-labels: business-line=kodo] ...
+
10:42:20changed: [bj-node-061] => labels applied
+
10:42:21TASK [加入集群 rke2-bj-prod-01] ...
+
10:42:33▌ 等待节点 Ready...
+
+
+
+
+ + +
+
+

配置中心管理

Apollo 配置中心(携程开源)· 按机房部署 Config Service Cluster,Portal 统一入口管理

+ ● 运行中 +
+ +
+
接入机房数
3 / 7
国内 3 已接入 · 海外 4 建设中
+
Apollo Cluster
7
按机房 1:1 划分
+
配置项总数
1,260
Namespace 38 个
+
接入业务线
2 / 5
kodo · las 已接入
+
同步状态
● 正常
最近发布 09:12:30
+
+ +
+

统一入口

Apollo Portal · LDAP 单点登录
+
+
+

Apollo Portal

apollo.xinfra.internal
+

统一管理 7 个机房 Config Service Cluster 的配置发布、灰度、回滚与变更审计,所有机房配置项均可在此单一入口检索与编辑,发布后由各机房 Config Service 就近下发。

+
LDAP 原生配置接入 · 已上线
+ 打开 Apollo Portal ↗ +
+
+
+ +
+

部署架构说明

Config Service / Admin Service / Portal
+
+
+
+
Portal + Admin Service YZH 主中心统一部署
+
配置发布、权限、审计统一入口
+
LDAP 账号统一登录
+
跨机房管理所有 Cluster
+
+
+
Config Service 每机房独立集群
+
Cluster = 机房标识(yzh / xs / jf ...)
+
客户端就近读取,降低跨机房延迟
+
单机房故障不影响其他机房取配置
+
+
+
配置数据同步 MySQL 主从 + 缓存
+
ConfigDB / PortalDB 部署在 YZH
+
各机房 Config Service 本地缓存全量配置
+
网络抖动时仍可降级提供本地缓存配置
+
+
+
+
+ +
+

机房配置中心列表

Cluster 维度 · Config Service 部署明细
+
+ + + + + + + + + + + +
机房 / 区域Apollo ClusterConfig Service 地址承载方式接入业务线配置项数状态
YZH 机房cluster=yzhconfig-yzh.xinfra.internal:8080容器化 · K8s Servicekodo486● 运行中
XS 机房cluster=xsconfig-xs.xinfra.internal:8080容器化 · K8s Servicelas398● 运行中
JF 机房cluster=jfconfig-jf.xinfra.internal:8080容器化 · K8s Service灵矽376● 灰度接入中
达拉斯 IDCcluster=dallas—容器化 · K8s Service—0● 建设中
新加坡 IDCcluster=singapore—容器化 · K8s Service—0● 建设中
香港 IDCcluster=hk—容器化 · K8s Service—0● 待启动
东南亚 IDCcluster=sea—容器化 · K8s Service—0● 待启动
+
+
+ +
+ 使用说明:YZH / XS 两机房已正式运行,kodo / las 业务线配置已接入;JF 机房处于灰度接入阶段。所有机房的配置统一通过 Apollo Portal 单一入口检索、编辑与发布,发布后由对应机房 Config Service 就近下发给客户端,机房间故障隔离、互不影响。达拉斯、新加坡、香港、东南亚四个海外机房按第三期规划陆续建设 Config Service 集群,建成后接入对应业务线配置。 +
+
+ + +
+
+

子系统导航

统一 LDAP 账号,点击即用免二次登录(同账号同密码)

+
+
+
+

Wayne

多集群发布平台
+

业务容器发布、命名空间与配额管理,复用 Wayne 原生多租户能力。

+
LDAP 原生配置接入 · 零代码
+
+
+

open-cdm

SQL 审核与变更平台
+

数据库 SQL 上线统一审核,支持 LDAP 用户组到角色的自动映射。

+
LDAP 原生配置接入 · 零代码
+
+
+

CacheCloud

Redis 统一管理平台
+

Redis 实例全生命周期管理,登录与监控运维统一入口。

+
LDAP 接入改造中 · 预计 3 天
+
+
+

qpass

统一告警 / 值班平台
+

夜莺、Zabbix、VictoriaMetrics 告警统一收敛与值班通知,按 P0/P1 分级推送。

+
LDAP 原生配置接入 · 零代码
+
+
+

Grafana

指标可视化平台
+

对接 VictoriaMetrics 数据源,K8s / 容器 / 业务指标统一仪表盘展示。

+
LDAP 原生配置接入 · 零代码
+
+
+

Apollo

配置中心(携程开源)
+

统一配置管理,按机房 Cluster 隔离,支持灰度发布、版本回滚与变更审计。

+
LDAP 接入改造中 · 规划中
+
+
+
+ +
+
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ + + + + + +