diff --git a/backend/main.go b/backend/main.go index 6b115be..fbef7c3 100644 --- a/backend/main.go +++ b/backend/main.go @@ -84,6 +84,8 @@ func main() { // 清理旧版本删除部署后残留的托管数据源(幂等) services.CleanupOrphanManagedLogSources() + // 异步重新探测运行中部署的数据源连接方式(平台/Loki 可能在主机或集群内) + go services.EnsureLogSourcesForRunningDeployments() // 补齐/升级内置告警规则(幂等):启动即执行,存量环境也能拿到「默认启用+绑默认通道」 seed.SeedAlertRules() diff --git a/backend/services/log_source.go b/backend/services/log_source.go index d724096..af597e1 100644 --- a/backend/services/log_source.go +++ b/backend/services/log_source.go @@ -2,6 +2,7 @@ package services import ( + "context" "encoding/json" "fmt" "log" @@ -485,6 +486,32 @@ func CleanupOrphanManagedLogSources() { db.Unlock() } +// AutoDetectLogSource 探测数据源的可用连接方式,返回最终选择(cluster-svc / url)。 +// +// 交付环境组合很多:平台可能在主机或集群内,Loki 也可能在主机或集群内。 +// cluster-svc 走 kube-apiserver 的 service proxy,不依赖集群 DNS;url 直连 +// 则需要平台能访问到该地址。这里按「代理优先、URL 兜底」实测,避免按部署 +// 模式硬编码导致某种组合连不上。 +func AutoDetectLogSource(ctx context.Context, src *models.LogSource) string { + if src.ClusterID != nil { + probe := *src + probe.TargetType = "cluster-svc" + if _, status, err := lokiProxyGET(ctx, &probe, "/ready", nil); err == nil && status == 200 { + src.TargetType = "cluster-svc" + return "cluster-svc" + } + } + if src.URL != "" { + probe := *src + probe.TargetType = "url" + if _, status, err := lokiProxyGET(ctx, &probe, "/ready", nil); err == nil && status == 200 { + src.TargetType = "url" + return "url" + } + } + return "" +} + // EnsureLogSourceForDeployment 部署成功后自动注册查询数据源(host→url;k8s→cluster-svc)。 // 已存在同名数据源时:平台托管的自动刷新连接信息,用户手填的不覆盖。 func EnsureLogSourceForDeployment(d *models.LokiDeployment) { @@ -506,8 +533,18 @@ func EnsureLogSourceForDeployment(d *models.LokiDeployment) { // 这里换成主机真实 IP,平台才能连上。 target.URL = reachableEndpoint(d) target.ClusterID = nil + } else { + // k8s 部署:集群内 Service 地址也记下来,作为 URL 直连候选 + target.URL = d.Endpoint } + // 实测可用性后决定连接方式:主机/集群内平台、主机/集群内 Loki 都兼容 + detectCtx, cancel := context.WithTimeout(context.Background(), 6*time.Second) + if method := AutoDetectLogSource(detectCtx, target); method != "" { + log.Printf("[log-source] %q 自动选择连接方式: %s", target.Name, method) + } + cancel() + db := repository.GetDB() db.Lock() for i := range db.LogSources { diff --git a/docs/deployment/kubernetes.md b/docs/deployment/kubernetes.md index f91e4c3..9b66e58 100644 --- a/docs/deployment/kubernetes.md +++ b/docs/deployment/kubernetes.md @@ -236,3 +236,25 @@ kubectl -n log get secret lokistack-token -o jsonpath='{.data.token}' | base64 - - 如果集群策略要求短期凭证,可改用 `kubectl -n log create token lokistack --duration=24h` 定期轮换。 - 上面的 Namespace 由管理员创建,平台 Token 本身没有集群级权限;只有确实需要平台自建命名空间时,才额外授予 `namespaces: create/get` 的 ClusterRole(create 无法按名称限制,预建 `log` 更安全)。 + +## 10. 数据源连接方式(部署后自动探测) + +平台自动注册的数据源不再按部署模式硬编码,部署完成后会实测两种方式: + +1. **cluster-svc**:经 kube-apiserver 的 service proxy 访问 + `//services/loki:3100/proxy`,不依赖集群 DNS / ClusterIP 直通; +2. **url**:直接访问 Loki 地址(Service DNS、主机 IP:3100 或 Ingress 域名)。 + +先试 cluster-svc,失败再试 url,选通的写入数据源。 + +| 平台位置 | Loki 位置 | 实际可用方式 | +|---|---|---| +| 集群内 | 集群内 | cluster-svc | +| 主机 | 集群内 | cluster-svc(平台能访问 apiserver:6443 时);否则 url(NodePort/Ingress) | +| 集群内 | 主机 | url(主机 IP:3100,需网络可达) | +| 主机 | 主机 | url | + +注意: +- `cluster-svc` 需要凭据具备 `services/proxy` 权限(本文第 9 节的 Role 已包含); +- 平台与 API Server / Loki 之间的网络必须放行;跨 VPC 时走 VPN、专线或公网 Ingress; +- 自动探测只决定“连接方式”,不会隐藏数据源;连接失败时“测试连接”会返回具体错误。