feat(k8s): M13 多集群资源对比看板 — GetMultiClusterComparison handler + ClusterComparePage (柱状图/雷达图/饼图/详细对比表)

This commit is contained in:
attacker committed 2026-06-24 05:03:47 +08:00
1 parent 7192f58b72
commit 3d7932c087
9 files changed
+591 -2

No files matched your search

+136
View File
@@ -3608,3 +3608,139 @@ func (h *KubernetesHandler) uploadPodFileWithNS(c *gin.Context, ns string) {
},
})
}
// ============================================================================
// M13: 多集群资源对比看板 (Multi-Cluster Comparison Dashboard) // Logan.Li
// ============================================================================
// GetMultiClusterComparison 聚合所有集群的资源数据进行对比
func (h *KubernetesHandler) GetMultiClusterComparison(c *gin.Context) {
// 1. 获取所有集群
var clusters []models.KubernetesCluster
h.db.Find(&clusters)
type ClusterComparison struct {
ID uint `json:"id"`
Name string `json:"name"`
Code string `json:"code"`
Status string `json:"status"`
Version string `json:"version"`
NodeCount int `json:"node_count"`
PodCount int `json:"pod_count"`
DeploymentCount int `json:"deployment_count"`
ServiceCount int `json:"service_count"`
CPUUsage float64 `json:"cpu_usage"`
MemoryUsage float64 `json:"memory_usage"`
APIServer string `json:"api_server"`
LastSyncAt *time.Time `json:"last_sync_at"`
// Node-level aggregated data from kubernetes_nodes table
TotalCPUCores int `json:"total_cpu_cores"`
TotalMemoryMB int64 `json:"total_memory_mb"`
MasterCount int `json:"master_count"`
WorkerCount int `json:"worker_count"`
HealthyNodes int `json:"healthy_nodes"`
UnhealthyNodes int `json:"unhealthy_nodes"`
}
// 2. 获取所有节点的聚合数据(按 cluster_id 分组)
type NodeAgg struct {
ClusterID uint
NodeCount int
MasterCount int
WorkerCount int
HealthyNodes int
UnhealthyNodes int
TotalCPU int
TotalMemory int64
AvgCPUUsage float64
AvgMemUsage float64
}
nodeAggMap := map[uint]*NodeAgg{}
{
var nodes []models.KubernetesNode
h.db.Find(&nodes)
for _, n := range nodes {
agg, ok := nodeAggMap[n.ClusterID]
if !ok {
agg = &NodeAgg{ClusterID: n.ClusterID}
nodeAggMap[n.ClusterID] = agg
}
agg.NodeCount++
agg.TotalCPU += n.CPU
agg.TotalMemory += n.Memory
if n.CPUUsage > 0 || n.MemoryUsage > 0 {
if agg.AvgCPUUsage == 0 { agg.AvgCPUUsage = n.CPUUsage } else { agg.AvgCPUUsage = (agg.AvgCPUUsage*float64(agg.NodeCount-1) + n.CPUUsage) / float64(agg.NodeCount) }
if agg.AvgMemUsage == 0 { agg.AvgMemUsage = n.MemoryUsage } else { agg.AvgMemUsage = (agg.AvgMemUsage*float64(agg.NodeCount-1) + n.MemoryUsage) / float64(agg.NodeCount) }
}
if n.Role == "master" {
agg.MasterCount++
} else {
agg.WorkerCount++
}
if n.Status == "Ready" {
agg.HealthyNodes++
} else {
agg.UnhealthyNodes++
}
}
}
// 3. 构建对比数据
comparisons := []ClusterComparison{}
totalNodes, totalPods, totalDeployments, totalServices := 0, 0, 0, 0
for _, cl := range clusters {
cc := ClusterComparison{
ID: cl.ID,
Name: cl.Name,
Code: cl.Code,
Status: cl.Status,
Version: cl.Version,
NodeCount: cl.NodeCount,
PodCount: cl.PodCount,
DeploymentCount: cl.DeploymentCount,
ServiceCount: cl.ServiceCount,
CPUUsage: cl.CPUUsage,
MemoryUsage: cl.MemoryUsage,
APIServer: cl.APIServer,
LastSyncAt: cl.LastSyncAt,
}
// 优先用 node 级别的实时聚合数据
if agg, ok := nodeAggMap[cl.ID]; ok && agg.NodeCount > 0 {
cc.TotalCPUCores = agg.TotalCPU
cc.TotalMemoryMB = agg.TotalMemory
cc.MasterCount = agg.MasterCount
cc.WorkerCount = agg.WorkerCount
cc.HealthyNodes = agg.HealthyNodes
cc.UnhealthyNodes = agg.UnhealthyNodes
// 如果集群级别的 cpu_usage 为 0,使用节点平均值
if cc.CPUUsage == 0 && agg.AvgCPUUsage > 0 {
cc.CPUUsage = agg.AvgCPUUsage
}
if cc.MemoryUsage == 0 && agg.AvgMemUsage > 0 {
cc.MemoryUsage = agg.AvgMemUsage
}
}
totalNodes += cc.NodeCount
totalPods += cc.PodCount
totalDeployments += cc.DeploymentCount
totalServices += cc.ServiceCount
comparisons = append(comparisons, cc)
}
// 4. 返回结果
c.JSON(200, models.Response{
Code: 200,
Message: "success",
Data: gin.H{
"clusters": comparisons,
"totals": gin.H{
"cluster_count": len(clusters),
"node_count": totalNodes,
"pod_count": totalPods,
"deployment_count": totalDeployments,
"service_count": totalServices,
},
},
})
}
+3
View File
@@ -432,6 +432,9 @@ func Register(r *gin.Engine, db *gorm.DB, log *zap.Logger, cfg *config.Config, c
kubernetesRouter.GET("/:clusterCode/namespace/:namespace/:resource/:name/yaml", k8sHandler.GetResourceYAMLNS)
kubernetesRouter.PUT("/:clusterCode/namespace/:namespace/:resource/:name/yaml", k8sHandler.UpdateResourceYAMLNS)
kubernetesRouter.DELETE("/:clusterCode/namespace/:namespace/:resource/:name/yaml", k8sHandler.DeleteResourceYAMLNS)
// 🆕 M13: 多集群资源对比看板
kubernetesRouter.GET("/compare", k8sHandler.GetMultiClusterComparison)
}
// 告警路由