refactor: 移除资源用量的可选 Prometheus 接入与平台监控页
- 资源用量弹窗:删除 applyPrometheus/promQueryValue 与峰值/限流字段 (LOKI_USAGE_PROMETHEUS_URL 从未内置,代码恒走降级),统一提示 「未接入 Prometheus:暂无峰值/限流数据」;扩容建议改基于 metrics-server 实时值 - 移除「平台监控」菜单页与 /api/v1/system/metrics-summary; 原始指标保留在标准 /api/v1/metrics(Prometheus 文本格式)可自行抓取 - 手册/落地页/CHANGELOG 同步(去除备份恢复与监控页宣传,指标端点表述中性化)
This commit is contained in:
1 parent
f87fb4b2b3
commit
c1f822fb10
17 files changed
+9
-465
No files matched your search
@@ -4,9 +4,6 @@ import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
@@ -19,7 +16,7 @@ import (
|
||||
// ResourceUsage 是页面上「资源」弹框的数据。
|
||||
//
|
||||
// 三种部署模式都能采集:
|
||||
// - k8s-yaml : StatefulSet resources + metrics-server(实时用量)+ 可选 Prometheus(峰值/限流)
|
||||
// - k8s-yaml : StatefulSet resources + metrics-server(实时用量)
|
||||
// - host-docker : docker stats / docker inspect(容器限额未设则按宿主机内存做参考)
|
||||
// - host-binary : ps 采集进程 CPU%/RSS(无 cgroup 限额)
|
||||
//
|
||||
@@ -45,11 +42,6 @@ type ResourceUsage struct {
|
||||
// 限额是否真的配置了(docker 未加 --memory 时为 false,页面不画百分比)
|
||||
LimitsConfigured bool `json:"limitsConfigured"`
|
||||
|
||||
// 可选(需 Prometheus)
|
||||
CPUPeakMilli *int64 `json:"cpuPeakMilli,omitempty"`
|
||||
MemPeakBytes *int64 `json:"memPeakBytes,omitempty"`
|
||||
ThrottlePercent *float64 `json:"throttlePercent,omitempty"`
|
||||
|
||||
// 采集受限说明(如缺 metrics.k8s.io 权限、未装 metrics-server、docker 无历史数据)
|
||||
MetricsNote string `json:"metricsNote,omitempty"`
|
||||
|
||||
@@ -148,7 +140,6 @@ func (s *DeploymentService) k8sUsage(ctx context.Context, d *models.LokiDeployme
|
||||
usage.MetricsNote = "无法解析 metrics-server 返回"
|
||||
}
|
||||
|
||||
s.applyPrometheus(usage)
|
||||
usage.buildHints()
|
||||
return usage, nil
|
||||
}
|
||||
@@ -167,29 +158,6 @@ func explainMetricsError(err error) string {
|
||||
}
|
||||
}
|
||||
|
||||
// applyPrometheus 补 24h 峰值与 CPU 限流率(未配置 Prometheus 地址则跳过)。
|
||||
func (s *DeploymentService) applyPrometheus(u *ResourceUsage) {
|
||||
base := strings.TrimSpace(os.Getenv("LOKI_USAGE_PROMETHEUS_URL"))
|
||||
if base == "" || u.Pod == "" {
|
||||
if u.MetricsNote == "" {
|
||||
u.MetricsNote = "未配置 Prometheus,暂无 24h 峰值与限流率"
|
||||
}
|
||||
return
|
||||
}
|
||||
sel := fmt.Sprintf(`pod=%q,namespace=%q,container="loki"`, u.Pod, u.Namespace)
|
||||
if v, ok := promQueryValue(base, fmt.Sprintf(`max_over_time(sum(rate(container_cpu_usage_seconds_total{%s}[5m]))[24h:1m])`, sel)); ok {
|
||||
milli := int64(v * 1000)
|
||||
u.CPUPeakMilli = &milli
|
||||
}
|
||||
if v, ok := promQueryValue(base, fmt.Sprintf(`max_over_time(sum(container_memory_working_set_bytes{%s})[24h:1m])`, sel)); ok {
|
||||
b := int64(v)
|
||||
u.MemPeakBytes = &b
|
||||
}
|
||||
if v, ok := promQueryValue(base, fmt.Sprintf(`100 * sum(rate(container_cpu_cfs_throttled_periods_total{pod=%q,namespace=%q}[15m])) / sum(rate(container_cpu_cfs_periods_total{pod=%q,namespace=%q}[15m]))`, u.Pod, u.Namespace, u.Pod, u.Namespace)); ok {
|
||||
u.ThrottlePercent = &v
|
||||
}
|
||||
}
|
||||
|
||||
// ---------- host-docker ----------
|
||||
|
||||
func (s *DeploymentService) dockerUsage(ctx context.Context, d *models.LokiDeployment) (*ResourceUsage, error) {
|
||||
@@ -245,7 +213,7 @@ func (s *DeploymentService) dockerUsage(ctx context.Context, d *models.LokiDeplo
|
||||
usage.MetricsNote = "docker stats 读取失败:" + err.Error()
|
||||
}
|
||||
if usage.MetricsNote == "" {
|
||||
usage.MetricsNote = "Docker 部署无历史峰值;如需 24h 峰值请接入 cAdvisor/Prometheus"
|
||||
usage.MetricsNote = "未接入 Prometheus:暂无峰值/限流数据"
|
||||
}
|
||||
|
||||
usage.buildHints()
|
||||
@@ -287,14 +255,9 @@ func (s *DeploymentService) processUsage(ctx context.Context, d *models.LokiDepl
|
||||
// ---------- 共用:扩容建议 ----------
|
||||
|
||||
func (u *ResourceUsage) buildHints() {
|
||||
// 峰值需 Prometheus,平台不接入:扩容建议基于 metrics-server 实时值
|
||||
cpuRef := u.CPUCurrentMilli
|
||||
if u.CPUPeakMilli != nil && *u.CPUPeakMilli > cpuRef {
|
||||
cpuRef = *u.CPUPeakMilli
|
||||
}
|
||||
memRef := u.MemCurrentBytes
|
||||
if u.MemPeakBytes != nil && *u.MemPeakBytes > memRef {
|
||||
memRef = *u.MemPeakBytes
|
||||
}
|
||||
|
||||
var notes []string
|
||||
if u.CPULimitMilli > 0 {
|
||||
@@ -319,9 +282,6 @@ func (u *ResourceUsage) buildHints() {
|
||||
notes = append(notes, "内存偏高")
|
||||
}
|
||||
}
|
||||
if u.ThrottlePercent != nil && *u.ThrottlePercent >= 10 {
|
||||
notes = append(notes, fmt.Sprintf("CPU 限流 %.0f%%", *u.ThrottlePercent))
|
||||
}
|
||||
if !u.Ready {
|
||||
notes = append(notes, "实例未就绪")
|
||||
}
|
||||
@@ -337,40 +297,6 @@ func (u *ResourceUsage) buildHints() {
|
||||
}
|
||||
}
|
||||
|
||||
// ---------- Prometheus ----------
|
||||
|
||||
// promQueryValue 查 Prometheus 瞬时值;未配置或失败返回 ok=false(页面降级)。
|
||||
func promQueryValue(base, expr string) (float64, bool) {
|
||||
client := &http.Client{Timeout: 8 * time.Second}
|
||||
u := strings.TrimSuffix(base, "/") + "/api/v1/query?query=" + url.QueryEscape(expr)
|
||||
resp, err := client.Get(u)
|
||||
if err != nil {
|
||||
return 0, false
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
if resp.StatusCode >= 400 {
|
||||
return 0, false
|
||||
}
|
||||
var payload struct {
|
||||
Data struct {
|
||||
Result []struct {
|
||||
Value [2]interface{} `json:"value"`
|
||||
} `json:"result"`
|
||||
} `json:"data"`
|
||||
}
|
||||
if json.NewDecoder(resp.Body).Decode(&payload) != nil || len(payload.Data.Result) == 0 {
|
||||
return 0, false
|
||||
}
|
||||
if len(payload.Data.Result[0].Value) < 2 {
|
||||
return 0, false
|
||||
}
|
||||
raw, ok := payload.Data.Result[0].Value[1].(string)
|
||||
if !ok {
|
||||
return 0, false
|
||||
}
|
||||
return parseFloatSafe(raw), true
|
||||
}
|
||||
|
||||
// ---------- 单位解析 ----------
|
||||
|
||||
// parseQuantityMilli 解析 CPU 用量/限额为毫核。
|
||||
|
||||
Reference in new issue
Block a user