主题
K8s Alloy 采集 Pod 控制台日志

1. 目标架构
Readme
Loki 的集群在k8s集群外部,不在k8s 内部,关于 Loki 的部署可参考:https://opforge.srebro.cn/project/log/loki/01.html
K8s 集群内部署 Alloy DaemonSet,每个节点一个 Alloy Pod。Alloy 通过 Kubernetes API 采集本节点 Pod 的 stdout/stderr 控制台日志,然后推送到集群外现有 Loki Gateway。
整体架构图

2. 部署前确认
确认 K8s 节点或 Pod 网络能访问你的 Loki Gateway:
bash
kubectl run curl-test -n default --rm -it --image=curlimages/curl -- \
curl -v http://192.168.1.100:3100/ready如果 Loki Gateway 有防火墙或安全组,需要放通 K8s Pod 网段或 Node 网段到 3100 端口。
3. 当前 YAML 里的关键配置
alloy-k8s-loki-logs.yaml文件在,https://cnb.cool/sre-demo/k8s-demo/-/blob/main/yaml/v1.32/loki/alloy-k8s-loki-logs.yaml
当前 alloy-k8s-loki-logs.yaml 已经按本环境配置好:
text
Loki Gateway: 192.168.1.100:3100
Loki push URL: http://192.168.1.100:3100/loki/api/v1/push
Tenant: tenant1
Cluster label: xxx-k8s对应 Alloy 配置:
alloy
loki.write "default" {
endpoint {
url = "http://192.168.1.100:3100/loki/api/v1/push"
tenant_id = "tenant1"
}
}集群标签配置:
alloy
stage.static_labels {
values = {
cluster = "xxx-k8s",
platform = "kubernetes",
agent = "alloy",
}
}说明:
cluster="xxx-k8s"用来区分这批日志来自当前 K8s 集群。tenant_id="tenant1"需要和 Grafana Loki 数据源里的X-Scope-OrgID保持一致。- 如果未来接入多个 K8s 集群,可以给不同集群设置不同
cluster标签,例如prod-k8s、test-k8s。
4. 部署 Alloy
执行:
bash
kubectl apply -f alloy-k8s-loki-logs.yaml查看 DaemonSet:
bash
kubectl -n monitoring get ds alloy
kubectl -n monitoring get pod -l app.kubernetes.io/name=alloy -o wide每个 K8s 节点应该有一个 Alloy Pod。
5. 查看 Alloy 运行日志
bash
kubectl -n monitoring logs -l app.kubernetes.io/name=alloy --tail=100 -f如果配置正确,通常能看到 discovery、tail pod logs、push Loki 的相关日志。
6. 验证 Loki 是否收到日志
在 Grafana Explore 里选择 Loki 数据源,查询:
logql
{cluster="xxx-k8s", platform="kubernetes"}按命名空间查询:
logql
{cluster="xxx-k8s", namespace="default"}按 Java 微服务查询:
logql
{cluster="xxx-k8s", app="your-java-service"}按日志级别查询:
logql
{cluster="xxx-k8s", level="ERROR"}按命名空间、服务和日志级别组合查询:
logql
{cluster="xxx-k8s", namespace="xxx", app="srebro-uc", level="INFO"}如果你的 Pod 没有 app 或 app.kubernetes.io/name 标签,可以先用:
logql
{cluster="xxx-k8s"} |~ "关键字"
8. level 标签说明
K8s 采集的是 Pod 控制台输出,没有这种文件目录结构,所以 level 需要从日志正文里解析。当前 YAML 在 loki.process "pod_logs" 里配置了:
alloy
stage.regex {
expression = "(?i)\\b(?P<level>TRACE|DEBUG|INFO|WARN|WARNING|ERROR|FATAL)\\b"
labels_from_groups = true
}只要 Java 控制台日志里出现以下关键字,就会生成对应的 Loki 标签:
text
TRACE
DEBUG
INFO
WARN
WARNING
ERROR
FATAL例如日志正文:
text
2026-06-11 16:30:00.123 INFO [srebro-uc] user login success
2026-06-11 16:31:00.456 ERROR [srebro-uc] call remote service failed会被打上:
text
level="INFO"
level="ERROR"注意:level 标签只会对修改 Alloy 配置后新采集的日志生效,历史日志不会自动补标签。
9. app 标签说明
传统部署里,app 是从日志文件路径第一级目录提取的:
alloy
rule {
source_labels = ["__path__"]
regex = "/home/application/logs/([^/]+)/[^/]+/.*\\.log"
target_label = "app"
replacement = "$1"
}K8s 采集 Pod 控制台日志时没有这种日志目录结构,所以当前配置改为从 Deployment 名称提取 app 标签。
Deployment 创建 Pod 的链路通常是:
text
Deployment: srebro-uc
-> ReplicaSet: srebro-uc-6dccfd4db
-> Pod: srebro-uc-6dccfd4db-l2zsv当前 Alloy 配置使用 Pod 的 controller 元数据,把 ReplicaSet 名里的最后一段 hash 去掉:
alloy
rule {
source_labels = ["__meta_kubernetes_pod_controller_kind", "__meta_kubernetes_pod_controller_name"]
regex = "ReplicaSet;(.+)-[a-f0-9]{8,10}"
action = "replace"
target_label = "app"
separator = ";"
replacement = "$1"
}这样最终会得到:
text
app="srebro-uc"同时保留了 workload 标签,用于查看原始 controller 名称:
text
workload="srebro-uc-6dccfd4db"如果未来有非 Deployment 类型的工作负载,例如 StatefulSet 或 Job,可以按同样思路增加对应规则。
可选:仍然建议给 Java 微服务 Deployment 增加标准标签,方便 K8s 资源管理和其他监控系统识别:
yaml
metadata:
labels:
app.kubernetes.io/name: order-service
app.kubernetes.io/part-of: business-platform
spec:
template:
metadata:
labels:
app.kubernetes.io/name: order-service
app.kubernetes.io/part-of: business-platform这样 Grafana 查询会更稳定:
logql
{cluster="xxx-k8s", namespace="prod", app="order-service"}10. 排除不想采集的 Pod
当前 YAML 支持通过注解排除采集。给 Pod template 加:
yaml
metadata:
annotations:
loki.grafana.com/scrape: "false"例如某个 Deployment:
yaml
spec:
template:
metadata:
annotations:
loki.grafana.com/scrape: "false"