开源的容器云日志方案
1、Promtail
Promtail 是代理,负责收集日志并将其发送给loki。对标ELK中的Logstash。
Promtail是一个日志收集的代理,它的主要工作模式是发现存储在磁盘上的日志文件,并将其与一组标签关联的日志文件转发到 Loki,它通常部署到需要监视应用程序的每台机器/容器上。Promtail主要是用来发现目标、将标签附加到日志流以及将日志推送到Loki。截止到目前,Promtail可以跟踪两个来源的日志:本地日志文件和systemd日志(仅支持AMD64架构)
2、Loki
Loki 是主服务器,负责存储日志和处理查询。对标ELK中的ElasticSearch。
Loki是一组可以组成一个功能齐全的日志堆栈组件,与其它日志系统不同的是,Loki只建立日志标签的索引而不索引原始日志消息,为日志数据设置一组标签,这意味着Loki的运营成本更低,效率也能提高几个数量级
(1)Loki标签(Labels)
标签是Loki最核心的一项功能,它是一个键值对,通过给一个日志打上一个或多个标签,按标签查询可以精准快速地定位到所有符合条件的日志。标签可以在配置文件中配置,如下:
scrape_configs: - job_name: systempipeline_stages:static_configs:- targets:- localhost labels:job: syslogenv: dev__path__: /var/log/syslog - job_name: apachepipeline_stages:static_configs:- targets:- localhost labels:job: apacheenv: dev__path__: /var/log/apache.log {job="apache"} <- 查询所有 key=job value = "apache"标签的日志{job="syslog"} <- 查询所有key=job value = "syslog"标签的日志{job=~"apache|syslog"} <- 查询所有key=job value = "syslog" 或者"syslog"标签的日志{env="dev"} <- 查询所有 key=env value = "dev"标签的日志,本例中即是所有日志
也可以通过正则表达式,动态地设置标签
- job_name: systempipeline_stages:- regex: expression: "^(?P\\S+) (?P\\S+) (?P\\S+) \\[(?P[\\w:/]+\\s[+\\-]\\d{4})\\] \"(?P\\S+)\\s?(?P\\S+)?\\s?(?P\\S+)?\" (?P\\d{3}|-) (?P\\d+|-)\\s?\"?(?P[^\"]*)\"?\\s?\"?(?P[^\"]*)?\"?$" - labels: action: status_code:static_configs:- targets:- localhost labels:job: apacheenv: dev__path__: /var/log/apache.log
上述表达式可以动态地将日志中的值(action=”GET”
,
action=”POST”,tatus_code=”200″,
status_code=”400″)提取放入标签中。假设有如下日志:11.11.11.11 - frank [25/Jan/2000:14:00:01 -0500] "GET /1986.js HTTP/1.1" 200 932 "-" "Mozilla/5.0 (Windows; U; Windows NT 5.1; de; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7 GTB6"11.11.11.12 - frank [25/Jan/2000:14:00:02 -0500] "POST /1986.js HTTP/1.1" 200 932 "-" "Mozilla/5.0 (Windows; U; Windows NT 5.1; de; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7 GTB6"11.11.11.13 - frank [25/Jan/2000:14:00:03 -0500] "GET /1986.js HTTP/1.1" 400 932 "-" "Mozilla/5.0 (Windows; U; Windows NT 5.1; de; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7 GTB6"11.11.11.14 - frank [25/Jan/2000:14:00:04 -0500] "POST /1986.js HTTP/1.1" 400 932 "-" "Mozilla/5.0 (Windows; U; Windows NT 5.1; de; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7 GTB6"
Loki会生成如下四条不同的流(标签key/value不同,job=”apache”,env=”dev”,action=”GET”,status_code=”200″为一个标签组合),即4个新的日志,供之后查询调用;其他的日志行根据符合条件的标签加入到相应流中。
{job="apache",env="dev",action="GET",status_code="200"} 11.11.11.11 - frank [25/Jan/2000:14:00:01 -0500] "GET /1986.js HTTP/1.1" 200 932 "-" "Mozilla/5.0 (Windows; U; Windows NT 5.1; de; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7 GTB6"{job="apache",env="dev",action="POST",status_code="200"} 11.11.11.12 - frank [25/Jan/2000:14:00:02 -0500] "POST /1986.js HTTP/1.1" 200 932 "-" "Mozilla/5.0 (Windows; U; Windows NT 5.1; de; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7 GTB6"{job="apache",env="dev",action="GET",status_code="400"} 11.11.11.13 - frank [25/Jan/2000:14:00:03 -0500] "GET /1986.js HTTP/1.1" 400 932 "-" "Mozilla/5.0 (Windows; U; Windows NT 5.1; de; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7 GTB6"{job="apache",env="dev",action="POST",status_code="400"} 11.11.11.14 - frank [25/Jan/2000:14:00:04 -0500] "POST /1986.js HTTP/1.1" 400 932 "-" "Mozilla/5.0 (Windows; U; Windows NT 5.1; de; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7 GTB6"
(2)Loki组件
数据写入流程如下
1、分发器接收到HTTP请求后将数据按流的形式储存,每个流将会用哈希环转为哈希值
2、分发器将各个流发送到相对应的日志存储器中
3、分发器会把流数据压缩成块或追加到已有的(具有相同标签)的块中。对于每个租户和每个标签组,块都是独一无二的
4、分发器通过HTTP连接响应回成功码
数据读取流程
1、查询器接收到获取数据的HTTP请求
2、查询器将所有查询发送到日志存储器中
3、日志存储器接收到请求后返回符合匹配查询条件的响应数据
4、如果存储器没有返回数据,查询器将从后端仓库懒加载数据并运行查询语句
5、查询器处理了接收到的数据后通过HTT连接返回数据
(3)Rules and the Ruler
Alerting Rules
Alerting Rules可以定义基于LogQL表达式的的报警条件,当触发报警时可以向外部服务器发送通知信息,例子如下:
groups:- name: should_fire rules:- alert: HighPercentageError expr: |sum(rate({app="foo", env="production"} |= "error" [5m])) by (job) /sum(rate({app="foo", env="production"}[5m])) by (job) > 0.05 for: 10m labels: severity: page annotations: summary: High request latency- name: credentials_leak rules: - alert: http-credentials-leaked annotations: message: "{{ $labels.job }} is leaking http basic auth credentials." expr: 'sum by (cluster, job, pod) (count_over_time({namespace="prod"} |~ "http(s?)://(\\w+):(\\w+)@" [5m]) > 0)' for: 10m labels: severity: critical
当标签为app=”foo”, env=”production” 的错误日志占比超过5%的情况,发送告警信息
Recording Rules
Recording Rules可以周期性地预计算所需的或统计性的表达式,并储存成一组新的度量数据
name: NginxRulesinterval: 1mrules:- record: nginx:requests:rate1m expr: |sum( rate({container="nginx"}[1m])) labels:cluster: "us-central1"
该查询语句每隔一分钟会被执行,统计一分钟内nginx的请求的请求次数
(4)LogQL
LogQL是受到PromQL启发的查询语句,但是为Loki量身定制的。LogQL相当于是分布式系统中聚合日志源的grep
命令,通过使用标签和运算符来过滤。
3、Grafana
Grafana提供用户界面。对标ELK中的Kibana
Grafana是一款开源的可视化和分析软件,它允许用户查询、可视化、警告和探索监控指标。Grafana主要提供时间序列数据的仪表板解决方案,支持超过数十种数据源
集成Loki
(1)Loki query editor
在Loki查询编辑器中可以使用LogQL语句创建日志和统计性查询
(2)Log browser
使用Loki日志浏览器,可以非常容易的浏览到所有的标签列表从而查询到相应的日志,也可以通过LogQL按需查询相应日志
Expolre
Grafana Explore模块支持深入探究、监察日志(支持Loki),查询的日志结果将已图表的形式进行可视化,对应的日志会在图表下方展示。用户也可以自定义日志的展示方法和图表的展现形式。
Alerts
Grafana Alerts模块支持发现系统运行时发生的问题,主要包括两个部分:
Alert rules – 报警何时会被触发,是根据一个或多个条件定义的规则,Grafana会周期性地进行评估
Notification channel-报警通过何种方式发送,支持钉钉,邮件等
当创建了Grafana仪表盘后,可在仪表盘下方配置报警条件、参数等,当前只有图形面板支持配置告警规则
4、方案对比
(1)首先,ELK/EFK架构功能确实强大,也经过了多年的实际环境验证,其中存储在Elasticsearch中的日志通常以非结构化JSON对象的形式存储在磁盘上,并且Elasticsearch为每个对象都建立了索引,以便进行全文搜索,然后用户可以特定查询语言来搜索这些日志数据。与之对应的Loki采用Golang开发,相比ES,Loki它更加轻量也更容易部署。Loki中的日志带有一组标签名和值,其中只有标签对被索引,通过存储压缩的非结构化日志和仅索引元数据, Loki操作更简单,运行更便宜,除此之外Loki特别适合存放 Kubernetes Pod日志; 诸如Pod标签之类的元数据会被自动删除和编入索引
(2)和Fluentd相比,Promtail是专门为Loki量身定制的,它可以为运行在同一节点上的Kubernetes Pods做服务发现,从指定文件夹读取日志。Loki采用了类似于Prometheus的标签方式。因此,当与Prometheus部署在同一个环境中时,因为相同的服务发现机制,来自Promtail的日志通常具有与应用程序指标相同的标签,统一了标签管理。
(3)Kibana提供了许多可视化工具来进行数据分析,高级功能比如异常检测等机器学习功能。Grafana专门针对Prometheus和Loki等时间序列数据打造,可以在同一个仪表板上查看日志的指标
相关背景
官方对Loki的介绍:Like Prometheus,But For Logs.,是类似于 Prometheus 的日志系统
(1)Prometheus
Prometheus是Google监控系统BorgMon类似实现的开源版,整套系统由, 监控服务、告警服务、时序数据库等几个部分,及周边生态的各种指标收集器(Exporter)组成,是在当下主流的云原生监控告警系统
(2)PromQL
PromQL是Prometheus内置的一个强大的数据查询语言。 通过PromQL可以实现对监控数据的查询、聚合。同时PromQL也被应用于数据可视化(如Grafana)以及告警当中