package services import ( "fmt" "strings" ) // PromtailConfig 主机 Promtail 配置(推送至 lokiEndpoint,采集 logPath) func PromtailConfig(lokiEndpoint, logPath string) string { return fmt.Sprintf(`server: http_listen_port: 9080 grpc_listen_port: 0 log_level: info positions: filename: /tmp/positions.yaml clients: - url: %s/loki/api/v1/push scrape_configs: - job_name: app static_configs: - targets: [localhost] labels: job: app host: ${HOSTNAME} __path__: %s `, lokiEndpoint, logPath) } // PromtailHelmValues DaemonSet 模式 Promtail Helm values func PromtailHelmValues(lokiEndpoint string) string { return fmt.Sprintf(`config: clients: - url: %s/loki/api/v1/push daemonset: enabled: true serviceAccount: create: true resources: limits: cpu: 200m memory: 128Mi requests: cpu: 100m memory: 64Mi extraVolumes: - name: varlog hostPath: path: /var/log - name: varlibdockercontainers hostPath: path: /var/lib/docker/containers extraVolumeMounts: - name: varlog mountPath: /var/log readOnly: true - name: varlibdockercontainers mountPath: /var/lib/docker/containers readOnly: true `, lokiEndpoint) } // FluentbitConfig Sidecar 模式 Fluent Bit 配置(采集 logPath,推送至 lokiHost:lokiPort) func FluentbitConfig(lokiHost, lokiPort, logPath, app, namespace string) string { return fmt.Sprintf(`[SERVICE] Flush 5 Log_Level info HTTP_Server On HTTP_Listen 0.0.0.0 HTTP_Port 2020 [INPUT] Name tail Path %s Tag app.%s Refresh_Interval 5 Mem_Buf_Limit 5MB Skip_Long_Lines On Read_from_Head True DB /tmp/flb.db [FILTER] Name modify Match app.* Add namespace %s Add app %s [OUTPUT] Name loki Match * Host %s Port %s Labels job=fluent-bit, app=%s, namespace=%s `, logPath, app, namespace, app, lokiHost, lokiPort, app, namespace) } // FluentbitConfigMapYAML 包装 fluent-bit.conf 为 ConfigMap YAML(部署到 namespace) func FluentbitConfigMapYAML(conf, namespace string) string { return fmt.Sprintf(`apiVersion: v1 kind: ConfigMap metadata: name: fluent-bit-config namespace: %s data: fluent-bit.conf: | %s `, namespace, indentBlock(conf, " ")) } // SidecarPatchYAML strategic merge patch:为 Deployment 注入 Fluent Bit sidecar 容器 const SidecarPatchYAML = `spec: template: spec: volumes: - name: app-logs emptyDir: {} - name: fluent-bit-config configMap: name: fluent-bit-config containers: - name: fluent-bit image: cr.fluentbit.io/fluent/fluent-bit:3.1.1 imagePullPolicy: IfNotPresent volumeMounts: - name: app-logs mountPath: /var/log/app readOnly: true - name: fluent-bit-config mountPath: /fluent-bit/etc/ resources: limits: cpu: 200m memory: 256Mi requests: cpu: 100m memory: 128Mi ` // SidecarRemovePatchYAML strategic merge patch:从 Deployment 移除 Fluent Bit sidecar(卸载) const SidecarRemovePatchYAML = `spec: template: spec: containers: - name: fluent-bit $patch: delete volumes: - name: app-logs $patch: delete - name: fluent-bit-config $patch: delete ` // indentBlock 给每行加前缀(ConfigMap 嵌入配置需缩进) func indentBlock(s, pad string) string { lines := strings.Split(s, "\n") for i, l := range lines { if l != "" { lines[i] = pad + l } } return strings.Join(lines, "\n") } // parseLokiURL 从 http://host:port 提取 host 与 port(Fluent Bit OUTPUT 需要) func parseLokiURL(endpoint string) (host, port string) { u := strings.TrimSpace(endpoint) u = strings.TrimPrefix(u, "http://") u = strings.TrimPrefix(u, "https://") if i := strings.Index(u, "/"); i >= 0 { u = u[:i] } if i := strings.LastIndex(u, ":"); i >= 0 { return u[:i], u[i+1:] } return u, "3100" }