目录

Loki日志聚合系统

loki简介

Loki是 Grafana Labs 团队最新的开源项目,是一个水平可扩展,高可用性,多租户的日志聚合系统。它的设计非常经济高效且易于操作,因为它不会为日志内容编制索引,而是为每个日志流编制一组标签。项目受 Prometheus 启发,官方的介绍就是:Like Prometheus, but for logs.,类似于 Prometheus 的日志系统。

与其他日志聚合系统相比,Loki具有下面的一些特性:

  • 不对日志进行全文索引。通过存储压缩非结构化日志和仅索引元数据,Loki 操作起来会更简单,更省成本。
  • 通过使用与 Prometheus 相同的标签记录流对日志进行索引和分组,这使得日志的扩展和操作效率更高。
  • 特别适合储存 Kubernetes Pod 日志; 诸如 Pod 标签之类的元数据会被自动删除和编入索引。
  • 受 Grafana 原生支持。

Loki 由以下3个部分组成:

  • loki是主服务器,负责存储日志和处理查询。
  • promtail是代理,负责收集日志并将其发送给 loki 。
  • Grafana用于 UI 展示

Loki 的功能组件

  • promtail
  • distributor
  • ingester
  • querler
  • query frontend
  • overrides
  • tablemanager
  • runtimeconfig

Loki架构图 https://tc.ctq6.cn/tc/ba8c0ac799049ac07e5acdaec195bf4f.png

Promtail

Promtail 是负责日志数据的采集、提取、匹配、过滤、打 lables、Push to loki 这写工作的

支持的采集方式包括 File Target、Journal Target、Syslog Target、Stdin Target

整个 Promtail 对日志数据处理流程如下 Promtail数据处理流程图 https://tc.ctq6.cn/tc/c7d0d50627b9e9fc06bb5348e8728045.png

Distributor

Distributor 主要接收 Promtail Push 过来的日志数据,并把日志数据分发给 Ingester

Distributor 与 Ingester 之间以 RPC 的方式进行通信,它通过对元数据进行 hash 算法计算出将日志数据分发到哪一个 Ingester 上

Distributor 以日志数据的 TenantID、Labels 作为 Hash key

Ingester

Ingester 负责接收数据并构建 chunk,存储日志索引及数据

Ingester构建chunk https://tc.ctq6.cn/tc/fb89220ba908a7577c26a15b9341baca.png

当一个 chunk 填充满之后,ingester 将其刷新到数据库,块和索引分别进行存储

Ingester存储chunk和index https://tc.ctq6.cn/tc/d240178d4883fc121d2f598db04506c3.png

刷新完一个 chunk 之后,Ingester 会创建一个空的 chunk

Querier

Querier 负责数据读取,它通过给定的一个时间范围和标签选择器,查看索引以确定哪些块匹配,并通过 greps 聚合各个 Ingester 中的数据,并将结果返回给 client

https://tc.ctq6.cn/tc/66f4403825bd5b07550a08f55ed4fa13.png

Grafana

Loki 的数据查询,都是通过 Grafana,在 Grafana 中支持 loki 的数据源,通过配置 Loki 的接口地址即可

Grafana 的查询,支持 LogQL,在 Grafana 中查询都是通过 Label 或 log 文本,支持语法如下:

Lable 的操作符:

  • = exactly equal
  • != not equal
  • =~ regex-match
  • !~ do not regex-match

Loki语法说明

选择器

对于查询表达式的标签部分,将其包装在花括号中{},然后使用键值对的语法来选择标签,多个标签表达式用逗号分隔,比如

  • |=:日志行包含字符串。
  • !=:日志行不包含字符串。
  • |~:日志行匹配正则表达式。
  • !~:日志行与正则表达式不匹配

精确匹配:|=“2020-11-16 "

1
{app_kubernetes_io_instance="x'x'x'x"}|="2020-11-16 "

模糊匹配:|~“2020-11-16 "

1
{app_kubernetes_io_instance="x'x'x'x'x"}|~"2020-11-16 "

排除过滤:!=/!~ “数据中心”

1
2
{app_kubernetes_io_instance="x'x'x'x'x"}!="数据中心"
{app_kubernetes_io_instance="x'x'x'x'x'x'x'x'x"}!~"数据中心"

正则匹配: |~ “()”

1
2
{app_kubernetes_io_instance="x'x'x'x'x'x"}!~"(admin|web)"
{app_kubernetes_io_instance="x'x'x'x'x'x'x"}|~"ERROR|error"

范围查询

  • rate:计算每秒的条目数
  • count_over_time:计算给定范围内每个日志流的条目

三十分钟日志行记录

1
count_over_time({app_kubernetes_io_instance="UUUU"}[30m]) 

12h小时内出现错误的速率

1
rate({app_kubernetes_io_instance=~".*UUUUU.*"} |~ "ERROR|error" [12h])

集合运算

与PromQL一样,LogQL支持内置聚合运算符的一个子集,可用于聚合单个向量的元素,从而产生具有更少元素但具有集合值的新向量:

  • sum:计算标签上的总和
  • min:选择最少的标签
  • max:选择标签上方的最大值
  • avg:计算标签上的平均值
  • stddev:计算标签上的总体标准差
  • stdvar:计算标签上的总体标准方差
  • count:计算向量中元素的数量
  • bottomk:通过样本值选择最小的k个元素
  • topk:通过样本值选择最大的k个元素

统计1个小时日志量最大的前10个服务

1
topk(10,sum(rate({app_kubernetes_io_instance=~".*uuuu.*"}[60m])) by(container))

统计最近6小时内错误日志计数

1
sum(count_over_time({app_kubernetes_io_instance=~".*uuuuuu.*"}|~"ERROR"[6h])) by (container)

Loki Url 表达式编写

url如下

1
https://localhost:3100/explore?orgId=1&left=%5B%22now-1h%22,%22now%22,%22Loki%22,%7B%22expr%22:%22%7Bapp_kubernetes_io_instance%3D~%5C%22user-service%5C%22%7D%7C~%5C%222020-11-05%5C%22%7C~%5C%22ERROR%5C%22%7C~%5C%22.aaa.%5C%22%22,%22maxLines%22:5000%7D%5D

分析

  • 1、%7C 表示|
  • 2、%5C%22 表示”
  • 3、时间:now-1h 可替换 now-1min或者 now-5min
  • 4、项目名称:user-service 可替换为 .service. 或者 web-service
  • 5、查询日志:2020-11-05 可替换为 2020-11-04
  • 6、删除一个管道 %7C%5C%22ERROR%5C%22%7C%5C%22.aaa.%5C%22 这一段删除
  • 最后生成的链接粘贴到浏览器访问 也可通过url加解密生成最终查询url链接

url加解密

进入指定网站中,https://www.sojson.com/encodeurl.html

上例中解密如下:

1
https://localhsot/explore?orgId=1&left=["now-1m","now","Loki",{"expr":"{app_kubernetes_io_instance%3D\"user-service-\"}|\"2020-11-05\"|\"ERROR\"|\".aaaaa.\"","maxLines":5000}]

根据自定义查询语句

  • 根据日期查询
    • 编写查询语句
    1
    
    https://lcoalhsot/explore?orgId=1&left=["now-1h","now","Loki",{"expr":"{app_kubernetes_io_instance=~\"user-service\"}|~\"2020-11-18\"","maxLines":5000}]
    
    • 加密
    1
    
    https://lcoalhsot/explore?orgId=1&left=%5B%22now-1h%22,%22now%22,%22Loki%22,%7B%22expr%22:%22%7Bapp_kubernetes_io_instance=~%5C%22user-service%5C%22%7D%7C~%5C%222020-11-18%5C%22%22,%22maxLines%22:5000%7D%5D
    
  • 根据服务名称查询
    • 编写查询语句
    1
    
    https://localhost/explore?orgId=1&left=["now-1h","now","Loki",{"expr":"{app_kubernetes_io_instance=~\"data-service\"}|~\"2020-11-18\"","maxLines":5000}]
    
    • 加密
    1
    
    https://localhost/explore?orgId=1&left=%5B%22now-1h%22,%22now%22,%22Loki%22,%7B%22expr%22:%22%7Bapp_kubernetes_io_instance=~%5C%22data-service%5C%22%7D%7C~%5C%222020-11-18%5C%22%22,%22maxLines%22:5000%7D%5D
    
  • 根据对应的数据库查询
    • 编写查询语句
    1
    
    https://localhost/explore?orgId=1&left=["now-1h","now","Loki",{"expr":"{app_kubernetes_io_instance=~\"data-service\"}|~\"2020-11-18\"|~\"database\"","maxLines":5000}]
    
    • 加密
    1
    
    https://localhost/explore?orgId=1&left=%5B%22now-1h%22,%22now%22,%22Loki%22,%7B%22expr%22:%22%7Bapp_kubernetes_io_instance=~%5C%22data-service%5C%22%7D%7C~%5C%222020-11-18%5C%22%7C~%5C%22database%5C%22%22,%22maxLines%22:5000%7D%5D
    

加密好的url直接粘贴到浏览器中即可查询

Loki api使用

  • 查询标签

    1
    
    curl -G -s  "http://localhost:3100/loki/api/v1/labels" | jq
    
     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
    
    curl -G -s  "http://lcoalhpst:3100/loki/api/v1/labels" | jq .data[]
    "__name__"
    "app"
    "app_kubernetes_io_component"
    "app_kubernetes_io_instance"
    "app_kubernetes_io_managed_by"
    "app_kubernetes_io_name"
    "app_kubernetes_io_version"
    "chart"
    "component"
    "container"
    "controller_revision_hash"
    "filename"
    "helm_sh_chart"
    "heritage"
    "job"
    "k8s_app"
    "name"
    "namespace"
    "pod"
    "pod_template_generation"
    "pod_template_hash"
    "release"
    "releaseRevision"
    "statefulset_kubernetes_io_pod_name"
    "stream"
    "task"
    
  • 根据标签查询对应标签值

    1
    
    curl -G -s http://localhost:3100/loki/api/v1/label/<name>/values |jq
    
    1
    2
    3
    
    curl -G -s  "http://lcoalhost:3100/loki/api/v1/label/app_kubernetes_io_instance/values" | jq .data[]
    "web-service"
    "user-service"
    
  • 根据标签查询对应的日志

    1
    2
    
    
    curl -G -s http://localhost:3100/loki/api/v1/query_range | jq
    
    • 查询对应日志
    1
    
    curl -G -s  "http://lcoalhost:3100/loki/api/v1/query_range" --data-urlencode 'query={app_kubernetes_io_instance=~".*user-service.*"}|~"ERROR|error"' | jq .data.result | jq .[].values[0][1]
    

Loki安装部署

使用Helm安装Loki

前提

首先需要确保已经部署了 Kubernetes 集群,并安装配置了 Helm 客户端,然后添加 Loki 的 chart 仓库:

1
helm repo add loki https://grafana.github.io/loki/charts

可以使用如下命令更新chart仓库:

1
helm repo update
部署Loki

使用默认配置部署

1
helm upgrade --install loki loki/loki-stack

指定命名空间

1
helm upgrade --install loki --namespace=logging loki/loki

指定配置

1
helm upgrade --install loki loki/loki --set "key1=val1,key2=val2,..."

部署 Loki 工具栈(Loki, Promtail, Grafana, Prometheus)

1
2
helm upgrade --install loki loki/loki-stack \
    --set fluent-bit.enabled=true,promtail.enabled=false,grafana.enabled=true,prometheus.enabled=true,prometheus.alertmanager.persistentVolume.enabled=false,prometheus.server.persistentVolume.enabled=false
部署grafana

使用 Helm 安装 Grafana 到 Kubernetes 集群,可以使用如下所示命令:

1
helm install stable/grafana -n loki-grafana

要获取 Grafana 管理员密码,可以使用如下所示命令:

1
kubectl get secret --namespace <YOUR-NAMESPACE> loki-grafana -o jsonpath="{.data.admin-password}" | base64 --decode ; echo

要访问 Grafana UI 页面,可以使用下面的命令:

1
kubectl port-forward --namespace <YOUR-NAMESPACE> service/loki-grafana 3000:80

然后在浏览器中打开http://localhost:3000,用 admin 和上面输出的密码进行登录。然后 按照提示添加 Loki 数据源,Loki 地址为http://loki:3100

使用Docker安装Loki

前提
  • Docker
  • Docker-compose
使用docker安装

执行完成后,loki-config.yaml 和 promtail-config.yaml 两个配置文件会被下载到我们使用的目录下面,Docker 容器会使用这些配置文件来运行 Loki 和 Promtail

1
2
3
4
wget https://raw.githubusercontent.com/grafana/loki/v1.5.0/cmd/loki/loki-local-config.yaml -O loki-config.yaml
docker run -v $(pwd):/mnt/config -p 3100:3100 grafana/loki:1.5.0 -config.file=/mnt/config/loki-config.yaml
$ wget https://raw.githubusercontent.com/grafana/loki/v1.5.0/cmd/promtail/promtail-docker-config.yaml -O promtail-config.yaml
docker run -v $(pwd):/mnt/config -v /var/log:/var/log grafana/promtail:1.5.0 -config.file=/mnt/config/promtail-config.yaml
使用Docker Compose安装
1
2
wget https://raw.githubusercontent.com/grafana/loki/v1.5.0/production/docker-compose.yaml -O docker-compose.yaml
docker-compose -f docker-compose.yaml up