日誌收集系統PLG(Promtail+Loki+Grafana)介紹及部署

怡安發表於2024-04-11

一、簡 介

Loki是受Prometheus啟發由Grafana Labs團隊開源的水平可擴充套件,高度可用的多租戶日誌聚合系統。 開發語言: Google Go。它的設計具有很高的成本效益,並且易於操作。使用標籤來作為索引,而不是對全文進行檢索,也就是說,你透過這些標籤既可以查詢日誌的內容也可以查詢到監控的資料籤,極大地降低了日誌索引的儲存。系統架構十分簡單,由以下3個部分組成 :

Promtail 是代理,負責收集日誌並將其傳送給 loki 。

Loki 是主伺服器,負責儲存日誌和處理查詢 。

Grafana 用於 UI 展示。

只要在應用程式伺服器上安裝promtail來收集日誌然後傳送給Loki儲存,就可以在Grafana UI介面透過新增Loki為資料來源進行日誌查詢(如果Loki伺服器效能不夠,可以部署多個Loki進行儲存及查詢)。作為一個日誌系統不光只有查詢分析日誌的能力,還能對日誌進行監控和報警。

二、原理分析

promtail收集並將日誌傳送給loki的 Distributor 元件 Distributor會對接收到的日誌流進行正確性校驗,並將驗證後的日誌分批並行傳送到Ingester Ingester 接受日誌流並構建資料塊,壓縮後存放到所連線的儲存後端 Querier 收到HTTP查詢請求,並將請求傳送至Ingester 用以獲取記憶體資料 ,Ingester 收到請求後返回符合條件的資料 ; 如果 Ingester 沒有返回資料,Querier 會從後端儲存載入資料並遍歷去重執行查詢 ,透過HTTP返回查詢結果

三、對比

PLG與ELK比較優勢ELK雖然功能豐富,但規模複雜,資源佔用高,操作苦難,很多功能往往用不上,有點殺雞用牛刀的感覺。 Loki 不對日誌進行全文索引。透過儲存壓縮非結構化日誌和索引後設資料,Loki 操作起來會更簡單,更省成本。 透過使用與 Prometheus 相同的標籤記錄流對日誌進行索引和分組,這使得日誌的擴充套件和操作效率更高。 安裝部署簡單快速,且受 Grafana 原生支援。

四、下載

curl -O -L "https://github.com/grafana/loki/releases/download/v1.5.0/loki-linux-amd64.zip" 
curl -O -L "https://github.com/grafana/loki/releases/download/v1.5.0/promtail-linux-amd64.zip"
wget https://dl.grafana.com/enterprise/release/grafana-enterprise-8.3.3.linux-amd64.tar.gz

五、 安裝loki、grafana、promtail

安裝loki

先將loki-linux-amd64.zip和grafana-enterprise-8.3.3.linux-amd64.tar.gz上傳到日誌伺服器(10.60.134.55);再將promtail-linux-amd64.zip上傳到應用伺服器(10.60.134.60、10.60.134.48、10.60.134.56)。

在日誌伺服器 上建立目錄 /usr/local/logsCollect/loki用於安裝loki,建立目錄/usr/local/logsCollect/grafana用於安裝grafana,如下:

mkdir  /data/loki
mkdir  /data/loki/{chunks,index}

在日誌伺服器 上建立目錄,用於檔案儲存和索引儲存。

解壓unzip loki-linux-amd64.zip,並配置config.yaml

auth_enabled: false
server:
  http_listen_port: 8094
ingester:
  lifecycler:
    address: 10.60.134.55 #日誌伺服器ip,即本機地址
    ring:
      kvstore:
        store: inmemory
      replication_factor: 1
    final_sleep: 0s
  chunk_idle_period: 5m
  chunk_retain_period: 30s
schema_config:
  configs:
  - from: 2024-04-01
    store: boltdb
    object_store: filesystem
    schema: v11
    index:
      prefix: index_
      period: 168h   #每張表的時間範圍7天
storage_config:
  boltdb:
    directory: /data/loki/index   #索引檔案儲存地址
  filesystem:
    directory: /data/loki/chunks  #塊儲存地址
limits_config:
  enforce_metric_name: false
  reject_old_samples: true
  reject_old_samples_max_age: 168h
chunk_store_config:
# 最大可查詢歷史日期 7天,這個時間必須是schema_config中的period的倍數,否則報錯。
  max_look_back_period: 168h
# 表的保留期7天
table_manager:
  retention_deletes_enabled: true
  retention_period: 168h

並建立啟動指令碼start.sh和關閉指令碼shutdown.sh

#!/bin/bash
nohup ./loki-linux-amd64 -config.file=./config.yaml >./server.log 2>&1 &
echo "$!" > pid
#!/bin/bash
kill -9 `cat pid`
echo "關閉成功!"

啟動loki命令:sh start.sh。如下日誌表示啟動成功。

安裝 grafana

首先解壓grafana-enterprise-8.3.3.linux-amd64.tar.gz,建立啟動指令碼start.sh和關閉指令碼shutdown.sh。注意conf/defaults.ini為grafana的配置檔案,其中http_port為瀏覽器訪問埠。

啟動grafana命令:sh start.sh。如下日誌表示啟動成功。

在應用伺服器安裝 promtail

在應用伺服器 上建立目錄 /usr/local/logsCollect/promtail用於安裝promtail。

解壓promtail-linux-amd64.zip,並配置promtail.yaml

server:
  http_listen_port: 9080
  grpc_listen_port: 0

positions:
  filename: ./positions.yaml

clients:
  - url: http://10.60.134.55:8094/loki/api/v1/push #日誌伺服器loki地址和埠

scrape_configs:
#ucenter1
 - job_name: zcbackend-172.29.21.22-1
   static_configs:
   - targets:
       - 10.60.134.60
   - labels:
      job: zcbachend-172.29.21.22-1
      host: 10.60.134.60
      __path__: /jiuqi/zichan/zichanyitihuazhenghexiangmu-8084/backend/server.log  #本機日誌路徑

並建立啟動指令碼start.sh和關閉指令碼shutdown.sh

啟動promtail命令:sh start.sh。如下日誌表示啟動成功。

六、 測試

開啟grafana。預設密碼admin/admin。

新增資料來源

測試連線

查詢日誌

也能透過匯入的方式新增皮膚,json檔案如下:

日誌收集系統PLG(Promtail+Loki+Grafana)介紹及部署
{ 
  "annotations": {
    "list": [
      {
        "builtIn": 1,
        "datasource": {
          "type": "datasource",
          "uid": "grafana"
        },
        "enable": true,
        "hide": true,
        "iconColor": "rgba(0, 211, 255, 1)",
        "name": "Annotations & Alerts",
        "target": {
          "limit": 100,
          "matchAny": false,
          "tags": [],
          "type": "dashboard"
        },
        "type": "dashboard"
      }
    ]
  },
  "editable": true,
  "fiscalYearStartMonth": 0,
  "graphTooltip": 0,
  "id": 3,
  "iteration": 1671275851848,
  "links": [],
  "liveNow": false,
  "panels": [
    {
      "aliasColors": {},
      "bars": false,
      "dashLength": 10,
      "dashes": false,
      "datasource": {
        "type": "loki",
        "uid": "${ENV}"
      },
      "fill": 1,
      "fillGradient": 0,
      "gridPos": {
        "h": 5,
        "w": 24,
        "x": 0,
        "y": 0
      },
      "hiddenSeries": false,
      "id": 4,
      "legend": {
        "alignAsTable": true,
        "avg": false,
        "current": false,
        "max": false,
        "min": false,
        "rightSide": true,
        "show": true,
        "total": false,
        "values": false
      },
      "lines": true,
      "linewidth": 1,
      "nullPointMode": "null",
      "options": {
        "alertThreshold": true
      },
      "percentage": false,
      "pluginVersion": "8.5.10",
      "pointradius": 2,
      "points": false,
      "renderer": "flot",
      "seriesOverrides": [],
      "spaceLength": 10,
      "stack": false,
      "steppedLine": false,
      "targets": [
        {
          "datasource": {
            "type": "loki",
            "uid": "hJ7iGN-Sz"
          },
          "expr": "sum (count_over_time({filename=~\"$log\",host=~\"$host\"}[2m] )) by (host,filename)",
          "hide": false,
          "legendFormat": "{{host}}=={{filename}}",
          "refId": "B"
        }
      ],
      "thresholds": [],
      "timeRegions": [],
      "title": "日誌量統計",
      "tooltip": {
        "shared": true,
        "sort": 0,
        "value_type": "individual"
      },
      "type": "graph",
      "xaxis": {
        "mode": "time",
        "show": true,
        "values": []
      },
      "yaxes": [
        {
          "$$hashKey": "object:319",
          "format": "short",
          "logBase": 1,
          "show": true
        },
        {
          "$$hashKey": "object:320",
          "format": "short",
          "logBase": 1,
          "show": true
        }
      ],
      "yaxis": {
        "align": false
      }
    },
    {
      "datasource": {
        "type": "loki",
        "uid": "hJ7iGN-Sz"
      },
      "description": "",
      "gridPos": {
        "h": 21,
        "w": 24,
        "x": 0,
        "y": 5
      },
      "id": 2,
      "options": {
        "dedupStrategy": "exact",
        "enableLogDetails": false,
        "prettifyLogMessage": false,
        "showCommonLabels": false,
        "showLabels": false,
        "showTime": true,
        "sortOrder": "Descending",
        "wrapLogMessage": true
      },
      "pluginVersion": "7.4.3",
      "targets": [
        {
          "datasource": {
            "type": "loki",
            "uid": "hJ7iGN-Sz"
          },
          "expr": "{filename=~\"$log\",host=~\"$host\"}|~ \"(?i)$log_level\"",
          "hide": false,
          "maxLines": 500,
          "refId": "C"
        }
      ],
      "title": "日誌",
      "transparent": true,
      "type": "logs"
    }
  ],
  "refresh": "",
  "schemaVersion": 36,
  "style": "dark",
  "tags": [
    "PLG"
  ],
  "templating": {
    "list": [
      {
        "current": {
          "selected": false,
          "text": "Loki",
          "value": "Loki"
        },
        "hide": 0,
        "includeAll": false,
        "label": "選擇環境",
        "multi": false,
        "name": "ENV",
        "options": [],
        "query": "loki",
        "queryValue": "",
        "refresh": 1,
        "regex": "",
        "skipUrlSync": false,
        "type": "datasource"
      },
      {
        "current": {
          "selected": true,
          "text": "資產server",
          "value": "資產server"
        },
        "datasource": {
          "type": "loki",
          "uid": "hJ7iGN-Sz"
        },
        "definition": "label_values({},filename)",
        "hide": 0,
        "includeAll": false,
        "label": "日誌",
        "multi": false,
        "name": "log",
        "options": [
          {
            "selected": true,
            "text": "資產server-8084",
            "value": "/jiuqi/zichan/zichanyitihuazhenghexiangmu-8084/backend/server.log"
          },
          {
            "selected": true,
            "text": "資產server-8085",
            "value": "/jiuqi/zichan/zichanyitihuazhenghexiangmu-8085/backend/server.log"
          },
          {
            "selected": true,
            "text": "資產server-8086",
            "value": "/jiuqi/zichan/zichanyitihuazhenghexiangmu-8086/backend/server.log"
          },
          {
            "selected": true,
            "text": "公車server-8087",
            "value": "/jiuqi/gongche/yitihuagongchehouduan-8087/backend/server.log"
          },
          {
            "selected": true,
            "text": "公車server-8088",
            "value": "/jiuqi/gongche/yitihuagongchehouduan-8088/backend/server.log"
          }
          
         ],
        "query": "label_values({},filename)",
        "refresh": 1,
        "regex": "",
        "skipUrlSync": false,
        "sort": 1,
        "type": "query"
      },
      {
        "current": {
          "selected": true,
          "text": "172.29.21.22",
          "value": "10.60.134.60"
        },
        "datasource": {
          "type": "loki",
          "uid": "hJ7iGN-Sz"
        },
        "definition": "label_values({},host)",
        "hide": 0,
        "includeAll": false,
        "label": "主機IP",
        "multi": false,
        "name": "host",
        "options": [
         {
            "selected": true,
            "text": "資產-172.29.21.22",
            "value": "10.60.134.60"
          },
          {
            "selected": true,
            "text": "資產-172.29.21.164",
            "value": "10.60.134.48"
          },
          {
            "selected": true,
            "text": "公車-172.29.21.36",
            "value": "10.60.134.56"
          }
        ],
        "query": "label_values({},host)",
        "refresh": 1,
        "regex": "",
        "skipUrlSync": false,
        "sort": 1,
        "type": "query"
      },
      {
        "allValue": "(^\\\\S|^\\\\s)",
        "current": {
          "selected": false,
          "text": "All",
          "value": "$__all"
        },
        "description": "可以直接輸入搜尋的關鍵字進行過濾",
        "hide": 0,
        "includeAll": true,
        "label": "關鍵字過濾",
        "multi": false,
        "name": "log_level",
        "options": [
          {
            "selected": true,
            "text": "All",
            "value": "$__all"
          },
          {
            "selected": false,
            "text": "INFO",
            "value": "INFO"
          },
          {
            "selected": false,
            "text": "DEBUG",
            "value": "DEBUG"
          },
          {
            "selected": false,
            "text": "WARN",
            "value": "WARN"
          },
          {
            "selected": false,
            "text": "ERROR",
            "value": "ERROR"
          },
          {
            "selected": false,
            "text": "UNKNOWN",
            "value": "UNKNOWN"
          },
          {
            "selected": false,
            "text": "直接輸入關鍵字搜尋",
            "value": "直接輸入關鍵字搜尋"
          }
        ],
        "query": "INFO,DEBUG,WARN,ERROR,UNKNOWN,直接輸入關鍵字搜尋",
        "queryValue": "",
        "skipUrlSync": false,
        "type": "custom"
      }
    ]
  },
  "time": {
    "from": "now-1h",
    "to": "now"
  },
  "timepicker": {},
  "timezone": "",
  "title": "Loki日誌收集",
  "uid": "NlV_8QD7k",
  "version": 19,
  "weekStart": ""
}
logcollect.json

相關文章