云原生内容分享(十二):云原生的日志监控系统(Loki-stack)

目录

首先说一下需求

解决该需求可供选择的方案

ELK

Loki

Loki与ELK的主要区别在于:

今天的重头戏 Loki

loki组件介绍

Grafana

loki 架构

数据处理过程

在k8s中部署Loki日志系统

Helm安装

部署

安装

查看


首先说一下需求

  • 公司的容器云运行的应用或某一个节点出现了问题,解决的思路

  • 问题首先被prometheus监控

  1. metric是来说明当前或者历史达到了某个值

  2. alert设置metric达到某个特定的基数触发了告警

仅仅这些日志是不能够解决问题的 还需要看下应用的日志

  • k8s的基本单位是pod

  • pod把日志输出到stdout和stderr

  • 当某个pod的内存变得很大

  • 触发了我们的alert

  • 这个时候管理员

  • 去页面查询确认是哪个pod有问题

  • 然后要确认pod内存变大的原因

  • 我们还需要去查询pod的日志

  • 如果没有日志系统

  • 那么我们就需要到页面或者使用命令进行查询了

  • 如果这个时候应用挂掉了 那么就没有办法再查询到相关日志了

解决该需求可供选择的方案

ELK

优势:

  1. 功能丰富,允许复杂的操作

劣势:

  1. 主流的ELK(全文检索)或者EFK比较重

  2. ES复杂的搜索功能很多都用不上 规模复杂,资源占用高,操作苦难大多数查询只关注一定时间范围和一些简单的参数(如host、service等)

  3. Kibana和Grafana之间切换,影响用户体验

  4. 倒排索引的切分和共享的成本较高

Loki

  1. 最小化度量和日志的切换成本有助于减少异常事件的响应时间和提高用户的体验

  2. 在查询语言的易操作性和复杂性之间可以达到一个权衡

  3. 更具成本效益

Loki与ELK的主要区别在于:

  1. Loki不会对原始的日志数据进行全文索引,而是采用了Prometheus的标签思想,只对标签索引

  2. 日志数据本身也会被压缩,并以chunks(块)的形式存储在对象存储或者本地文件系统

  3. Loki能够以微服务模式运行,也就是把自身的各个模块分解出单个进程运行。比如,通过横向扩展多个查询器(Querier)模块可提高查询性能。

这几点区别使Loki更加轻量和灵活,特别适合云原生环境。

今天的重头戏 Loki

loki组件介绍

  • Promtail

  1. 用来将容器日志发送到 Loki 或者 Grafana 服务上的日志收集工具

  2. 该工具主要包括发现采集目标以及给日志流添加上 Label 标签 然后发送给 Loki

  3. Promtail 的服务发现是基于 Prometheus 的服务发现机制实现的

  • Loki

  • 受 Prometheus 启发的可水平扩展、高可用以及支持多租户的日志聚合系统

  • 使用了和 Prometheus 相同的服务发现机制,将标签添加到日志流中而不是构建全文索引

  • 从 Promtail 接收到的日志和应用的 metrics 指标就具有相同的标签集
    不仅提供了更好的日志和指标之间的上下文切换,还避免了对日志进行全文索引

Grafana

  • 一个用于监控和可视化观测的开源平台

  • 支持非常丰富的数据源

  • 在 Loki 技术栈中它专门用来展示来自 Prometheus 和 Loki 等数据源的时间序列数据
    可进行查询、可视化、报警等操作

  • 可以用于创建、探索和共享数据 Dashboard

  • 鼓励数据驱动

loki 架构

数据处理过程

  • promtail收集日志并将其发送给loki

  • Distributor就是第一个接收日志的组件

  • Loki通过构建压缩数据块来实现批处理和压缩数据

在k8s中部署Loki日志系统

Helm安装

部署

  • 首先添加 Loki 的 Chart 仓库:

helm repo add grafana https://grafana.github.io/helm-charts
helm repo update
  • 获取 loki-stack 的 Chart 包并解压:

helm pull grafana/loki-stack --untar --version 2.9.10 #目前最新的
  • 编辑values文件,选择安装什么组件

    • 这边是安装一套loki-stack(loki+promtail+grafana)

    • 需要提前安装storage (我这边是nfs-storage )

test_pod:
  enabled: true
  image: bats/bats:1.8.2
  pullPolicy: IfNotPresent

loki:
  enabled: true
  isDefault: true
  persistence:
    enabled: true
    storageClassName: nfs-storage
    accessModes:
      - ReadWriteOnce
    size: 10Gi
  isDefault: true
  url: http://{{(include "loki.serviceName" .)}}:{{ .Values.loki.service.port }}
  readinessProbe:
    httpGet:
      path: /ready
      port: http-metrics
    initialDelaySeconds: 45
  livenessProbe:
    httpGet:
      path: /ready
      port: http-metrics
    initialDelaySeconds: 45
  datasource:
    jsonData: "{}"
    uid: ""


promtail:
  enabled: true
  config:
    logLevel: info
    serverPort: 3101
    clients:
      - url: http://{{ .Release.Name }}:3100/loki/api/v1/push

fluent-bit:
  enabled: false

grafana:
  enabled: true
  persistence:
    enabled: true
    storageClassName: nfs-storage
    accessModes:
      - ReadWriteOnce
    size: 10Gi
  sidecar:
    datasources:
      label: ""
      labelValue: ""
      enabled: true
      maxLines: 1000
  image:
    tag: 8.3.5

prometheus:
  enabled: false
  isDefault: false
  url: http://{{ include "prometheus.fullname" .}}:{{ .Values.prometheus.server.service.servicePort }}{{ .Values.prometheus.server.prefixURL }}
  datasource:
    jsonData: "{}"

filebeat:
  enabled: false
  filebeatConfig:
    filebeat.yml: |
      # logging.level: debug
      filebeat.inputs:
      - type: container
        paths:
          - /var/log/containers/*.log
        processors:
        - add_kubernetes_metadata:
            host: ${NODE_NAME}
            matchers:
            - logs_path:
                logs_path: "/var/log/containers/"
      output.logstash:
        hosts: ["logstash-loki:5044"]

logstash:
  enabled: false
  image: grafana/logstash-output-loki
  imageTag: 1.0.1
  filters:
    main: |-
      filter {
        if [kubernetes] {
          mutate {
            add_field => {
              "container_name" => "%{[kubernetes][container][name]}"
              "namespace" => "%{[kubernetes][namespace]}"
              "pod" => "%{[kubernetes][pod][name]}"
            }
            replace => { "host" => "%{[kubernetes][node][name]}"}
          }
        }
        mutate {
          remove_field => ["tags"]
        }
      }
  outputs:
    main: |-
      output {
        loki {
          url => "http://loki:3100/loki/api/v1/push"
          #username => "test"
          #password => "test"
        }
        # stdout { codec => rubydebug }
      }

# proxy is currently only used by loki test pod
# Note: If http_proxy/https_proxy are set, then no_proxy should include the
# loki service name, so that tests are able to communicate with the loki
# service.
proxy:
  http_proxy: ""
  https_proxy: ""
  no_proxy: ""

安装

[root]# kubectl create ns logging
[root]# helm upgrade --install loki -n logging -f values.yaml . 
Release "loki" does not exist. Installing it now.
NAME: loki
LAST DEPLOYED: Thu Jul 13 14:29:44 2023
NAMESPACE: logging
STATUS: deployed
REVISION: 1
NOTES:
The Loki stack has been deployed to your cluster. Loki can now be added as a datasource in Grafana.

See http://docs.grafana.org/features/datasources/loki/ for more detail.

查看

[k8s-01 14:40:16 /home/loki-stack]
[root]# kubectl get pod -n logging
NAME                           READY   STATUS    RESTARTS   AGE
loki-0                         1/1     Running   0          2m5s
loki-grafana-db7dc5cfb-8jw2x   2/2     Running   0          2m5s
loki-promtail-cz7lh            1/1     Running   0          2m5s
loki-promtail-ptwck            1/1     Running   0          2m5s
loki-promtail-r44dv            1/1     Running   0          2m5s

  • 这里我们为 Grafana 设置的 NodePort 类型的 Service:

[k8s-01 14:44:12 /home/loki-stack]
[root]# kubectl get svc -n logging
NAME              TYPE        CLUSTER-IP    EXTERNAL-IP   PORT(S)    AGE
loki              ClusterIP   10.96.1.241   <none>        3100/TCP   3m8s
loki-grafana      ClusterIP   10.96.1.48    <none>        80/TCP     3m8s
loki-headless     ClusterIP   None          <none>        3100/TCP   3m8s
loki-memberlist   ClusterIP   None          <none>        7946/TCP   3m8s

  • 把grafana的svc改成nodeport

kubectl patch svc loki-grafana -n logging -p '{"spec": {"type": "NodePort"}}'

可以通过 NodePort 端口 访问 Grafana,使用下面的命令获取 Grafana 的登录密码:

kubectl get secret --namespace logging loki-grafana -o jsonpath="{.data.admin-password}" | base64 --decode ; echo


我们使用 Helm 安装的 Promtail 默认已经帮我们做好了配置,已经针对 Kubernetes 做了优化.

效果

 

  • 21
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

之乎者也·

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值