Kubernetes集群日志-使用Loki实现日志告警

日志报警

对于生产环境以及一个有追求的运维人员来说,哪怕是毫秒级别的宕机也是不能容忍的。对基础设施及应用进行适当的日志记录和监控非常有助于解决问题,还可以帮助优化成本和资源,以及帮助检测以后可能会发生的一些问题。使用 Loki 收集日志是否可以根据采集的日志来进行报警呢?答案是肯定的,而且有两种方式可以来实现:Promtail 中的 metrics 阶段和 Loki 的 ruler 组件。

测试应用

比如现在我们有一个如下所的 nginx 应用用于 Loki 日志报警:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
cat > appv1.yml <<EOF
apiVersion: apps/v1
kind: Deployment
metadata:
name: appv1
spec:
selector:
matchLabels:
app: appv1
template:
metadata:
labels:
use: test
app: appv1
spec:
containers:
- image: nginx:alpine
name: appv1
command: ["/bin/sh", "-c", "echo '你好, 这是(王先森)APP-v1服务中心'>/usr/share/nginx/html/index.html;nginx -g 'daemon off;'"]
ports:
- containerPort: 80
name: portv1
---
apiVersion: v1
kind: Service
metadata:
name: appv1
spec:
selector:
app: appv1
ports:
- name: http
port: 80
targetPort: portv1
type: NodePort
EOF

为方便测试,我们这里使用 NodePort 类型的服务来暴露应用,直接安装即可:

1
2
3
4
5
6
$ kubectl apply -f appv1.yml 
deployment.apps/appv1 unchanged
service/appv1 configured
$ kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
appv1 NodePort 192.168.216.162 <none> 80:32062/TCP 63d

我们可以通过如下命令来来模拟每隔 10s 访问 Nginx 应用:

1
$ while true; do curl --silent --output /dev/null --write-out '%{http_code}' http://10.1.1.120:32062; sleep 10; echo; done

Loki告警配置

官方文档 Ruler storage

Grafana Loki 包含一个名为 ruler 的组件。Ruler 负责持续评估一组可配置查询并根据结果执行操作。在通过使用Loki实现高效日志分析和查询 部署的Loki开启了告警配置,我们需要添加新的告警规则。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
apiVersion: v1
kind: ConfigMap
metadata:
name: loki-rule
namespace: logging
labels:
app: loki
data:
nginx.yaml: |
groups:
- name: nginx-rate
rules:
- alert: LokiNginxRate
expr: sum(rate({app="appv1"} |= "error" [1m])) by (job, pod) / sum(rate({app="appv1"}[1m])) by (job, pod) > 0.01
for: 1m
labels:
severity: critical
annotations:
summary: NGINX 实例 {{ $labels.pod }} 的请求错误率过高。
description: high request latency

修改StatefulSets

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
kubectl edit -n logging statefulsets.apps loki
volumeMounts:
- name: config
mountPath: /etc/loki/config/loki.yaml
subPath: loki.yaml
- name: rule
mountPath: /etc/loki/rules/fake # 挂载到/etc/loki/rules/下fake目录中,
# 如果您有一个 Multi-Tenancy 集群,则规则文件应存储在子文件夹中 <rules-path>/<tenant-id> .如果您不使用 Multi-Tenancy ,则规则文件应位于 <rules-path>/fake 下,fake为默认用户目录。
..........
volumes:
- name: config
configMap:
defaultMode: 0640
name: loki
- name: rule # 添加告警规则configmap
configMap:
defaultMode: 0640
name: loki-rule

检查告警

1
2
3
4
5
6
# 查看 loki 日志,日志关键字 
$ kubectl logs -f -n logging loki-0 loki |grep rule
level=info ts=2023-12-20T06:48:05.448914358Z caller=mapper.go:47 msg="cleaning up mapped rules directory" path=/data/loki/rules-temp
level=info ts=2023-12-20T06:48:05.458968739Z caller=module_service.go:82 msg=initialising module=ruler
level=info ts=2023-12-20T06:48:05.459017096Z caller=ruler.go:528 msg="ruler up and running"
level=info ts=2023-12-20T06:48:05.460113433Z caller=mapper.go:160 msg="updating rule file" file=/data/loki/rules-temp/fake/nginx.yaml

上面日志显示,loki已经更新新的规则文件。
如果文件的格式有问题,将无法加载文件,日志会显示错误原因。
每次更新rule file,需要查看loki日志,确认配置更新。

告警配置规则

Loki 的 rulers 规则和结构与 Prometheus 是完全兼容,唯一的区别在于查询语句(LogQL)不同,在 Loki 中我们用 LogQL 来查询日志,一个典型的 rules 配置文件如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
groups:
# 组名称
- name: xxxx
rules:
# Alert名称
- alert: xxxx
# logQL查询语句
expr: xxxx
# 产生告警的持续时间 pending.
[ for: | default = 0s ]
# 自定义告警事件的label
labels:
[ : ]
# 告警时间的注释
annotations:
[ : ]

比如我们这里配置的规则 sum(rate({app="appv1"} |= "error" [1m])) by (job) / sum(rate({app="appv1"}[1m])) by (job) > 0.01 表示通过日志查到 nginx 日志的错误率大于 1%就触发告警:

同样在 1m 之内如果持续超过阈值,则会真正触发报警规则,触发后我们在 Alertmanager 也可以看到对应的报警信息了: