边侧监控选型
边侧监控方案
问题
边缘计算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上下载最新版,然后通过
mv prometheus-*.tar.gz prometheus.tar.gz
tar xvfz prometheus.tar.gz
cd prometheus
mkdir -p data
./prometheus
启动服务就行,默认时序数据库存在当前目录下的data
中,配置文件默认就是当前路径下的prometheus.yml
文件。
如果是docker,建议将配置文件挂载到外面,方便修改:
mkdir -p /etc/prometheus
docker run -p 9090:9090 -v /etc/prometheus/prometheus.yml:/etc/prometheus/prometheus.yml prom/prometheus
配置文件的格式:
# 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
添加告警规则文件。在后者里面填入告警规则,例如:
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支持模板化语法,方便填充实际值到告警信息,如:
{{$labels.<labelname>}}
{{$value}}
alerting
配置下面就是alertmanager
的静态配置,通过这里关联下面的alertmanager
。
除了告警之外,rule_files
还支持类似物化视图的异步计算时间序列,语法类似:
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文件夹之后启动即可。配置文件格式如下:
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
的配置例子:
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
用来抑制告警,语法如下:
- 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如下:
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的启动参数中可以添加:
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
指定之前启动的实例:
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
中就有这个包:
helm install kube-prometheus bitnami/kube-prometheus --namespace monitor --create-namespace --version 8.15.3
好消息是这个chart里面的镜像都是docker.io
上面的,所以docker正常配置代理就可以拉下来了,无须修改chart.
装好之后在monitor
下就可以看到对应的服务了:
NAME READY STATUS RESTARTS AGE
pod/kube-prometheus-node-exporter-k5gd6 1/1 Running 0 43m
pod/kube-prometheus-blackbox-exporter-8567bbfd99-7k8ms 1/1 Running 0 43m
pod/kube-prometheus-kube-state-metrics-5c9f68d87-5vdn6 1/1 Running 0 43m
pod/kube-prometheus-operator-c9c58b595-mv6kk 1/1 Running 0 43m
pod/alertmanager-kube-prometheus-alertmanager-0 2/2 Running 0 40m
pod/prometheus-kube-prometheus-prometheus-0 2/2 Running 0 40m
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/kube-prometheus-alertmanager ClusterIP 10.43.34.93 <none> 9093/TCP 43m
service/kube-prometheus-prometheus ClusterIP 10.43.96.98 <none> 9090/TCP 43m
service/kube-prometheus-kube-state-metrics ClusterIP 10.43.31.57 <none> 8080/TCP 43m
service/kube-prometheus-operator ClusterIP 10.43.33.45 <none> 8080/TCP 43m
service/kube-prometheus-blackbox-exporter ClusterIP 10.43.54.206 <none> 19115/TCP 43m
service/kube-prometheus-node-exporter ClusterIP 10.43.135.99 <none> 9100/TCP 43m
service/alertmanager-operated ClusterIP None <none> 9093/TCP,9094/TCP,9094/UDP 40m
service/prometheus-operated ClusterIP None <none> 9090/TCP 40m
NAME DESIRED CURRENT READY UP-TO-DATE AVAILABLE NODE SELECTOR AGE
daemonset.apps/kube-prometheus-node-exporter 1 1 1 1 1 <none> 43m
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/kube-prometheus-blackbox-exporter 1/1 1 1 43m
deployment.apps/kube-prometheus-kube-state-metrics 1/1 1 1 43m
deployment.apps/kube-prometheus-operator 1/1 1 1 43m
NAME DESIRED CURRENT READY AGE
replicaset.apps/kube-prometheus-blackbox-exporter-8567bbfd99 1 1 1 43m
replicaset.apps/kube-prometheus-kube-state-metrics-5c9f68d87 1 1 1 43m
replicaset.apps/kube-prometheus-operator-c9c58b595 1 1 1 43m
NAME READY AGE
statefulset.apps/alertmanager-kube-prometheus-alertmanager 1/1 40m
statefulset.apps/prometheus-kube-prometheus-prometheus 1/1 40m
主要是安装了prometheus、alertmanager和node exporter,满足基本使用需求. 其中prometheus和alertmanager都是sts,存储用的是emptydir:
这也意味着重启pod会导致时序数据库中的数据丢失,如果想要不丢失需要配置一下pvc(不过丢失一般也没啥,毕竟只是监控数据):
# 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
,如下:
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
里面定义服务暴露出来的端口和路径。
如果想要匹配所有命名空间,则格式为:
spec:
namespaceSelector:
any: true
同理,还有PodMonitor用来监控Pod.
告警配置
通过PrometheusRule
来配置告警,格式如下:
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
来配置:
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):
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
:
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上下载二进制文件之后直接启动就行:
mtail --progs /etc/mtail --logs /var/log/syslog --logs /var/log/ntp/peerstats --novm_logs_runtime_errors
--progs
对应的是mtail的配置文件,--logs
对应的是需要监控日志文件所在的文件夹。其他选项请参考这里。
配置
mtail的配置文件语法有点像awk,一个例子:
counter total
/^[a-z]+((?P<response_size>\d+)|-)$/ {
$1 != "-" {
total = $response_size
}
}
首先是声明变量,支持变量类型就是Prometheus的metric type,即:
- counter
- gauge
- histogram
根据文档描述,不支持summary. 变量支持hidden
修饰符,即不export该统计数据.
下面就是正则匹配,//
之间是golang的正则形式,后面应该有个空格。特别地,需要通过strptime
解析出日志中的时间戳。
需要复用的正则可以使用const
定义在最前面;如果解析时间戳的逻辑比较复杂,也可以使用装饰器语法定义一个函数:
# 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的语法:
@syslog
/foo/ {
...
}
如果时间戳里面有一些奇怪的符号,可以用subst
函数先替换掉。
/x/
的意思就是 $1 =~ /x/
,也可以写$1 !~ /x/
表示不匹配,当然也支持else
语法;同时还支持otherwise
语法,类似switch
的default
,即:
/pattern/ {
...
} else {
...
}
{
/pattern1/ {}
/pattern2/ {}
otherwise {}
}
完整的语法描述参考这里. 一个简单的统计错误日志的计数器如下:
counter error_line_total by filename
/ERROR/ {
error_line_total[getfilename()]++
}
通过3903端口将统计值暴露出去,prometheus那边配置好采集,加上一个简单的alert rule即可:
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
,需要在配置里面把对应的路径挂载上。
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配置,主要参考这里.
由于是国人项目,官方文档比较容易看懂,这里就不再赘述,请参考以下配置:
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
服务端:
loki -config.file=loki.local-config.yaml
需要一个配置文件,例如:
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),也需要一个配置文件,例如:
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
来装:
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工具。