From 98a28b62eb44bad78919d2f50c2cfe8a0476d12c Mon Sep 17 00:00:00 2001 From: douxu Date: Mon, 22 Jun 2026 16:06:09 +0800 Subject: [PATCH] feat: add Grafana Alloy log collection manifests for K8s - add alloy-daemonset to run Alloy on every node via DaemonSet - add alloy-configmap to scrape Pod logs through the K8s API and parse zap JSON fields (level, traceID, pod, namespace) into Loki labels - add alloy-rbac granting pods/log read access for log collection - forward parsed logs to loki-service for Grafana querying --- deploy/k8s/alloy-configmap.yaml | 81 +++++++++++++++++++++++++++++++++ deploy/k8s/alloy-daemonset.yaml | 48 +++++++++++++++++++ deploy/k8s/alloy-rbac.yaml | 30 ++++++++++++ 3 files changed, 159 insertions(+) create mode 100644 deploy/k8s/alloy-configmap.yaml create mode 100644 deploy/k8s/alloy-daemonset.yaml create mode 100644 deploy/k8s/alloy-rbac.yaml diff --git a/deploy/k8s/alloy-configmap.yaml b/deploy/k8s/alloy-configmap.yaml new file mode 100644 index 0000000..a11402f --- /dev/null +++ b/deploy/k8s/alloy-configmap.yaml @@ -0,0 +1,81 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: alloy-config + namespace: default +data: + config.alloy: | + // 发现集群内所有 Pod + discovery.kubernetes "pods" { + role = "pod" + } + + // 重写元数据标签,并只保留带 app label 的 Pod + discovery.relabel "pods" { + targets = discovery.kubernetes.pods.targets + + rule { + source_labels = ["__meta_kubernetes_namespace"] + target_label = "namespace" + } + rule { + source_labels = ["__meta_kubernetes_pod_name"] + target_label = "pod" + } + rule { + source_labels = ["__meta_kubernetes_pod_container_name"] + target_label = "container" + } + rule { + source_labels = ["__meta_kubernetes_pod_label_app"] + target_label = "app" + } + // 只采集有 app label 的 Pod + rule { + source_labels = ["__meta_kubernetes_pod_label_app"] + action = "keep" + regex = ".+" + } + } + + // 通过 Kubernetes API 抓取容器日志(无需挂载宿主机日志目录) + loki.source.kubernetes "pods" { + targets = discovery.relabel.pods.output + forward_to = [loki.process.parse.receiver] + } + + // 解析 zap 输出的 JSON 日志,并将关键字段提升为 Loki Label + loki.process "parse" { + forward_to = [loki.write.default.receiver] + + // 解析结构化字段 + stage.json { + expressions = { + level = "level", + traceID = "traceID", + spanID = "spanID", + caller = "caller", + pod = "pod", + namespace = "namespace", + node = "node", + } + } + + // 提升为 Label,支持在 Grafana 中按实例/Trace 过滤 + stage.labels { + values = { + level = "", + traceID = "", + pod = "", + namespace = "", + node = "", + } + } + } + + // 推送到 Loki + loki.write "default" { + endpoint { + url = "http://loki-service:3100/loki/api/v1/push" + } + } diff --git a/deploy/k8s/alloy-daemonset.yaml b/deploy/k8s/alloy-daemonset.yaml new file mode 100644 index 0000000..1423d23 --- /dev/null +++ b/deploy/k8s/alloy-daemonset.yaml @@ -0,0 +1,48 @@ +apiVersion: apps/v1 +kind: DaemonSet +metadata: + name: alloy + namespace: default +spec: + selector: + matchLabels: + app: alloy + template: + metadata: + labels: + app: alloy + spec: + serviceAccountName: alloy + tolerations: + - key: node-role.kubernetes.io/master + effect: NoSchedule + containers: + - name: alloy + image: grafana/alloy:v1.16.3 + imagePullPolicy: IfNotPresent + args: + - run + - /etc/alloy/config.alloy + - --storage.path=/var/lib/alloy/data + - --server.http.listen-addr=0.0.0.0:12345 + ports: + - containerPort: 12345 + name: http + volumeMounts: + - name: config + mountPath: /etc/alloy + - name: data + mountPath: /var/lib/alloy/data + resources: + limits: + cpu: 200m + memory: 128Mi + requests: + cpu: 50m + memory: 64Mi + volumes: + - name: config + configMap: + name: alloy-config + - name: data + emptyDir: {} diff --git a/deploy/k8s/alloy-rbac.yaml b/deploy/k8s/alloy-rbac.yaml new file mode 100644 index 0000000..0a48dd1 --- /dev/null +++ b/deploy/k8s/alloy-rbac.yaml @@ -0,0 +1,30 @@ +apiVersion: v1 +kind: ServiceAccount +metadata: + name: alloy + namespace: default +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: alloy +rules: + - apiGroups: [""] + resources: ["nodes", "nodes/proxy", "services", "endpoints", "pods"] + verbs: ["get", "list", "watch"] + - apiGroups: [""] + resources: ["pods/log"] + verbs: ["get", "list", "watch"] +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: alloy +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: alloy +subjects: + - kind: ServiceAccount + name: alloy + namespace: default