边侧监控方案
问题
边缘计算v2适配了目前所有流行的应用部署方式:
裸系统(物理机)部署; docker部署; k8s部署; 因此对应的监控系统也要考虑兼顾各种部署方式。并且,随着时间的发展,平台会接入越来越多的边侧集群或者设备,因此要考虑负载问题。
目前阶段主要需要的是基本的异常检测(应用、机器、网络等),和即时告警通知 。由于边侧服务一般流量比较稳定,因此对于应用性能分析和统计数据等需求没有那么显著,而且这些都可以退化到基于日志来曲线解决问题。
除了监控自己平台的服务,还要考虑第三方服务接入的问题,因此在数据权限这块需要相对灵活。
选型
目前我们的云端服务也同时有这三种部署模式,使用的解决方案是基于ELK的技术栈。该方案能力强大,对Metric/Trace/Log都有完善的收集方案,缺点就是资源消耗很大。
考虑到上面分析的监控需求,以及云端资源的短缺问题,这里合理的方案是:
将监控服务配置在边缘侧而不是统一发送到云端; 尽量使用轻量级监控方案以减少资源占用; 需要支持通过命令行配置监控。因为目前边缘计算v2没做端口转发服务,依赖图形界面进行配置的,如zabbix
,如果现场没有windows机器就很难配置了; 需要支持windows采集,在特殊情况下,还是会使用windows host的。这就排除了ilogtail
等只支持linux的方案; 经过调研,这里还是使用基于prometheus
的方案,prometheus
本身就是基于配置文件进行配置的,查询可以使用命令行工具。主要依赖的东西:
prometheus server
. 部署在k8s内部或者裸机中。如果是混合部署环境(既需要k8s也需要裸机部署),应当部署在k8s里。这是因为prometheus是pull模型,可以访问k8s外面的服务;alert-manager
. 配置告警,目前主要考虑钉钉告警,后续根据第三方需求可以增加短信告警等,反正都是调用API;mtail
等轻量级日志收集工具,配合alert-manager完成错误日志告警;node-exporter
等各种exporter,这个需要用户自行安装。当然我们可以在边缘计算脚本/应用模板里面一些常用的;1~3都是使用golang编写,支持编译成各平台原生的二进制,能满足跨平台的需求。Trace相关的(OpenTelemetry
)收集一般使用Jaeger等工具,边侧使用到的可能性较小。
如果Log/Metric/Trace都需要收集,那还是直接用EFK这种大型系统吧,零零碎碎的部署更麻烦。
架构
这套架构是很成熟的方案,资料较多。核心思想就是prometheus
定时拉取各种exporter暴露出来的metrics端口,将数据存入时序数据库。AlertManager
等工具通过PromQL
查询语言与时序数据库交互,从而查询想要的数据:
在我们这里,主要使用prometheus
和AlertManager
,图形化的grafana
不是这个阶段 的重点。这主要是因为prometheus
是部署在边缘侧的,图形化工具在云端无法正常浏览,除非做端口转发。
端口转发需要引入其他agent(如rport
或者frp
),云端也需要打开端口段或者引入三级域名才能正常工作,运维上比较麻烦,现在暂时不考虑。
Metric & Alarm
即prometheus和alertManager部分。
一般安装
prometheus
如果在k8s外使用prometheus,就是一般的二进制安装。包括docker安装或者windows安装,原理都差不多。
prometheus-server
本身就是一个二进制文件,如果是裸机安装,只要从github上下载最新版,然后通过
1
2
3
4
5
mv prometheus-*.tar.gz prometheus.tar.gz
tar xvfz prometheus.tar.gz
cd prometheus
mkdir -p data
./prometheus
启动服务就行,默认时序数据库存在当前目录下的data
中,配置文件默认就是当前路径下的prometheus.yml
文件。
如果是docker,建议将配置文件挂载到外面,方便修改:
1
2
mkdir -p /etc/prometheus
docker run -p 9090:9090 -v /etc/prometheus/prometheus.yml:/etc/prometheus/prometheus.yml prom/prometheus
配置文件的格式:
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
# my global config
global :
scrape_interval : 15s # Set the scrape interval to every 15 seconds. Default is every 1 minute.
evaluation_interval : 15s # Evaluate rules every 15 seconds. The default is every 1 minute.
# scrape_timeout is set to the global default (10s).
# Alertmanager configuration
alerting :
alertmanagers :
- static_configs :
- targets :
# - alertmanager:9093
# Load rules once and periodically evaluate them according to the global 'evaluation_interval'.
rule_files :
# - "first_rules.yml"
# - "second_rules.yml"
# A scrape configuration containing exactly one endpoint to scrape:
# Here it's Prometheus itself.
scrape_configs :
# The job name is added as a label `job=<job_name>` to any timeseries scraped from this config.
- job_name : "prometheus"
# metrics_path defaults to '/metrics'
# scheme defaults to 'http'.
static_configs :
- targets : [ "localhost:9090" ]
里面是静态的抓取和告警配置。
默认抓取localhost:9090/metrics
,即prometheus
自身的metric.
prometheus自带了告警功能,但是不含通知 功能,需要配合alertmanager来完成通知。
修改上面的rule_files
添加告警规则文件。在后者里面填入告警规则,例如:
1
2
3
4
5
6
7
8
9
10
11
groups :
- name : example
rules :
- alert : HighErrorRate
expr : job:request_latency_seconds:mean5m{job="myjob"} > 0.5
for : 10m
labels :
severity : page
annotations :
summary : High request latency
description : description info
这个结构其实很像是k8s api object, 核心字段主要就是.groups[].rules[].expr
的PromQL表达式,以及for
的持续时间。labels
和annotations
是为告警添加的kv.
注意annotations
中的value支持模板化语法,方便填充实际值到告警信息,如:
1
2
{{$labels.<labelname>}}
{{$value}}
alerting
配置下面就是alertmanager
的静态配置,通过这里关联下面的alertmanager
。
除了告警之外,rule_files
还支持类似物化视图的异步计算时间序列,语法类似:
1
2
3
4
5
groups :
- name : example
rules :
- record : job:http_inprogress_requests:sum
expr : sum(http_inprogress_requests) by (job)
其中record
就是新产生的metric名称,expr是PromQL表达式。
alertmanager
如果是docker安装,可以使用docker-compose将二者一起安装。如果是二进制安装,方法类似prometheus,直接下载解压,创建data文件夹之后启动即可。配置文件格式如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
global :
resolve_timeout : 5m
route :
group_by : [ 'alertname' ]
group_wait : 5s
group_interval : 60s
repeat_interval : 1h
receiver : 'web.hook'
receivers :
- name : 'web.hook'
webhook_configs :
- url : 'http://127.0.0.1:5001/'
inhibit_rules :
- source_match :
severity : 'critical'
target_match :
severity : 'warning'
equal : [ 'alertname' , 'dev' , 'instance' ]
alertmanager的原理有点类似api网关,通过路由进行匹配,然后分发到不同的receiver
中。
route
的配置例子:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
route :
receiver : 'default-receiver'
group_wait : 30s
group_interval : 5m
repeat_interval : 4h
group_by : [ cluster, alertname]
routes :
- receiver : 'database-pager'
group_wait : 10s
match_re :
service : mysql|cassandra
- receiver : 'frontend-pager'
group_by : [ product, environment]
match :
team : frontend
首先是全局配置,默认接收器是default-receiver
,分组的依据是集群和告警名称。
group_wait
是告警触发之后等待合并同组告警的时间阈值;group_interval
是相同group发送通知的冷却时间;repeat_interval
是同一个告警的冷却时间。
routes
下面定义具体的子路由,通过match
或者match_re
来匹配Prometheus发送过来数据的label
.
可以添加continue
字段配置子路由匹配之后是否继续向下匹配,默认是false
.
receiver的格式取决于其类型,alertmanager内置了很多告警媒介,如邮件、telegram甚至微信。如钉钉这种虽然没有内置进去,但是可以通过webhook扩展,参考这里 。
告警信息同样可以使用消息模板,如果消息比较大也可以写成单独的模板文件。模板的语法和prometheus一样,同样遵从go template语法。
inhibit_rules
用来抑制告警,语法如下:
1
2
3
4
5
6
7
- source_match :
alertname : NodeDown
severity : critical
target_match :
severity : critical
equal :
- node
当已经发送的告警匹配到target_match
或target_match_re
规则,此时新的告警满足source_match
或者source_match_re
,则新的告警不会发送。
此外,管理员还可以通过alertmanager的界面配置临时静默。
高可用
对于边缘侧而言,prometheus一般部署一个就够了,因为边侧节点和服务的数量不会特别多。不过如果需要的话,也可以利用prometheus的联邦集群特性搭建集群。这个功能的核心就是/federate
接口可以直接将prometheus的监控数据暴露出去。例如配置prometheus如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
scrape_configs :
- job_name : 'federate'
scrape_interval : 15s
honor_labels : true
metrics_path : '/federate'
params :
'match[]' :
- '{job="prometheus"}'
- '{__name__=~"job:.*"}'
- '{__name__=~"node.*"}'
static_configs :
- targets :
- '192.168.77.11:9090'
- '192.168.77.12:9090'
则当前节点会自动抓取targets
中其他两个prometheus中的满足match[]
条件的数据。
但是集群联邦实际上解决的是高负载问题,单点的中心集群或者边侧集群仍然存在不可用风险。
由于k8s自己就是高可用的解决方案,所以k8s内的prometheus一般不需要考虑该问题。但是对于docker或者裸机部署,这个就需要思考一下。
官方给出的方案其实比较简单粗暴:部署多套一模一样的prometheus即可,因为是pull机制,并没有冲突。
alertmanager其实类似,也可以部署多套。不同的是,alertmanager的重复通知对用户影响很大。所以alertmanager的不同实例之间需要通信以组成真正的集群。alertmanager的启动参数中可以添加:
1
alertmanager --web.listen-address= ":9093" --cluster.listen-address= "127.0.0.1:8001" --config.file= /etc/prometheus/alertmanager.yml --storage.path= /data/alertmanager/
之后新增的alertmanager的参数中,通过cluster.peer
指定之前启动的实例:
1
alertmanager --web.listen-address= ":9094" --cluster.listen-address= "127.0.0.1:8002" --cluster.peer= 127.0.0.1:8001 --config.file= /etc/prometheus/alertmanager.yml --storage.path= /data/alertmanager2/
两者的配置文件一模一样,但是数据存储的位置不同。这些集群实例之间通过gossip协议进行通信。
服务发现
prometheus抓取除了支持static_configs
之外,还可以集成服务发现动态添加目标服务,不过很遗憾不支持nacos.
变通的方法是写一个nacos的客户端订阅nacos中的服务列表,然后变化时将数据写入文件,使用基于文件的服务发现。
不过在边侧,建议还是用静态配置吧,因为节点不会很多。
自定义标签
除了exporter自己暴露的标签外,在scrape_configs
下面可以增加labels
或者relabel_config
,用来添加自定义标签,后者一般配合服务发现使用。
k8s内安装
安装
在k8s里面安装,不要直接安装prometheus
,而是选择第三方封装的prometheus-operator .
从上面可以看到,prometheus
只有一个单纯的二进制文件,依赖配置文件进行配置,所以每次修改配置都要重启服务,这显然不符合k8s的设计思路。将服务封装成operator,然后通过修改yaml来进行配置才是更合适的方案。
CoreOS引入了Operator的概念,这里我们使用helm来安装,用到的包是kube-prometheus
,bitnami
中就有这个包 :
1
helm install kube-prometheus bitnami/kube-prometheus --namespace monitor --create-namespace --version 8.15.3
好消息是这个chart里面的镜像都是docker.io
上面的,所以docker正常配置代理就可以拉下来了,无须修改chart.
装好之后在monitor
下就可以看到对应的服务了:
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
NAME READY STATUS RESTARTS AGE
pod / kube - prometheus - node - exporter - k5gd6 1 / 1 Running 0 43 m
pod / kube - prometheus - blackbox - exporter - 8567 bbfd99 - 7 k8ms 1 / 1 Running 0 43 m
pod / kube - prometheus - kube - state - metrics - 5 c9f68d87 - 5 vdn6 1 / 1 Running 0 43 m
pod / kube - prometheus - operator - c9c58b595 - mv6kk 1 / 1 Running 0 43 m
pod / alertmanager - kube - prometheus - alertmanager - 0 2 / 2 Running 0 40 m
pod / prometheus - kube - prometheus - prometheus - 0 2 / 2 Running 0 40 m
NAME TYPE CLUSTER - IP EXTERNAL - IP PORT ( S ) AGE
service / kube - prometheus - alertmanager ClusterIP 10.43 . 34.93 < none > 9093 / TCP 43 m
service / kube - prometheus - prometheus ClusterIP 10.43 . 96.98 < none > 9090 / TCP 43 m
service / kube - prometheus - kube - state - metrics ClusterIP 10.43 . 31.57 < none > 8080 / TCP 43 m
service / kube - prometheus - operator ClusterIP 10.43 . 33.45 < none > 8080 / TCP 43 m
service / kube - prometheus - blackbox - exporter ClusterIP 10.43 . 54.206 < none > 19115 / TCP 43 m
service / kube - prometheus - node - exporter ClusterIP 10.43 . 135.99 < none > 9100 / TCP 43 m
service / alertmanager - operated ClusterIP None < none > 9093 / TCP , 9094 / TCP , 9094 / UDP 40 m
service / prometheus - operated ClusterIP None < none > 9090 / TCP 40 m
NAME DESIRED CURRENT READY UP - TO - DATE AVAILABLE NODE SELECTOR AGE
daemonset . apps / kube - prometheus - node - exporter 1 1 1 1 1 < none > 43 m
NAME READY UP - TO - DATE AVAILABLE AGE
deployment . apps / kube - prometheus - blackbox - exporter 1 / 1 1 1 43 m
deployment . apps / kube - prometheus - kube - state - metrics 1 / 1 1 1 43 m
deployment . apps / kube - prometheus - operator 1 / 1 1 1 43 m
NAME DESIRED CURRENT READY AGE
replicaset . apps / kube - prometheus - blackbox - exporter - 8567 bbfd99 1 1 1 43 m
replicaset . apps / kube - prometheus - kube - state - metrics - 5 c9f68d87 1 1 1 43 m
replicaset . apps / kube - prometheus - operator - c9c58b595 1 1 1 43 m
NAME READY AGE
statefulset . apps / alertmanager - kube - prometheus - alertmanager 1 / 1 40 m
statefulset . apps / prometheus - kube - prometheus - prometheus 1 / 1 40 m
主要是安装了prometheus、alertmanager和node exporter,满足基本使用需求. 其中prometheus和alertmanager都是sts,存储用的是emptydir:
这也意味着重启pod会导致时序数据库中的数据丢失,如果想要不丢失需要配置一下pvc(不过丢失一般也没啥,毕竟只是监控数据):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
# ref: https://artifacthub.io/packages/helm/bitnami/kube-prometheus
kubectl create ns monitor
helm install prometheus-stack bitnami/kube-prometheus -n monitor --version 8.15.4 \
--set global.storageClass= local-path \
--set prometheus.persistence.enabled= true \
--set alertmanager.persistence.enabled= true \
--set prometheus.retention= "72h" \
--set alertmanager.retention= "72h" \
--set kubelet.serviceMonitor.resourcePath= /metrics/resource \
--set prometheus.service.type= LoadBalancer \
--set alertmanager.service.type= LoadBalancer \
--set prometheus.ruleSelector.matchLabels.monitor= default \
--set alertmanager.configSelector.matchLabels.monitor= default \
--set alertmanager.externalConfig= true
默认会启动2个ClusterIP
类型的service,对应prometheus
和alertmanager
的server,端口分别是9090和9093,内部域名分别是prometheus-stack-prometheus.monitor.svc.cluster.local
和prometheus-stack-alertmanager.monitor.svc.cluster.local
.
上面配置将service的type改为LoadBalancer
,这样就可以通过外网访问对应的端口了。当然理论上也可以通过配置ingress来达到该目的,请参考这里 .
默认情况下,kube-prometheus
会安装NodeExporter
,所以在安装结束之后,可以打开prometheus
的web页,输入up
查看一下该功能是否正常。或者简单点输入curl localhost:9090/api/v1/query?query=up
看一下也行。
监控配置
Operator通过CRD对象进行配置,增加一个服务监控就是增加一个ServiceMonitor
,如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
apiVersion : monitoring.coreos.com/v1
kind : ServiceMonitor
metadata :
name : example-app
namespace : monitor
labels :
team : frontend
spec :
namespaceSelector :
matchNames :
- default
selector :
matchLabels :
app : example-app
endpoints :
- port : 80
显然namespaceSelector
定义服务所在命名空间;selector
用来通过label匹配服务;endpoints
里面定义服务暴露出来的端口和路径。
如果想要匹配所有命名空间,则格式为:
1
2
3
spec :
namespaceSelector :
any : true
同理,还有PodMonitor用来监控Pod.
告警配置
通过PrometheusRule
来配置告警,格式如下:
1
2
3
4
5
6
7
8
9
10
11
12
apiVersion : monitoring.coreos.com/v1
kind : PrometheusRule
metadata :
labels :
monitor : default
name : prometheus-example-rules
spec :
groups :
- name : example-rules
rules :
- alert : ExampleAlert
expr : vector(1)
groups
下面的语法和普通的prometheus的rules文件没啥区别。
AlertManager
则通过AlertmanagerConfig
来配置:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
apiVersion : monitoring.coreos.com/v1alpha1
kind : AlertmanagerConfig
metadata :
name : config-example
labels :
monitor : default
spec :
route :
groupBy : [ 'job' ]
groupWait : 30s
groupInterval : 5m
repeatInterval : 12h
receiver : 'webhook'
receivers :
- name : 'webhook'
webhookConfigs :
- url : 'http://example.com/'
.spec
的内容和直接配置alertmanager的配置文件格式也是一样的。
注意 :比较蛋疼的是,Alertmanager上面的配置会被强制注入一个namespace
的匹配标签,所以无法在所有命名空间生效。解决办法是自己创建一个全局的配置,而不是使用默认的全局配置。
所以在使用helm安装之前,需要自己创建一个secret,如果helm应用叫prometheus-stack
,那么secret应该叫alertmanager-prometheus-stack-kube-prom-alertmanager
,里面有个key
叫alertmanager.yaml
,内容是(base64):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
global :
resolve_timeout : 5m
route :
group_by : [ 'job' ]
group_wait : 5s
group_interval : 1m
repeat_interval : 15m
receiver : 'null'
routes :
- matchers :
- alertname = Watchdog
receiver : 'null'
- matchers :
- severity =~ "critical|warning"
receiver : webhook
receivers :
- name : 'null'
- name : 'webhook'
webhook_configs :
- url : 'http://edge-webhook:9095/api/v1/alert'
send_resolved : true
特别需要注意的是,这个配置文件里面有个默认的WatchDog路径,这是不能删掉的,不然alertmanager就不work了。
黑盒探测
注意到这种方法只能添加k8s内的pod或者服务,如果想要从k8s外的http接口拉取数据。则需要使用Probe
,配合blackbox-exporter
来使用。
如果查看deployments,可以看到black-box的deploy,configmap
中也有一个相关的配置。实际上black-box就是一个通过ping/tcp/udp探测的服务。使用方法就是创建Probe
:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
apiVersion : monitoring.coreos.com/v1
kind : Probe
metadata :
name : domain-probe
namespace : monitoring
labels :
monitor : default
spec :
jobName : domain-probe
prober :
url : prometheus-stack-kube-prom-blackbox-exporter:19115
module : http_2xx
targets :
# ingress:{}
staticConfig :
static :
- baidu.com
module支持各种探测方法,包括:http_2xx
, http_post_2xx
, tcp_connect
, pop3s_banner
, ssh_banner
, irc_banner
,这些都默认配置在blackbox的configmap里了。实际上还可以增加更多,但是默认没打开,如grpc
/icmp
/dns
这些,具体参考这里 。
.spec.prober.url
就是blackbox
服务的容器地址,如果不在同一个namespace
就要使用完全限定名了,即prometheus-stack-kube-prom-blackbox-exporter.monitor.svc.cluster.local:19115
.
注意目前尚不支持UDP探测。
关联配置
默认情况下,ServiceMonitor/Probe
创建后会自动生效。但是PrometheusRule
则不会,我在上面配置了selector
中的matchLabels
条件,所以需要添加.metadata.labels.monitor
=default
来匹配上这个规则。同理AlertManagerConfig
也需要通过label关联。
这里的设计实际上有点混乱,有的API对象是直接默认就会关联,有的必须要加标签。如果记不住就都加上monitor:default
的标签即可。
常用告警配置
请参考这个项目 ,基本常用的exporter对应的告警都有。
Log
实际上我们一般需要做的是错误日志告警 ,即出现ERROR日志的时候通过alertmanager
发送告警,而不需要真正的收集日志。边缘侧收集日志推荐使用loki
,比efk
更加轻量级,简单的日志统计功能推荐使用Google的mtail
.
特别注意的是:如果能通过prometheus收集错误响应(5xx)的次数等数据,就没必要部署mtail来统计错误日志了。不过非请求(如定时任务或异步任务)就需要自己在代码里统计metric暴露了。
mtail
mtail
实际上是一种特殊的exporter, 它使用正则过滤日志,并做简单的统计,最后将统计值暴露出去。不同的是mtail
还支持push模式。
Google并没有提供mtail
的官方镜像,更别说helm chart了,所以它的安装有点麻烦。
一般安装
mtail
仍然只是一个go写的二进制文件,依赖配置文件驱动。所以从github上下载二进制文件之后直接启动就行:
1
mtail --progs /etc/mtail --logs /var/log/syslog --logs /var/log/ntp/peerstats --novm_logs_runtime_errors
--progs
对应的是mtail的配置文件,--logs
对应的是需要监控日志文件所在的文件夹。其他选项请参考这里 。
配置
mtail的配置文件语法有点像awk,一个例子:
1
2
3
4
5
6
counter total
/^[a-z]+((?P<response_size>\d+)|-)$/ {
$1 != "-" {
total = $response_size
}
}
首先是声明变量,支持变量类型就是Prometheus的metric type,即:
根据文档描述,不支持summary. 变量支持hidden
修饰符,即不export该统计数据.
下面就是正则匹配,//
之间是golang的正则形式,后面应该有个空格。特别地,需要通过strptime
解析出日志中的时间戳。
需要复用的正则可以使用const
定义在最前面;如果解析时间戳的逻辑比较复杂,也可以使用装饰器语法定义一个函数:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# The `syslog' decorator defines a procedure. When a block of mtail code is
# "decorated", it is called before entering the block. The block is entered
# when the keyword `next' is reached.
def syslog {
/(?P<date>(?P<legacy_date>\w+\s+\d+\s+\d+:\d+:\d+)|(?P<rfc3339_date>\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}.\d+[+-]\d{2}:\d{2}))/ +
/\s+(?:\w+@)?(?P<hostname>[\w\.-]+)\s+(?P<application>[\w\.-]+)(?:\[(?P<pid>\d+)\])?:\s+(?P<message>.*)/ {
# If the legacy_date regexp matched, try this format.
len($legacy_date) > 0 {
strptime($legacy_date, "Jan _2 15:04:05")
}
# If the RFC3339 style matched, parse it this way.
len($rfc3339_date) > 0 {
strptime($rfc3339_date, "2006-01-02T15:04:05-07:00")
}
# Call into the decorated block
next
}
}
上面是官方的例子,它定义了两种可能的时间格式。使用方法是类似python的语法:
1
2
3
4
@syslog
/foo/ {
...
}
如果时间戳里面有一些奇怪的符号,可以用subst
函数先替换掉。
/x/
的意思就是 $1 =~ /x/
,也可以写$1 !~ /x/
表示不匹配,当然也支持else
语法;同时还支持otherwise
语法,类似switch
的default
,即:
1
2
3
4
5
6
7
8
9
10
11
/pattern/ {
...
} else {
...
}
{
/pattern1/ {}
/pattern2/ {}
otherwise {}
}
完整的语法描述参考这里 . 一个简单的统计错误日志的计数器如下:
1
2
3
4
5
counter error_line_total by filename
/ERROR/ {
error_line_total[getfilename()]++
}
通过3903端口将统计值暴露出去,prometheus那边配置好采集,加上一个简单的alert rule即可:
1
2
3
4
5
6
7
8
9
10
groups :
- name : LogStatExporter
rules :
- alert : FileErrorAlert
expr : sum(increase(error_line_total[1m])) by (filename) > 0
labels :
severity : critical
annotations :
summary : "Log file {{ $labels.filename }} has excessive errors"
description : "Log file {{ $labels.filename }} has experienced {{ $value }} errors in the last 1m"
k8s安装
如果k8s容器的日志都以stdout/stderr打出来(按k8s官方推荐的方法)或者挂载到了宿主机,那么mtail可以使用DaemonSet
部署。stdout的日志路径都在/var/log/container
下面,宿主机路径也是固定的,所以静态配置DaemonSet即可。
如果k8s容器的日志打在了容器里面,或者使用了分布式文件存储(如longhorn),那只能使用sidecar部署模式,需要每个app自行部署。
部署完成之后,需要增加Prometheus的ServiceMonitor
配置,然后配置PrometheusRule
来配置告警。
Loggie
这个是在调研中意外发现的一个国人项目 ,应该是网易团队开源的,他的功能比mtail更加丰富,但是又不像loki
那么重,而且也是golang编写,比阿里用C++写的logtail适用范围更广。更重要的是,loggie是完全开源的,比阿里的半吊子开源部分组件还要商业化要友好的多。
mtail
的问题有几个:
只能满足简单的统计需求,value只能是number; prometheus
本身就不适合用来做日志统计,因为日志收集的信息各种各样,比如错误日志一般要将错误信息记录下来,这个放在Prometheus的tag里很不合适(重复度低,而且信息太长)。这就触发告警时能携带的上下文消息太少:比如错误日志告警就只能提示有错误日志,无法将错误信息也带上。mtail没有云原生支持,还是通过传统的配置文件来管理; Loggie
则较好的解决了这几个问题,而且他自带了logAlert功能,可以完成告警的需求。
一般安装
官方的Release实际上只有linux amd64的二进制,其他的要自己build。写这篇文档的时候windows兼容性还有点问题,建议windows上还是用mtail作为平替。
linux版本的安装参考这里 即可。
k8s安装
支持helm安装,参考这里 .
特别需要注意的是:如果日志挂载到hostpath
,需要在配置里面把对应的路径挂载上。
1
2
3
4
5
6
7
helm install loggie https://ghproxy.com/https://github.com/loggie-io/installation/releases/download/v1.4.0/loggie-v1.4.0.tgz -n monitor \
--set image = loggieio/loggie:v1.4.1 \
--set config.loggie.discovery.enabled= true \
--set config.loggie.discovery.kubernetes.containerRuntime= docker \
--set config.loggie.discovery.kubernetes.rootFsCollectionEnabled= true \
--set config.loggie.discovery.kubernetes.parseStdout= true \
--set serviceMonitor.enabled= true
配置
支持通过CRD配置,主要参考这里 .
由于是国人项目,官方文档比较容易看懂,这里就不再赘述,请参考以下配置:
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
apiVersion : loggie.io/v1beta1
kind : ClusterLogConfig
metadata :
name : error-log-grep
spec :
selector :
type : pod
labelSelector :
alertError : open
pipeline :
sources : |
- type: file
name: stdout
addonMeta: true
paths:
- stdout
sink : |
type: alertWebhook
addr: http://edge-webhook:9095/api/v1/loggie
interceptors : |
- type: rateLimit
qps: 4096
- type: logAlert
matcher:
contains: ["ERROR"]
sendOnlyMatched: true
Loki
上面两个组件做简单的日志过滤都不错,如果有日志收集的需求,建议还是使用Loki
.
粗略看来,Loki的设计和Prometheus有很多相似之处,配置文件的字段都差不多,LogQL
查询语言和PromQL
也很像。在k8s中,也有Loki Operator
项目,不过很遗憾bitnami中没有对应的chart,官方仓库 需要翻墙。
但是日志场景实际上比较复杂,Loki并不是pull模型的一般由promtail
来解析日志然后通过Loki的HTTP接口推送日志。Loki的架构比Prometheus也复杂很多,虽然也是单个二进制文件,但是支持-target
参数,使其扮演不同的角色,从而拆分成微服务架构。
Loki的数据分为Chunks
和Index
两种,二者需要不同存储介质。在边缘侧部署,一般使用Loki的单体模式就够了。这种情况下,Loki将所有chunk数据存入文件系统;否则,必须指定一个块文件存储系统,如minio.
Loki相关资料比较复杂,下面只是简述供参考。
一般安装
到github 下载二进制文件(或者使用docker安装也行),包括:
logcli
: 这是命令行客户端,Prometheus也有类似的promql-cli
,不过后者是社区提供的;loki
:核心服务器程序;promtail
:抓取日志的客户端;启动loki
服务端:
1
loki -config.file= loki.local-config.yaml
需要一个配置文件 ,例如:
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
auth_enabled : false
server :
http_listen_port : 3100
common :
ring :
instance_addr : 127.0.0.1
kvstore :
store : inmemory
replication_factor : 1
path_prefix : /tmp/loki
schema_config :
configs :
- from : 2020-05-15
store : boltdb-shipper
object_store : filesystem
schema : v11
index :
prefix : index_
period : 24h
storage_config :
boltdb_shipper :
active_index_directory : /data/loki/boltdb-shipper-active
cache_location : /data/loki/boltdb-shipper-cache
cache_ttl : 24h
shared_store : filesystem
filesystem :
directory : /data/loki/chunks
table_manager :
retention_deletes_enabled : true
retention_period : 72h
上面的配置主要就是使用了本地存储,并且指定了index和存储路径,最后指明日志仅存储3天(注意这个值必须是24h的整数倍)。
然后启动promtail(也可以用docker),也需要一个配置文件 ,例如:
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
server :
http_listen_port : 9080
grpc_listen_port : 0
positions :
filename : /var/log/positions.yaml # This location needs to be writeable by Promtail.
client :
backoff_config :
max_period : 5s
max_retries : 20
min_period : 100ms
batchsize : 102400
batchwait : 1s
timeout : 10s
clients :
- url : http://ip_or_hostname_where_Loki_run:3100/loki/api/v1/push
scrape_configs :
- job_name : system
pipeline_stages :
static_configs :
- targets :
- localhost
labels :
job : varlogs # A `job` label is fairly standard in prometheus and useful for linking metrics and logs.
host : yourhost # A `host` label will help identify logs from this machine vs others
__path__: /var/log/*.log # The path matching uses a third party library : https://github.com/bmatcuk/doublestar
上面是一个静态文件夹下的日志抓取配置。
除了这些以外,还有很多配置选项,这里不再描述,使用的时候自己看文档即可。
k8s安装
官方的loki-stack
被墙了,这里还是用bitnami
的grafana-loki
来装:
1
2
3
4
5
6
helm install loki-stack bitnami/grafana-loki -n monitor --version 2.10.1 \
--set global.storageClass= longhorn \
--set metrics.enabled= true \
--set metrics.serviceMonitor.enabled= true \
--set gateway.service.type= LoadBalancer \
--set gateway.service.ports.http= 9092
需要注意的loki
本身没有界面,需要安装grafana
,或者使用logcli
工具来交互。
告警配置
类似prometheus,也是通过rule来配置,请参考这里 .
总结
Linux/K8s环境使用Loggie;windows环境使用mtail。
需要一个webhook服务,用来将告警发送到钉钉等im工具。