fix: favicon .ico 生成 + README 更新 + run.sh kubernetes 别名

- 新增 frontend/public/favicon.ico (4 size: 16/32/48/64)
- index.html .ico 引用调整到 .svg 前面(兼容旧浏览器)
- README.md 全量更新:Kubernetes 完整命令列表 + K8s 管理亮点
- run.sh 主入口添加 k8s 别名(向后兼容)
- aiops-development skill 更新部署命令和 favicon 文档
This commit is contained in:
attacker committed 2026-06-25 00:53:57 +08:00
1 parent f061785266
commit 65636b3f5a
14 files changed
+457 -520

No files matched your search

+51 -24
View File
@@ -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://<NODE_IP>: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://<NODE_IP>: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
Binary file not shown.
+3 -3
View File
@@ -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
+27 -2
View File
@@ -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"
@@ -16,11 +19,12 @@ import (
// DashboardHandler 仪表盘处理器
type DashboardHandler struct {
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",
+37 -4
View File
@@ -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 获取服务器详情
+2 -2
View File
@@ -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)
+6 -6
View File
@@ -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/
+13 -1
View File
@@ -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 助手指引 |
-379
View File
@@ -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
---
*本路线图会定期更新,请以最新版本为准。*
+36
View File
@@ -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 缓存
+183
View File
@@ -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)
```
+1 -1
View File
@@ -3,8 +3,8 @@
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
<link rel="icon" type="image/x-icon" href="/favicon.ico" />
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
<meta name="theme-color" content="#1e6feb" />
<title>AIOps智能运维平台</title>
</head>
Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

+98 -98
View File
@@ -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 <registry>/$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:-<NODE_IP>}:$K8S_NODE_PORT"
info "健康检查: http://${node_ip:-<NODE_IP>}:$K8S_NODE_PORT/health"
info "访问地址: http://${node_ip:-<NODE_IP>}:$KUBERNETES_NODE_PORT"
info "健康检查: http://${node_ip:-<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 "$@"
;;
# 帮助