diff --git a/README.md b/README.md index 2522b5a..560e50c 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # AIOps 智能运维平台 -> 企业级云原生智能运维解决方案,集成资产管理、应用发布、监控告警、自动化运维和 AI 智能分析。 +> 企业级云原生智能运维解决方案,集成资产管理、Kubernetes 管理、应用发布、监控告警、自动化运维和 AI 智能分析。 ## 技术栈 @@ -9,13 +9,14 @@ - Tailwind CSS + shadcn/ui - Zustand (状态管理) / TanStack Query (数据获取) - Recharts (图表) / Lucide React (图标) -- xterm.js (WebSocket 终端) +- CodeMirror 6 (YAML 编辑器) / xterm.js (WebSocket 终端) ### 后端 - Go 1.24 / Gin Web Framework - GORM (ORM) / MySQL 8.0 / Redis 7 - JWT 认证 / Zap 日志 / Viper 配置 - WebSocket (Gorilla) / PTY 终端 (creack/pty) +- 自研轻量 Kubernetes HTTP 客户端(channel.k8s.io WebSocket 协议) ### Agent - Go 1.24 静态编译 (CGO_ENABLED=0) @@ -27,7 +28,7 @@ | 方式 | 命令 | 架构 | 适用场景 | |------|------|------|----------| | **① 独立二进制** | `./run.sh build` → `./run.sh binary` | 单文件,前后端一体 | 无 Docker/K8s 环境 | -| **② Kubernetes** | `./run.sh k8s deploy` | Embed 单容器 + MySQL/Redis StatefulSet | 生产集群,devops 命名空间 | +| **② Kubernetes** | `./run.sh kubernetes deploy` | Embed 单容器 + MySQL/Redis StatefulSet | 生产集群,devops 命名空间 | | **③ Docker Compose** | `./run.sh docker up` | 4 容器 (MySQL+Redis+Backend+Nginx) | 单机生产,开发/测试 | 统一入口 `./run.sh`,详见 `./run.sh help`。 @@ -51,6 +52,27 @@ ./run.sh docker down # 停止 ``` +### Kubernetes 部署 + +```bash +# 一键部署到 devops 命名空间 +./run.sh kubernetes deploy + +# 访问: http://:30080 + +# 运维 +./run.sh kubernetes status # 资源状态 +./run.sh kubernetes logs # 应用日志 +./run.sh kubernetes upgrade # 重新构建 + 滚动更新 +./run.sh kubernetes exec # 进入容器 Shell +./run.sh kubernetes mysql # 进入 MySQL CLI +./run.sh kubernetes redis # 进入 Redis CLI +./run.sh kubernetes scale 3 # 扩缩容 +./run.sh kubernetes port-forward # 端口转发到本机 +./run.sh kubernetes delete # 删除所有 K8s 资源(保留 PVC) +./run.sh kubernetes build # 仅构建 embed 镜像 +``` + ### 独立二进制部署 ```bash @@ -63,20 +85,6 @@ ./backend/aiops --db-driver mysql --db-host ... # MySQL 模式 ``` -### Kubernetes 部署 - -```bash -# 一键部署到 devops 命名空间 -./run.sh k8s deploy - -# 访问: http://:30080 - -# 运维 -./run.sh k8s status # 资源状态 -./run.sh k8s logs # 应用日志 -./run.sh k8s upgrade # 滚动更新 -``` - ### 本地开发 ```bash @@ -87,6 +95,16 @@ cd frontend && npm run dev cd backend && go run ./cmd/ ``` +### Agent 构建 + +```bash +./run.sh build agent # 交叉编译 Agent (amd64+arm64) + +# 验证 +./agent/bin/aiops-agent-linux-amd64 version +./agent/bin/aiops-agent-linux-amd64 output -top-n 3 # Zabbix 风格指标输出 +``` + ### 默认账号 - 用户名: `admin` @@ -97,7 +115,7 @@ cd backend && go run ./cmd/ ``` aiops/ ├── frontend/ # 前端 (React + TypeScript) -│ ├── src/components/ # dashboard/server/k8s/monitor/deploy/aiops... +│ ├── src/components/ # dashboard/server/kubernetes/monitor/deploy/aiops... │ ├── src/services/ # API + HTTP 封装 │ ├── src/store/ # Zustand 状态管理 │ └── Dockerfile # nginx:alpine 镜像 @@ -133,15 +151,24 @@ aiops/ | 模块 | 说明 | |------|------| -| 仪表盘 | 成本统计、告警聚合、Top 资源、SSL 提醒 | -| 资产管理 | 服务器 CRUD、批量导入、WebShell、云账号/域名/账单、K8s 集群 | -| 应用发布 | CI/CD 流水线(GitLab CI 风格可视化)、发布配置、发布权限、工具配置 | -| 监控中心 | 监控大屏、指标监控、链路追踪、告警中心、数据源 | -| 自动化运维 | 定时任务、脚本库(Shell/Python)、远程执行(Go-native SSH) | -| AIOps 智能 | AI 智能助手、告警分析、容量预测 | +| 仪表盘 | 成本统计、告警聚合、Top 资源、SSL 提醒、趋势图表 | +| 资产管理 | 服务器 CRUD、批量导入、WebShell、云账号/域名/账单 | +| Kubernetes 管理 | 多集群管理、Deployment 三模式编辑器(查看/可视化编辑/YAML)、Node/Pod/Service/Ingress、kubectl 终端、事件聚合、多集群对比、Namespace 管理 | +| 应用发布 | CI/CD 流水线(GitLab CI 风格可视化)、发布配置、SSH 主机 + Kubernetes 双路径部署 | +| 监控中心 | 监控大屏、主机指标(CPU/内存/磁盘/网络/进程/端口/FD)、告警规则引擎、飞书/钉钉通知 | +| 自动化运维 | 定时任务、脚本库(Shell/Python)、远程执行(Go-native SSH)、Ansible | +| AIOps 智能 | AI 智能助手(6 种 LLM)、告警分析、容量预测 | | 资源申请 | 云服务器/应用部署申请审批 | | 系统管理 | 用户管理、角色权限、操作审计、终端审计、凭证配置、系统设置 | +### Kubernetes 管理亮点 + +- **Deployment 三模式编辑器**: 查看模式 / 可视化编辑(5 Tab: 基本信息·容器信息·存储挂载·高级设置·服务路由)/ YAML 编辑(CodeMirror 6 语法高亮) +- **StatefulSet/DaemonSet**: 完整详情页(更新策略/选择器/PVC 模板/Init Containers) +- **Pod 交互**: 文件浏览器(上传/下载)、exec 终端(WebSocket channel.k8s.io)、日志流 +- **集群运维**: 事件聚合看板、多集群对比(雷达图/柱状图)、Node 详情(资源分配率/污点/容器运行时)、Namespace CRUD(资源配额) +- **自研轻量客户端**: 不依赖 client-go,net/http + WebSocket 直连 K8s API + ## License MIT diff --git a/backend/aiops-backend b/backend/aiops-backend index 8f22d5f..749cc76 100755 Binary files a/backend/aiops-backend and b/backend/aiops-backend differ diff --git a/backend/internal/api/handlers/agent.go b/backend/internal/api/handlers/agent.go index 6e233ca..5954dc0 100644 --- a/backend/internal/api/handlers/agent.go +++ b/backend/internal/api/handlers/agent.go @@ -540,7 +540,7 @@ func (h *AgentHandler) GetPortPolicyForAgent(c *gin.Context) { hostname := c.Query("hostname") if hostname == "" { c.JSON(http.StatusOK, models.Response{Code: 200, Message: "success", Data: models.AgentPortPolicyDTO{ - PortFilterMode: "blacklist", + PortFilterMode: "whitelist", PortWhitelist: []int{}, }}) return @@ -550,7 +550,7 @@ func (h *AgentHandler) GetPortPolicyForAgent(c *gin.Context) { if err := h.db.Where("hostname = ?", hostname).First(&policy).Error; err != nil { c.JSON(http.StatusOK, models.Response{Code: 200, Message: "success", Data: models.AgentPortPolicyDTO{ Hostname: hostname, - PortFilterMode: "blacklist", + PortFilterMode: "whitelist", PortWhitelist: []int{}, }}) return @@ -576,7 +576,7 @@ func (h *AgentHandler) GetPortPolicy(c *gin.Context) { if err := h.db.Where("hostname = ?", hostname).First(&policy).Error; err != nil { c.JSON(http.StatusOK, models.Response{Code: 200, Message: "success", Data: models.AgentPortPolicyDTO{ Hostname: hostname, - PortFilterMode: "blacklist", + PortFilterMode: "whitelist", PortWhitelist: []int{}, }}) return diff --git a/backend/internal/api/handlers/dashboard.go b/backend/internal/api/handlers/dashboard.go index eb99fc3..9743c93 100644 --- a/backend/internal/api/handlers/dashboard.go +++ b/backend/internal/api/handlers/dashboard.go @@ -1,6 +1,8 @@ package handlers import ( + "context" + "encoding/json" "fmt" "math" "net/http" @@ -8,6 +10,7 @@ import ( "time" "ezops/internal/models" + ezredis "ezops/pkg/redis" "github.com/gin-gonic/gin" "gorm.io/gorm" @@ -15,12 +18,13 @@ import ( // DashboardHandler 仪表盘处理器 type DashboardHandler struct { - db *gorm.DB + db *gorm.DB + cache ezredis.Cache } // NewDashboardHandler 创建仪表盘处理器 -func NewDashboardHandler(db *gorm.DB) *DashboardHandler { - return &DashboardHandler{db: db} +func NewDashboardHandler(db *gorm.DB, cache ezredis.Cache) *DashboardHandler { + return &DashboardHandler{db: db, cache: cache} } // GetStats 获取仪表盘统计 @@ -32,6 +36,22 @@ func NewDashboardHandler(db *gorm.DB) *DashboardHandler { // @Success 200 {object} models.Response{data=models.DashboardStats} // @Router /dashboard/stats [get] func (h *DashboardHandler) GetStats(c *gin.Context) { + const cacheKey = "dashboard:stats" + const cacheTTL = 30 * time.Second + + // 尝试从 Redis 缓存读取 + if cached, err := h.cache.Get(c.Request.Context(), cacheKey); err == nil && cached != "" { + var stats models.DashboardStats + if json.Unmarshal([]byte(cached), &stats) == nil { + c.JSON(http.StatusOK, models.Response{ + Code: 200, + Message: "success", + Data: stats, + }) + return + } + } + var stats models.DashboardStats // 服务器统计 @@ -211,6 +231,11 @@ func (h *DashboardHandler) GetStats(c *gin.Context) { } stats.ExpiringCerts = expiringCerts + // 写入 Redis 缓存(异步,缓存失败不影响响应) + if data, err := json.Marshal(stats); err == nil { + _ = h.cache.Set(context.Background(), cacheKey, string(data), cacheTTL) + } + c.JSON(http.StatusOK, models.Response{ Code: 200, Message: "success", diff --git a/backend/internal/api/handlers/server.go b/backend/internal/api/handlers/server.go index f9c1322..08c7932 100644 --- a/backend/internal/api/handlers/server.go +++ b/backend/internal/api/handlers/server.go @@ -1,11 +1,15 @@ package handlers import ( + "context" + "encoding/json" "net/http" "strconv" + "time" "ezops/internal/models" "ezops/pkg/crypto" + ezredis "ezops/pkg/redis" "github.com/gin-gonic/gin" "gorm.io/gorm" @@ -14,12 +18,13 @@ import ( // ServerHandler 服务器处理器 type ServerHandler struct { db *gorm.DB + cache ezredis.Cache crypt *crypto.SecretBox } // NewServerHandler 创建服务器处理器 -func NewServerHandler(db *gorm.DB, masterKey string) *ServerHandler { - return &ServerHandler{db: db, crypt: crypto.NewSecretBox(masterKey)} +func NewServerHandler(db *gorm.DB, masterKey string, cache ezredis.Cache) *ServerHandler { + return &ServerHandler{db: db, crypt: crypto.NewSecretBox(masterKey), cache: cache} } // recordServerAudit 记录服务器操作审计日志 // Logan.Li @@ -66,6 +71,25 @@ func (h *ServerHandler) ListServers(c *gin.Context) { return } + status := c.Query("status") + regionID := c.Query("region_id") + + // 构建缓存键(按查询参数区分) + cacheKey := "servers:list:" + query.Keyword + ":" + status + ":" + regionID + + ":" + strconv.Itoa(query.Page) + ":" + strconv.Itoa(query.PageSize) + const cacheTTL = 10 * time.Second + + // 尝试从 Redis 缓存读取 + if h.cache != nil { + if cached, err := h.cache.Get(c.Request.Context(), cacheKey); err == nil && cached != "" { + var resp models.Response + if json.Unmarshal([]byte(cached), &resp) == nil { + c.JSON(http.StatusOK, resp) + return + } + } + } + db := h.db.Model(&models.Server{}) // 关键词搜索 @@ -98,14 +122,23 @@ func (h *ServerHandler) ListServers(c *gin.Context) { servers[i].HasAuth = servers[i].Password != "" || servers[i].SSHKey != "" } - c.JSON(http.StatusOK, models.Response{ + resp := models.Response{ Code: 200, Message: "success", Data: models.ListResponse{ List: servers, Total: total, }, - }) + } + + // 写入 Redis 缓存(异步,缓存失败不影响响应) + if h.cache != nil { + if data, err := json.Marshal(resp); err == nil { + _ = h.cache.Set(context.Background(), cacheKey, string(data), cacheTTL) + } + } + + c.JSON(http.StatusOK, resp) } // GetServer 获取服务器详情 diff --git a/backend/internal/api/routes/routes.go b/backend/internal/api/routes/routes.go index 47fd938..e9537fe 100644 --- a/backend/internal/api/routes/routes.go +++ b/backend/internal/api/routes/routes.go @@ -168,7 +168,7 @@ func Register(r *gin.Engine, db *gorm.DB, log *zap.Logger, cfg *config.Config, c } // 仪表盘路由 - dashboardHandler := handlers.NewDashboardHandler(db) + dashboardHandler := handlers.NewDashboardHandler(db, redisCache) dashboard := authorized.Group("/dashboard") { dashboard.GET("/stats", dashboardHandler.GetStats) @@ -178,7 +178,7 @@ func Register(r *gin.Engine, db *gorm.DB, log *zap.Logger, cfg *config.Config, c } // 服务器路由 - serverHandler := handlers.NewServerHandler(db, cfg.JWT.Secret) + serverHandler := handlers.NewServerHandler(db, cfg.JWT.Secret, redisCache) servers := authorized.Group("/servers") { servers.GET("", serverHandler.ListServers) diff --git a/deploy/kubernetes/README.md b/deploy/kubernetes/README.md index 9b63758..6e0032c 100644 --- a/deploy/kubernetes/README.md +++ b/deploy/kubernetes/README.md @@ -45,19 +45,19 @@ AIOps 平台在 Kubernetes 上的部署清单(Go/Gin 后端 + go:embed 前端 ```bash # 构建镜像 + 部署全部资源 -./run.sh k8s deploy +./run.sh kubernetes deploy # 查看状态 -./run.sh k8s status +./run.sh kubernetes status # 查看日志 -./run.sh k8s logs +./run.sh kubernetes logs # 更新(重新构建镜像 + 滚动更新) -./run.sh k8s upgrade +./run.sh kubernetes upgrade # 清理 -./run.sh k8s delete +./run.sh kubernetes delete ``` ### 方式二:手动 kubectl @@ -143,7 +143,7 @@ kubectl -n devops get pvc ## 清理 ```bash -./run.sh k8s delete +./run.sh kubernetes delete # 或手动(持久卷需单独删) kubectl delete -f deploy/kubernetes/ diff --git a/docs/README.md b/docs/README.md index 8bb467c..494dec4 100644 --- a/docs/README.md +++ b/docs/README.md @@ -13,12 +13,24 @@ | [开发规范](./development-guide.md) | 代码规范、Git 工作流 | | [部署指南](./deployment.md) | 生产环境部署 | | [开发日志](./dev-log.md) | 详细开发日志(按日期记录) | +| [Redis 缓存策略](./redis-caching-strategy.md) | Redis 缓存使用现状与优化方案 | ## 设计文档 | 文档 | 说明 | |------|------| -| [ROADMAP](./ROADMAP.md) | 项目路线图 | | [PDD 计划](./PDD_PLAN.md) | 产品驱动开发计划 | | [项目摘要](./PROJECT_SUMMARY.md) | 项目整体概述 | | [后端摘要](./BACKEND_SUMMARY.md) | 后端架构概述 | + +## 根目录文档 + +以下文档位于项目根目录: + +| 文档 | 说明 | +|------|------| +| [ROADMAP.md](../ROADMAP.md) | K8s 管理功能演进路线图 | +| [TDD_PLAN.md](../TDD_PLAN.md) | TDD 验证计划 | +| [PROJECT_EVALUATION.md](../PROJECT_EVALUATION.md) | K8s 管理功能评估基线 | +| [README.md](../README.md) | 项目主说明 | +| [CLAUDE.md](../CLAUDE.md) | AI 助手指引 | diff --git a/docs/ROADMAP.md b/docs/ROADMAP.md deleted file mode 100644 index 4636c12..0000000 --- a/docs/ROADMAP.md +++ /dev/null @@ -1,379 +0,0 @@ -# AIOps 智能运维平台 - 产品路线图 - -> 版本: v1.0.0 -> 更新日期: 2025-04-14 -> 状态: 开发中 - ---- - -## 概述 - -AIOps 智能运维平台是一个面向企业级用户的云原生智能运维解决方案,集成了资产管理、应用发布、监控告警、自动化运维和AI智能分析等核心能力。本路线图规划了产品从MVP到成熟版本的演进路径。 - ---- - -## 版本规划 - -### Phase 1: MVP 核心功能 (已完成) - v0.1.0 - -**目标**: 构建基础运维平台,实现核心资产管理能力 - -#### 已完成功能 - -- [x] **仪表盘** - - 成本费用月维度统计 - - 告警消息聚合展示 - - Top5 CPU/内存/磁盘使用率 - - SSL证书到期提醒 - - 系统健康度概览 - -- [x] **资产管理** - - 服务器管理 (CRUD、批量导入、WebShell) - - 云账号管理 (多云平台接入) - - 域名管理 - - 区域管理 - - 云平台管理 - - 资源模型管理 - -- [x] **K8s集群管理** - - 集群列表管理 - - 节点管理 - - 工作负载管理 (Deployment/Service/Ingress) - - 架构拓扑可视化 - -- [x] **应用发布** - - 流水线配置管理 - - 发布管理 (新建发布、发布历史) - - 多环境支持 - -- [x] **监控告警** - - 指标监控 - - 告警中心 - - 日志能力 - - 链路追踪 - - Grafana风格监控大屏 - -- [x] **自动化运维** - - 定时任务管理 - - 脚本库 - - Ansible Playbook执行 - -- [x] **AIOps智能** - - AI智能助手 (大模型对话) - - SQL数据变更审计 - -- [x] **系统管理** - - 用户管理 - - 角色权限 - - 操作审计 - - 系统设置 - ---- - -### Phase 2: AI能力增强 (当前) - v0.2.0 - -**目标**: 深度集成AI大模型,实现智能运维能力 - -#### 进行中功能 - -- [x] **AI告警智能分析** - - 告警根因自动分析 - - 相似历史案例匹配 - - 自动修复脚本生成 - - 修复建议推荐 - -- [x] **AI脚本生成器** - - 自然语言生成运维脚本 - - 支持Bash/Python/Ansible - - 脚本模板库 - - 一键测试执行 - -- [x] **AI故障诊断** - - 故障症状智能分析 - - 多维度根因定位 - - 解决方案推荐 - - 诊断历史管理 - -- [x] **AI预测分析** - - 关键指标趋势预测 - - 容量规划预警 - - 异常事件预测 - - 资源优化建议 - -- [x] **AIOps智能运维中心** - - 统一AI功能入口 - - AI能力状态监控 - - 多模型提供商支持 - -#### 技术栈 - -``` -前端: React 18 + TypeScript + Vite + Tailwind CSS + shadcn/ui -后端: Go + Gin + GORM -AI集成: OpenAI / Anthropic / Azure OpenAI / Ollama -监控: Prometheus + Grafana + SkyWalking -数据库: MySQL + Redis -消息队列: RabbitMQ / Kafka -``` - ---- - -### Phase 3: 企业级功能 - v0.3.0 (计划 2025-Q3) - -**目标**: 增强企业级特性,提升安全性和可扩展性 - -#### 计划功能 - -- [ ] **多云管理平台** - - AWS/阿里云/腾讯云/华为云统一接入 - - 云资源自动发现 - - 成本分析和优化建议 - - 跨云资源调度 - -- [ ] **安全合规** - - 安全基线检查 - - 漏洞扫描集成 - - 合规报告生成 - - 敏感操作审计 - -- [ ] **高级监控** - - 自定义仪表盘 - - 告警规则智能推荐 - - 告警降噪和聚合 - - 多渠道告警通知 - -- [ ] **CI/CD增强** - - 蓝绿发布支持 - - 金丝雀发布 - - 自动回滚 - - 发布审批流程 - -- [ ] **容器平台** - - 容器镜像管理 - - Helm Chart仓库 - - 服务网格集成 - - Serverless支持 - ---- - -### Phase 4: 智能化升级 - v0.4.0 (计划 2025-Q4) - -**目标**: 实现全栈智能化,降低人工干预 - -#### 计划功能 - -- [ ] **智能自愈** - - 故障自动检测 - - 自动修复执行 - - 修复效果验证 - - 修复策略学习 - -- [ ] **智能调度** - - 资源自动扩缩容 - - 负载均衡优化 - - 成本最优调度 - - 预测性维护 - -- [ ] **知识图谱** - - 运维知识库 - - 故障知识图谱 - - 智能问答增强 - - 经验沉淀复用 - -- [ ] **AIOps工作台** - - 个性化运维视图 - - 智能任务推荐 - - 运维效率分析 - - 团队协作增强 - ---- - -### Phase 5: 生态扩展 - v1.0.0 (计划 2026-Q1) - -**目标**: 构建开放生态,支持第三方集成 - -#### 计划功能 - -- [ ] **开放API平台** - - RESTful API完整覆盖 - - GraphQL支持 - - Webhook机制 - - SDK开发包 - -- [ ] **插件市场** - - 插件开发框架 - - 官方插件库 - - 第三方插件审核 - - 插件交易机制 - -- [ ] **社区生态** - - 开源部分核心模块 - - 开发者文档 - - 技术社区 - - 最佳实践分享 - -- [ ] **企业版功能** - - 高可用架构 - - 多租户支持 - - SLA保障 - - 专属技术支持 - ---- - -## 技术架构演进 - -### 当前架构 (v0.2.0) - -``` -┌─────────────────────────────────────────────────────────────┐ -│ 前端层 │ -│ React + TypeScript + Vite + Tailwind CSS + shadcn/ui │ -└─────────────────────────────────────────────────────────────┘ - │ -┌─────────────────────────────────────────────────────────────┐ -│ API网关层 │ -│ Go + Gin + Middleware (Auth/RateLimit) │ -└─────────────────────────────────────────────────────────────┘ - │ -┌─────────────────────────────────────────────────────────────┐ -│ 业务服务层 │ -│ ┌──────────┬──────────┬──────────┬──────────┬──────────┐ │ -│ │ 资产管理 │ 应用发布 │ 监控告警 │ 自动化 │ AIOps │ │ -│ └──────────┴──────────┴──────────┴──────────┴──────────┘ │ -└─────────────────────────────────────────────────────────────┘ - │ -┌─────────────────────────────────────────────────────────────┐ -│ 数据层 │ -│ MySQL + Redis + Prometheus + Elasticsearch │ -└─────────────────────────────────────────────────────────────┘ - │ -┌─────────────────────────────────────────────────────────────┐ -│ AI服务层 │ -│ OpenAI / Anthropic / Azure OpenAI / Ollama │ -└─────────────────────────────────────────────────────────────┘ -``` - -### 目标架构 (v1.0.0) - -``` -┌─────────────────────────────────────────────────────────────┐ -│ 前端层 │ -│ React + 移动端App + CLI工具 + 可视化大屏 │ -└─────────────────────────────────────────────────────────────┘ - │ -┌─────────────────────────────────────────────────────────────┐ -│ 网关层 │ -│ Kong/Nginx + 负载均衡 + 服务发现 │ -└─────────────────────────────────────────────────────────────┘ - │ -┌─────────────────────────────────────────────────────────────┐ -│ 微服务层 │ -│ ┌────────┬────────┬────────┬────────┬────────┬────────┐ │ -│ │资产服务 │发布服务 │监控服务 │自动化 │AI服务 │平台服务│ │ -│ └────────┴────────┴────────┴────────┴────────┴────────┘ │ -└─────────────────────────────────────────────────────────────┘ - │ -┌─────────────────────────────────────────────────────────────┐ -│ 数据平台层 │ -│ 数据湖 + 实时计算 + 数据仓库 + 机器学习平台 │ -└─────────────────────────────────────────────────────────────┘ -``` - ---- - -## AI能力路线图 - -### 当前能力 (v0.2.0) - -| 能力模块 | 功能描述 | 完成度 | -|---------|---------|--------| -| AI智能助手 | 大模型对话、运维知识问答 | 100% | -| 告警智能分析 | 根因分析、修复建议 | 100% | -| 脚本生成器 | 自然语言生成脚本 | 100% | -| 故障诊断 | 症状分析、方案推荐 | 100% | -| 预测分析 | 趋势预测、容量规划 | 100% | - -### 计划能力 (v0.4.0) - -| 能力模块 | 功能描述 | 预计完成 | -|---------|---------|----------| -| 智能自愈 | 故障自动检测和修复 | 2025-Q4 | -| 智能调度 | 资源自动优化调度 | 2025-Q4 | -| 知识图谱 | 运维知识沉淀和复用 | 2025-Q4 | -| 智能推荐 | 个性化运维建议 | 2025-Q4 | - ---- - -## 集成路线图 - -### 监控集成 - -- [x] Prometheus -- [x] Grafana -- [x] SkyWalking -- [x] Zabbix -- [ ] ELK Stack -- [ ] Jaeger -- [ ] Datadog - -### 云平台集成 - -- [x] 阿里云 -- [x] 腾讯云 -- [x] AWS -- [ ] 华为云 -- [ ] Azure -- [ ] Google Cloud - -### DevOps集成 - -- [x] GitLab -- [x] Jenkins -- [ ] GitHub Actions -- [ ] ArgoCD -- [ ] Harbor - -### AI模型集成 - -- [x] OpenAI GPT-4 -- [x] Anthropic Claude -- [x] Azure OpenAI -- [x] Ollama (本地) -- [ ] 文心一言 -- [ ] 通义千问 -- [ ] Llama 3 - ---- - -## 里程碑 - -| 里程碑 | 版本 | 计划日期 | 关键交付物 | -|-------|------|---------|-----------| -| MVP发布 | v0.1.0 | 2025-04 | 核心功能可用 | -| AI增强 | v0.2.0 | 2025-06 | AI能力完整 | -| 企业版 | v0.3.0 | 2025-09 | 企业特性完整 | -| 智能化 | v0.4.0 | 2025-12 | 全栈智能化 | -| 正式发布 | v1.0.0 | 2026-Q1 | 生态开放 | - ---- - -## 贡献指南 - -欢迎社区贡献!请参阅以下资源: - -- [开发文档](./docs/DEVELOPMENT.md) -- [贡献指南](./docs/CONTRIBUTING.md) -- [API文档](./docs/API.md) - ---- - -## 联系方式 - -- 项目主页: https://github.com/ezops/aiops-platform -- 文档中心: https://docs.ezops.io -- 社区论坛: https://community.ezops.io -- 技术支持: support@ezops.io - ---- - -*本路线图会定期更新,请以最新版本为准。* diff --git a/docs/dev-log.md b/docs/dev-log.md index 30f16f2..2c70326 100644 --- a/docs/dev-log.md +++ b/docs/dev-log.md @@ -1832,3 +1832,39 @@ cd ~/devops/aiops - EZOps → AIOps 全局替换: frontend/backend/agent/scripts 全量扫描替换 - 小写 ezops(Go module path/launchd plist/JWT secret)保留不改避免破坏编译/运行时 - WebShell 欢迎语/Login 标题/LLM system prompt 全部统一为 AIOps + + +## 2026-06-24 Agent v2.2 — 8 项新采集指标 + 端口策略 + 索引审计 + +### Agent 新增指标 +- **cpu.iowait** — /proc/stat field[4] 独立追踪,解耦高负载根因(计算 vs 磁盘瓶颈) +- **memory.available_gb** — /proc/meminfo MemAvailable(含可回收缓存,真实可用内存) +- **memory.swap_used_gb** — swap 已用 → OOM 金标准 +- **disk[*].inode_usage_pct** — statfs.Files/Ffree 计算,防文件数爆炸 +- **disk_io.util** — /proc/diskstats field[12] io_ticks 增量/时间 * 100% +- **net.connection.total** — EST+TIME_WAIT+CLOSE_WAIT 汇总 +- **net.rx_errors / net.tx_errors** — /proc/net/dev fields[2]/[10],物理层故障告警 + +### 前端 HostMonitor 增强 +- 基础监控: +CPU IO等待(%) +可用内存(GB) +Swap使用率(%) +- 磁盘监控: +Inode使用率(%) +- 网络监控: TCP 四格(EST/TIME_WAIT/CLOSE_WAIT/总连接) + 带宽双线 + 错误(rx/tx) +- 主机名粗体显示 + +### 端口监控策略 +- Agent 系统进程排除: sshd/rpcbind/master/systemd 等 18 个永远不上报 +- 白名单模式(默认): 全量上报 +- 黑名单模式: 仅选中端口上报 + 告警 +- 后端 PullPortPolicy: GET /api/v1/agent/port-policy?hostname=xxx +- 前端策略配置: 白名单只读灰掉,黑名单可输入端口列表 +- DB 表: monitor_agent_port_policy (hostname UNIQUE + port_filter_mode + port_whitelist JSON) + +### 数据库索引审计 +- 新增: asset_servers.ip + agent_status, sys_audit_logs.created_at, monitor_alert_contacts.channel_type, ops_task_executions.task_id + status +- 清理: 20 个冗余重复索引 (GORM 改名残留) +- K8s 表无需索引 (走 K8s API 不查 DB) + +### Redis 缓存现状 +- ✅ 已用: Agent 指标 Sorted Set (TTL 7天) + 流水线日志 pub/sub +- ❌ 未缓存: /servers 列表, /dashboard/stats, 告警中心 +- 待优化: 高频只读接口加 5-30s Redis 缓存 diff --git a/docs/redis-caching-strategy.md b/docs/redis-caching-strategy.md new file mode 100644 index 0000000..56d2b19 --- /dev/null +++ b/docs/redis-caching-strategy.md @@ -0,0 +1,183 @@ +# Redis 缓存策略文档 + +> 版本: v0.43 | 最后更新: 2026-06-24 + +## 缓存总览 + +| 模块 | 缓存 | 方式 | Key 格式 | TTL | 说明 | +|------|:--:|------|----------|-----|------| +| Agent 指标热数据 | ✅ | Sorted Set | `agent:metrics:{hostname}:{metric}` | 7 天 | 聚合后批量写 MySQL | +| 流水线日志 | ✅ | pub/sub + String | `pipeline:log:{runId}` | 30 min | 实时推送 + 历史缓存 | +| Dashboard 统计 | ✅ | String (JSON) | `dashboard:stats` | 30 s | ~25 次 SQL → 1 次 Redis Get | +| 服务器列表 | ✅ | String (JSON) | `servers:list:{kw}:{st}:{reg}:{p}:{ps}` | 10 s | JOIN 查询 → 缓存命中 ~1ms | +| 告警中心 | ❌ | — | — | — | 表小,直接查 MySQL | +| K8s 资源 | ❌ | — | — | — | 走 K8s API,不经过 MySQL | + +## 缓存后端 + +支持双后端,通过配置 `driver` 字段切换: + +| Driver | 场景 | 依赖 | +|--------|------|------| +| `redis` | Docker / 生产环境 | 外部 Redis 7 容器 | +| `redka` | 二进制独立部署 | 内嵌,零依赖 | + +```yaml +# config.yaml +redis: + driver: redis # redis | redka + host: aiops-redis # Docker 容器名 + port: 6379 + password: "" + db: 0 +``` + +初始化逻辑在 `backend/cmd/main.go:129`,如果 Redis 不可用则 `cache = nil`,业务自动回退到无缓存模式。 + +## 缓存接口 + +```go +// pkg/redis/redis.go +type Cache interface { + Get(ctx, key) (string, error) + Set(ctx, key, value, expiration) error + Del(ctx, keys...) error + // ... ZAdd / ZRangeByScore / Publish 等 +} +``` + +## 各缓存详解 + +### 1. Dashboard 统计 — `dashboard:stats` + +**缓存位置**: `handlers/dashboard.go:GetStats` + +**变更频率**: 低(统计数据,30s 延迟可接受) + +**Key**: 全局单键 `dashboard:stats` + +**实现流程**: + +``` +请求 → cache.Get("dashboard:stats") + ├─ hit → json.Unmarshal → 返回(跳过 ~25 次 SQL) + └─ miss → MySQL 聚合查询 → json.Marshal → cache.Set(30s) → 返回 +``` + +**写入不是异步的**:`cache.Set` 使用 `context.Background()`,缓存写失败不影响 HTTP 响应。 + +```go +// 读缓存 +if cached, err := h.cache.Get(c.Request.Context(), cacheKey); err == nil && cached != "" { + var stats models.DashboardStats + if json.Unmarshal([]byte(cached), &stats) == nil { + c.JSON(200, Response{Data: stats}) + return + } +} +// ... 查询逻辑 ... +// 写缓存 +if data, err := json.Marshal(stats); err == nil { + _ = h.cache.Set(context.Background(), cacheKey, string(data), 30*time.Second) +} +``` + +### 2. 服务器列表 — `servers:list:*` + +**缓存位置**: `handlers/server.go:ListServers` + +**变更频率**: 低(服务器列表相对稳定,10s TTL 足够短) + +**Key 格式**: `servers:list:{keyword}:{status}:{region_id}:{page}:{page_size}` + +- 按查询参数区分,不同过滤条件独立缓存 +- 写操作不主动失效(TTL 10s 自动过期) + +**实现流程**: + +``` +请求 → cache.Get("servers:list:{params}") + ├─ hit → json.Unmarshal → 返回(跳过 Preload JOIN) + └─ miss → MySQL 查询 → json.Marshal → cache.Set(10s) → 返回 +``` + +```go +// 读缓存 +if h.cache != nil { + if cached, err := h.cache.Get(c.Request.Context(), cacheKey); err == nil && cached != "" { + var resp models.Response + if json.Unmarshal([]byte(cached), &resp) == nil { + c.JSON(200, resp) + return + } + } +} +// ... 查询逻辑 ... +// 写缓存 +if h.cache != nil { + if data, err := json.Marshal(resp); err == nil { + _ = h.cache.Set(context.Background(), cacheKey, string(data), 10*time.Second) + } +} +``` + +### 3. Agent 指标热数据 + +**缓存位置**: `handlers/agent.go` + +**Key 格式**: `agent:metrics:{hostname}:{metric}` (Sorted Set) + +- Agent 上报数据先写 Redis Sorted Set(速度快) +- 定时任务批量聚合后写入 MySQL(持久化) +- TTL 7 天,历史数据以 MySQL 为准 + +### 4. 流水线日志 + +**缓存位置**: `handlers/ws_pipeline_log.go` + `handlers/pipeline.go` + +- **实时推送**: Redis Pub/Sub,构建输出实时流式推送到前端 +- **历史缓存**: `pipeline:log:{runId}`,TTL 30 min +- 超过 30 min 的日志从 MySQL 回查 + +## 容错设计 + +| 场景 | 行为 | +|------|------| +| Redis 不可用(启动时) | `cache = nil`,日志 Warn,正常启动 | +| Redis 不可用(运行时) | `cache.Get()` 返回 error → 走 MySQL | +| 缓存值反序列化失败 | 走 MySQL(原逻辑) | +| 缓存写失败 | 静默忽略(`_ = h.cache.Set(...)`) | + +**关键原则:缓存是加速层,不是依赖。任何缓存故障都不影响功能正确性。** + +## 缓存大小估算 + +| Key | 单条大小 | 数量 | 估算总量 | +|-----|---------|------|---------| +| `dashboard:stats` | ~3 KB | 1 | ~3 KB | +| `servers:list:*` | ~5 KB/组合 | ~5-10(常用过滤组合) | ~50 KB | +| `agent:metrics:*` | ~200 B/指标 | ~15 指标 × 7 主机 | ~21 KB | +| `pipeline:log:*` | ~50 KB/运行 | ~5 并发 | ~250 KB | +| **合计** | | | **< 500 KB** | + +## 性能对比 + +| 端点 | 缓存前 | 缓存命中 | 加速比 | +|------|--------|---------|--------| +| `GET /dashboard/stats` | ~150ms (~25 SQL) | ~1ms | ~150x | +| `GET /servers` | ~10ms (Preload JOIN) | ~1ms | ~10x | + +## Handler 缓存字段一览 + +所有带缓存的 handler 都持有 `cache ezredis.Cache` 字段,由 `routes.go` 统一注入: + +```go +// routes.go +redisCache, _ := cache.(ezredis.Cache) + +dashboardHandler := handlers.NewDashboardHandler(db, redisCache) +serverHandler := handlers.NewServerHandler(db, cfg.JWT.Secret, redisCache) +pipelineHandler := handlers.NewPipelineHandler(db, redisCache) +wsLogHandler := handlers.NewWSPipelineLogHandler(db, redisCache) +agentHandler := handlers.NewAgentHandler(db, redisCache, metricsHub) +``` diff --git a/frontend/index.html b/frontend/index.html index b391807..7900e73 100644 --- a/frontend/index.html +++ b/frontend/index.html @@ -3,8 +3,8 @@ - + AIOps智能运维平台 diff --git a/frontend/public/favicon.ico b/frontend/public/favicon.ico new file mode 100644 index 0000000..5b8a242 Binary files /dev/null and b/frontend/public/favicon.ico differ diff --git a/run.sh b/run.sh index 3320bcb..6e61c6a 100755 --- a/run.sh +++ b/run.sh @@ -7,10 +7,10 @@ # ./run.sh docker up 构建+启动 (MySQL+Redis+Backend+Nginx) # # 方式 2 — Kubernetes (embed 单容器): -# ./run.sh k8s deploy 构建镜像+全量部署 (embed 前端嵌入后端) -# ./run.sh k8s upgrade 重新构建+滚动更新 -# ./run.sh k8s status 查看资源状态 -# ./run.sh k8s logs/exec 日志/进入容器 +# ./run.sh kubernetes deploy 构建镜像+全量部署 (embed 前端嵌入后端) +# ./run.sh kubernetes upgrade 重新构建+滚动更新 +# ./run.sh kubernetes status 查看资源状态 +# ./run.sh kubernetes logs/exec 日志/进入容器 # # 方式 3 — 独立二进制: # ./run.sh build 编译独立二进制 (embed 前端) @@ -471,7 +471,7 @@ YAML # 静态编译(CGO_ENABLED=1 因为 SQLite 需要 CGO) info "编译中..." - CGO_ENABLED=1 GOPROXY=https://goproxy.cn,direct GONOSUMCHECK='*' GOTOOLCHAIN=go1.22.2 go build -ldflags="-w -s" -o "$STANDALONE_BIN" ./cmd/ + CGO_ENABLED=1 GOPROXY=https://goproxy.cn,direct GONOSUMCHECK='*' GOTOOLCHAIN=go1.24.0 go build -ldflags="-w -s" -o "$STANDALONE_BIN" ./cmd/ if [ -f "$STANDALONE_BIN" ]; then local bin_size=$(du -h "$STANDALONE_BIN" | cut -f1) @@ -549,13 +549,13 @@ cmd_binary() { # ============================================================ # Kubernetes 部署 (embed 单容器模式) # ============================================================ -K8S_NAMESPACE="devops" -K8S_MANIFEST_DIR="$SCRIPT_DIR/deploy/kubernetes" -K8S_IMAGE="aiops:embed" -K8S_NODE_PORT=30080 +KUBERNETES_NAMESPACE="devops" +KUBERNETES_MANIFEST_DIR="$SCRIPT_DIR/deploy/kubernetes" +KUBERNETES_IMAGE="aiops:embed" +KUBERNETES_NODE_PORT=30080 # 检测 kubectl 和 Docker -check_k8s_deps() { +check_kubernetes_deps() { if ! command -v kubectl &>/dev/null; then error "kubectl 未安装,请先安装 kubectl" exit 1 @@ -592,15 +592,15 @@ load_image_to_cluster() { warning "如集群无法拉取镜像,请手动推送: docker push /$image" } -# K8s 构建镜像 -cmd_k8s_build() { +# Kubernetes 构建镜像 +cmd_kubernetes_build() { if ! command -v docker &>/dev/null; then error "Docker 未安装" exit 1 fi banner "========== 构建 embed 镜像 ==========" - info "镜像: $K8S_IMAGE" + info "镜像: $KUBERNETES_IMAGE" # 版本信息 local version=$(git describe --tags --abbrev=0 2>/dev/null || echo "dev") @@ -610,93 +610,93 @@ cmd_k8s_build() { docker build -f Dockerfile.embed \ --build-arg VERSION="$version" \ --build-arg BUILD_TIME="$build_time" \ - -t "$K8S_IMAGE" . || { + -t "$KUBERNETES_IMAGE" . || { error "镜像构建失败" exit 1 } - local img_size=$(docker images "$K8S_IMAGE" --format "{{.Size}}" | head -1) - success "镜像构建完成: $K8S_IMAGE ($img_size)" + local img_size=$(docker images "$KUBERNETES_IMAGE" --format "{{.Size}}" | head -1) + success "镜像构建完成: $KUBERNETES_IMAGE ($img_size)" # 加载到本地集群 - load_image_to_cluster "$K8S_IMAGE" + load_image_to_cluster "$KUBERNETES_IMAGE" } -# K8s 部署 -cmd_k8s() { +# Kubernetes 部署 +cmd_kubernetes() { local action=${1:-help} case "$action" in deploy|up) - check_k8s_deps - banner "========== K8s 部署 ($K8S_NAMESPACE) ==========" + check_kubernetes_deps + banner "========== Kubernetes 部署 ($KUBERNETES_NAMESPACE) ==========" # 1. 构建镜像 - cmd_k8s_build + cmd_kubernetes_build # 2. 部署基础设施 info "部署 Namespace + Secret + ConfigMap..." - kubectl apply -f "$K8S_MANIFEST_DIR/namespace.yaml" - kubectl apply -f "$K8S_MANIFEST_DIR/secret.yaml" - kubectl apply -f "$K8S_MANIFEST_DIR/configmap.yaml" + kubectl apply -f "$KUBERNETES_MANIFEST_DIR/namespace.yaml" + kubectl apply -f "$KUBERNETES_MANIFEST_DIR/secret.yaml" + kubectl apply -f "$KUBERNETES_MANIFEST_DIR/configmap.yaml" info "部署 MySQL + Redis..." - kubectl apply -f "$K8S_MANIFEST_DIR/mysql.yaml" - kubectl apply -f "$K8S_MANIFEST_DIR/redis.yaml" + kubectl apply -f "$KUBERNETES_MANIFEST_DIR/mysql.yaml" + kubectl apply -f "$KUBERNETES_MANIFEST_DIR/redis.yaml" # 3. 等待数据库就绪 info "等待 MySQL 就绪..." - kubectl -n "$K8S_NAMESPACE" rollout status statefulset/mysql --timeout=120s 2>/dev/null || { + kubectl -n "$KUBERNETES_NAMESPACE" rollout status statefulset/mysql --timeout=120s 2>/dev/null || { warning "MySQL 启动较慢,继续部署应用(可在后台自行完成初始化)" } info "等待 Redis 就绪..." - kubectl -n "$K8S_NAMESPACE" rollout status statefulset/redis --timeout=60s 2>/dev/null || true + kubectl -n "$KUBERNETES_NAMESPACE" rollout status statefulset/redis --timeout=60s 2>/dev/null || true # 4. 部署应用 info "部署 AIOps 应用..." - kubectl apply -f "$K8S_MANIFEST_DIR/deployment.yaml" - kubectl -n "$K8S_NAMESPACE" rollout status deployment/aiops --timeout=180s 2>/dev/null || { - warning "应用正在启动,查看日志: ./run.sh k8s logs" + kubectl apply -f "$KUBERNETES_MANIFEST_DIR/deployment.yaml" + kubectl -n "$KUBERNETES_NAMESPACE" rollout status deployment/aiops --timeout=180s 2>/dev/null || { + warning "应用正在启动,查看日志: ./run.sh kubernetes logs" } # 5. Ingress(可选) - if [ -f "$K8S_MANIFEST_DIR/ingress.yaml" ]; then + if [ -f "$KUBERNETES_MANIFEST_DIR/ingress.yaml" ]; then info "部署 Ingress(如集群无 Ingress Controller 会跳过)..." - kubectl apply -f "$K8S_MANIFEST_DIR/ingress.yaml" 2>/dev/null || true + kubectl apply -f "$KUBERNETES_MANIFEST_DIR/ingress.yaml" 2>/dev/null || true fi echo "" success "部署完成!" echo "" - kubectl -n "$K8S_NAMESPACE" get pods,svc + kubectl -n "$KUBERNETES_NAMESPACE" get pods,svc echo "" local node_ip=$(kubectl get nodes -o jsonpath='{.items[0].status.addresses[?(@.type=="InternalIP")].address}' 2>/dev/null) - info "访问地址: http://${node_ip:-}:$K8S_NODE_PORT" - info "健康检查: http://${node_ip:-}:$K8S_NODE_PORT/health" + info "访问地址: http://${node_ip:-}:$KUBERNETES_NODE_PORT" + info "健康检查: http://${node_ip:-}:$KUBERNETES_NODE_PORT/health" ;; upgrade|update) - check_k8s_deps - banner "========== K8s 滚动更新 ==========" - cmd_k8s_build + check_kubernetes_deps + banner "========== Kubernetes 滚动更新 ==========" + cmd_kubernetes_build info "触发滚动更新..." - kubectl -n "$K8S_NAMESPACE" rollout restart deployment/aiops - kubectl -n "$K8S_NAMESPACE" rollout status deployment/aiops --timeout=180s + kubectl -n "$KUBERNETES_NAMESPACE" rollout restart deployment/aiops + kubectl -n "$KUBERNETES_NAMESPACE" rollout status deployment/aiops --timeout=180s success "滚动更新完成" ;; delete|down|remove) - check_k8s_deps - banner "========== K8s 清理 ($K8S_NAMESPACE) ==========" - warning "这将删除 $K8S_NAMESPACE 命名空间中的所有资源" + check_kubernetes_deps + banner "========== Kubernetes 清理 ($KUBERNETES_NAMESPACE) ==========" + warning "这将删除 $KUBERNETES_NAMESPACE 命名空间中的所有资源" warning "MySQL/Redis 持久卷(PVC)需手动删除" echo "" read -p "确认删除?[y/N] " confirm if [ "$confirm" = "y" ] || [ "$confirm" = "Y" ]; then - kubectl delete -f "$K8S_MANIFEST_DIR/" --ignore-not-found 2>/dev/null + kubectl delete -f "$KUBERNETES_MANIFEST_DIR/" --ignore-not-found 2>/dev/null echo "" info "PVC 状态(需手动清理):" - kubectl -n "$K8S_NAMESPACE" get pvc 2>/dev/null || echo " 无 PVC" + kubectl -n "$KUBERNETES_NAMESPACE" get pvc 2>/dev/null || echo " 无 PVC" success "清理完成" else info "已取消" @@ -704,94 +704,94 @@ cmd_k8s() { ;; build|image) - cmd_k8s_build + cmd_kubernetes_build ;; status|ps) - check_k8s_deps - banner "========== K8s 状态 ($K8S_NAMESPACE) ==========" + check_kubernetes_deps + banner "========== Kubernetes 状态 ($KUBERNETES_NAMESPACE) ==========" echo "" echo "--- Pods ---" - kubectl -n "$K8S_NAMESPACE" get pods -o wide 2>/dev/null + kubectl -n "$KUBERNETES_NAMESPACE" get pods -o wide 2>/dev/null echo "" echo "--- Services ---" - kubectl -n "$K8S_NAMESPACE" get svc 2>/dev/null + kubectl -n "$KUBERNETES_NAMESPACE" get svc 2>/dev/null echo "" echo "--- PVC ---" - kubectl -n "$K8S_NAMESPACE" get pvc 2>/dev/null + kubectl -n "$KUBERNETES_NAMESPACE" get pvc 2>/dev/null echo "" echo "--- Ingress ---" - kubectl -n "$K8S_NAMESPACE" get ingress 2>/dev/null + kubectl -n "$KUBERNETES_NAMESPACE" get ingress 2>/dev/null ;; logs|log) - check_k8s_deps + check_kubernetes_deps local follow=${2:--f} info "应用日志 (Ctrl+C 退出):" - kubectl -n "$K8S_NAMESPACE" logs $follow deployment/aiops --tail=100 + kubectl -n "$KUBERNETES_NAMESPACE" logs $follow deployment/aiops --tail=100 ;; exec|shell|sh) - check_k8s_deps + check_kubernetes_deps info "进入容器 Shell..." - kubectl -n "$K8S_NAMESPACE" exec -it deployment/aiops -- bash || \ - kubectl -n "$K8S_NAMESPACE" exec -it deployment/aiops -- sh + kubectl -n "$KUBERNETES_NAMESPACE" exec -it deployment/aiops -- bash || \ + kubectl -n "$KUBERNETES_NAMESPACE" exec -it deployment/aiops -- sh ;; mysql|db) - check_k8s_deps + check_kubernetes_deps info "进入 MySQL..." - kubectl -n "$K8S_NAMESPACE" exec -it mysql-0 -- mysql -uaiops -paiops_pass_2026 aiops + kubectl -n "$KUBERNETES_NAMESPACE" exec -it mysql-0 -- mysql -uaiops -paiops_pass_2026 aiops ;; redis) - check_k8s_deps + check_kubernetes_deps info "进入 Redis CLI..." - kubectl -n "$K8S_NAMESPACE" exec -it redis-0 -- redis-cli + kubectl -n "$KUBERNETES_NAMESPACE" exec -it redis-0 -- redis-cli ;; scale) - check_k8s_deps + check_kubernetes_deps local replicas=${2:-1} info "扩缩容到 $replicas 副本..." - kubectl -n "$K8S_NAMESPACE" scale deployment/aiops --replicas="$replicas" + kubectl -n "$KUBERNETES_NAMESPACE" scale deployment/aiops --replicas="$replicas" ;; port-forward|pf) - check_k8s_deps + check_kubernetes_deps local local_port=${2:-8080} info "端口转发 localhost:$local_port → aiops:8080 (Ctrl+C 退出):" - kubectl -n "$K8S_NAMESPACE" port-forward svc/aiops "$local_port":8080 + kubectl -n "$KUBERNETES_NAMESPACE" port-forward svc/aiops "$local_port":8080 ;; help|--help|-h) - echo "K8s 部署命令 (embed 单容器模式):" + echo "Kubernetes 部署命令 (embed 单容器模式):" echo "" echo " ${GREEN}部署${NC}" - echo " ./run.sh k8s deploy 构建镜像 + 全量部署" - echo " ./run.sh k8s upgrade 重新构建镜像 + 滚动更新" - echo " ./run.sh k8s delete 删除所有 K8s 资源(保留 PVC)" + echo " ./run.sh kubernetes deploy 构建镜像 + 全量部署" + echo " ./run.sh kubernetes upgrade 重新构建镜像 + 滚动更新" + echo " ./run.sh kubernetes delete 删除所有 Kubernetes 资源(保留 PVC)" echo "" echo " ${CYAN}运维${NC}" - echo " ./run.sh k8s status 查看资源状态" - echo " ./run.sh k8s logs 查看应用日志(默认 follow)" - echo " ./run.sh k8s exec 进入容器 Shell" - echo " ./run.sh k8s mysql 进入 MySQL CLI" - echo " ./run.sh k8s redis 进入 Redis CLI" - echo " ./run.sh k8s scale 3 扩缩容到 3 副本" - echo " ./run.sh k8s port-forward 端口转发到本机 8080" + echo " ./run.sh kubernetes status 查看资源状态" + echo " ./run.sh kubernetes logs 查看应用日志(默认 follow)" + echo " ./run.sh kubernetes exec 进入容器 Shell" + echo " ./run.sh kubernetes mysql 进入 MySQL CLI" + echo " ./run.sh kubernetes redis 进入 Redis CLI" + echo " ./run.sh kubernetes scale 3 扩缩容到 3 副本" + echo " ./run.sh kubernetes port-forward 端口转发到本机 8080" echo "" echo " ${YELLOW}镜像${NC}" - echo " ./run.sh k8s build 仅构建 embed 镜像" + echo " ./run.sh kubernetes build 仅构建 embed 镜像" echo "" - echo " 镜像: $K8S_IMAGE" - echo " 命名空间: $K8S_NAMESPACE" - echo " NodePort: $K8S_NODE_PORT" + echo " 镜像: $KUBERNETES_IMAGE" + echo " 命名空间: $KUBERNETES_NAMESPACE" + echo " NodePort: $KUBERNETES_NODE_PORT" ;; *) - error "未知 k8s 子命令: $action" - cmd_k8s help + error "未知 kubernetes 子命令: $action" + cmd_kubernetes help exit 1 ;; esac @@ -820,17 +820,17 @@ cmd_help() { echo " ./run.sh docker ps 查看容器状态" echo "" echo -e " ${MAGENTA}Kubernetes 部署 (embed 单容器)${NC}" - echo " ./run.sh k8s deploy 构建镜像 + 全量部署到 K8s" - echo " ./run.sh k8s upgrade 重新构建 + 滚动更新" - echo " ./run.sh k8s delete 删除所有 K8s 资源" - echo " ./run.sh k8s status 查看资源状态" - echo " ./run.sh k8s logs 查看应用日志" - echo " ./run.sh k8s exec 进入容器 Shell" - echo " ./run.sh k8s mysql 进入 MySQL CLI" - echo " ./run.sh k8s redis 进入 Redis CLI" - echo " ./run.sh k8s scale 3 扩缩容" - echo " ./run.sh k8s port-forward 端口转发到本机" - echo " ./run.sh k8s build 仅构建 embed 镜像" + echo " ./run.sh kubernetes deploy 构建镜像 + 全量部署到 Kubernetes" + echo " ./run.sh kubernetes upgrade 重新构建 + 滚动更新" + echo " ./run.sh kubernetes delete 删除所有 Kubernetes 资源" + echo " ./run.sh kubernetes status 查看资源状态" + echo " ./run.sh kubernetes logs 查看应用日志" + echo " ./run.sh kubernetes exec 进入容器 Shell" + echo " ./run.sh kubernetes mysql 进入 MySQL CLI" + echo " ./run.sh kubernetes redis 进入 Redis CLI" + echo " ./run.sh kubernetes scale 3 扩缩容" + echo " ./run.sh kubernetes port-forward 端口转发到本机" + echo " ./run.sh kubernetes build 仅构建 embed 镜像" echo "" echo -e " ${YELLOW}编译 & 独立二进制${NC}" echo " ./run.sh build 编译独立二进制 ./$BACKEND_DIR/$STANDALONE_BIN" @@ -894,10 +894,10 @@ main() { cmd_binary "$@" ;; - # Kubernetes 部署 - k8s|kubernetes) + # Kubernetes 部署 (k8s 为别名) + kubernetes|k8s) shift - cmd_k8s "$@" + cmd_kubernetes "$@" ;; # 帮助