二丫讲梵 二丫讲梵
首页
  • 最佳实践
  • 迎刃而解
  • Nginx
  • Php
  • Zabbix
  • AWS
  • Prometheus
  • Grafana
  • CentOS
  • Systemd
  • Docker
  • Rancher
  • Ansible
  • Ldap
  • Gitlab
  • GitHub
  • Etcd
  • Consul
  • RabbitMQ
  • Kafka
  • MySql
  • MongoDB
  • OpenVPN
  • KVM
  • VMware
  • Other
  • ELK
  • K8S
  • LLM
  • Nexus
  • Jenkins
  • 随写编年
  • 家人物语
  • 追忆青春
  • 父亲的朋友圈
  • 电影音乐
  • 效率工具
  • 博客相关
  • Shell
  • 前端实践
  • Vue学习笔记
  • Golang学习笔记
  • Golang编程技巧
  • 学习周刊
  • Obsidian插件周刊
关于
友链
  • 本站索引

    • 分类
    • 标签
    • 归档
  • 本站页面

    • 导航
    • 打赏
  • 我的工具

    • 备忘录清单 (opens new window)
    • json2go (opens new window)
    • gopher (opens new window)
    • 微信MD编辑 (opens new window)
    • 国内镜像 (opens new window)
    • 出口IP查询 (opens new window)
    • 代码高亮工具 (opens new window)
  • 外站页面

    • 开往 (opens new window)
    • ldapdoc (opens new window)
    • HowToStartOpenSource (opens new window)
    • vdoing-template (opens new window)
GitHub (opens new window)

二丫讲梵

行者常至,为者常成
首页
  • 最佳实践
  • 迎刃而解
  • Nginx
  • Php
  • Zabbix
  • AWS
  • Prometheus
  • Grafana
  • CentOS
  • Systemd
  • Docker
  • Rancher
  • Ansible
  • Ldap
  • Gitlab
  • GitHub
  • Etcd
  • Consul
  • RabbitMQ
  • Kafka
  • MySql
  • MongoDB
  • OpenVPN
  • KVM
  • VMware
  • Other
  • ELK
  • K8S
  • LLM
  • Nexus
  • Jenkins
  • 随写编年
  • 家人物语
  • 追忆青春
  • 父亲的朋友圈
  • 电影音乐
  • 效率工具
  • 博客相关
  • Shell
  • 前端实践
  • Vue学习笔记
  • Golang学习笔记
  • Golang编程技巧
  • 学习周刊
  • Obsidian插件周刊
关于
友链
  • 本站索引

    • 分类
    • 标签
    • 归档
  • 本站页面

    • 导航
    • 打赏
  • 我的工具

    • 备忘录清单 (opens new window)
    • json2go (opens new window)
    • gopher (opens new window)
    • 微信MD编辑 (opens new window)
    • 国内镜像 (opens new window)
    • 出口IP查询 (opens new window)
    • 代码高亮工具 (opens new window)
  • 外站页面

    • 开往 (opens new window)
    • ldapdoc (opens new window)
    • HowToStartOpenSource (opens new window)
    • vdoing-template (opens new window)
GitHub (opens new window)
  • 最佳实践

  • 迎刃而解

  • Nginx

  • Php

  • Zabbix

  • AWS

  • Prometheus

  • Grafana

  • Loki

    • 使用docker-compose部署最新版loki+promtail+grafana采集Nginx的日志流程记录
      • 前言
      • 部署
        • 日志格式化
        • 部署组件
      • 其他内容
        • 调试日志
        • 采集容器日志
  • CentOS

  • Supervisord

  • Systemd

  • Docker

  • Docker-Compose

  • Rancher

  • Ansible

  • OpenLdap

  • GitLab

  • GitHub

  • Etcd

  • Consul

  • RabbitMQ

  • Kafka

  • Mysql

  • MongoDB

  • OpenVPN

  • Kvm

  • VMware

  • 配置文件详解

  • Other

  • 运维观止
  • Loki
二丫讲梵
2023-05-14
目录

使用docker-compose部署最新版loki+promtail+grafana采集Nginx的日志流程记录

文章发布较早,内容可能过时,阅读注意甄别。

# 前言

在一些轻量化的场景之中,使用 ELK 方案来解决日志问题就会比较笨重,素闻 Loki 比较香,今天折腾了一番,特此记录一下整个流程。

本文不涉及 Loki 的深度使用与研究,但是参照本文,你可以快速把 Loki 拉起来,并且把 Nginx 日志正确采集进来。

# 部署

Loki 有三个组件,他们的功能简介如下:

  • Loki
    • 受 Prometheus 启发的可以水平扩展、高可用以及支持多租户的日志聚合系统
    • 使用了和 Prometheus 相同的服务发现机制,将标签添加到日志流中而不是构建全文索引
  • Promtail:用来将容器日志发送到 Loki 或者 Grafana 服务上的日志收集工具
  • Grafana:这个大家都比较熟悉了,在这里主要提供 Loki 数据的检索,绘图等。

# 日志格式化

配置部署之前,先将 Nginx 的访问日志配置为 JSON 化:

log_format json escape=json '{"remote_addr": "$remote_addr",'
                                 '"time": "$time_iso8601",'
                                 '"request_uri": "$request_uri",'
                                 '"verb": "$request_method",'
                                 '"httpversion": "$server_protocol",'
                                 '"response": "$status", '
                                 '"body_bytes_sent": "$body_bytes_sent", '
                                 '"referrer": "$http_referer", '
                                 '"user_agent": "$http_user_agent", '
                                 '"http_x_forwarded_for": "$http_x_forwarded_for", '
                                 '"server_name": "$host",'
                                 '"request_time": "$request_time",'
                                 '"upstream_response_time": "$upstream_response_time",'
                                 '"upstream_addr": "$upstream_addr",'
                                 '"realpath_root": "$realpath_root",'
                                 '"cookie": "$http_cookie",'
                                 '"nginx_version": "$nginx_version",'
                                 '"scheme": "$scheme"}';

    access_log /data/log/tmp.log json;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

# 部署组件

部署使用 docker-compose 一键拉起,配置文件的目录结构如下:

$ tree -N -L 2
.
├── config
│   ├── loki-config.yaml
│   └── promtail-config.yaml
└── docker-compose.yaml
1
2
3
4
5
6

三个配置文件分别如下。

docker-compose.yaml:

$cat docker-compose.yaml
version: '3.5'

networks:
  loki:

services:
  loki:
    image: docker.mirrors.sjtug.sjtu.edu.cn/grafana/loki:2.8.2
    container_name: loki
    restart: unless-stopped
    ports:
      - 3100:3100
    volumes:
      - ./config:/etc/loki/config
      - ./loki/index:/opt/loki/index
      - ./loki/chunks:/opt/loki/chunks
    user: "0"
    command: -config.file=/etc/loki/config/loki-config.yaml
    networks:
      - loki

  promtail:
    image: docker.mirrors.sjtug.sjtu.edu.cn/grafana/promtail:2.8.2
    container_name: promtail
    restart: unless-stopped
    volumes:
      - ./promtail/logs:/var/logs
      - ./config:/etc/promtail/config
      - /data/log:/logs
    user: "0"
    command: -config.file=/etc/promtail/config/promtail-config.yaml
    networks:
      - loki

  grafana:
    image: docker.mirrors.sjtug.sjtu.edu.cn/grafana/grafana:9.5.2
    container_name: grafana
    restart: unless-stopped
    ports:
      - 3000:3000
    volumes:
      - ./grafana:/var/lib/grafana
    user: "0"
    networks:
      - loki
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
36
37
38
39
40
41
42
43
44
45
46

需要注意配置 user 参数,否则会出现创建目录没有权限的错误。

loki-config.yaml:

$ cat config/loki-config.yaml
auth_enabled: false

server:
  http_listen_port: 3100
  grpc_listen_port: 3110
  grpc_server_max_recv_msg_size: 1073741824  #grpc最大接收消息值,默认4m
  grpc_server_max_send_msg_size: 1073741824  #grpc最大发送消息值,默认4m

ingester:
  lifecycler:
    address: 127.0.0.1
    ring:
      kvstore:
        store: inmemory
      replication_factor: 1
    final_sleep: 0s
  chunk_idle_period: 5m
  chunk_retain_period: 30s
  max_transfer_retries: 0
  max_chunk_age: 20m  #一个timeseries块在内存中的最大持续时间。如果timeseries运行的时间超过此时间,则当前块将刷新到存储并创建一个新块

schema_config:
  configs:
    - from: 2021-01-01
      store: boltdb
      object_store: filesystem
      schema: v11
      index:
        prefix: index_
        period: 168h

storage_config:
  boltdb:
    directory: /opt/loki/index #存储索引地址
  filesystem:
    directory: /opt/loki/chunks

limits_config:
  enforce_metric_name: false
  reject_old_samples: true
  reject_old_samples_max_age: 168h
  ingestion_rate_mb: 30  #修改每用户摄入速率限制,即每秒样本量,默认值为4M
  ingestion_burst_size_mb: 20  #修改每用户摄入速率限制,即每秒样本量,默认值为6M

chunk_store_config:
        #max_look_back_period: 168h   #回看日志行的最大时间,只适用于即时日志
  max_look_back_period: 0s

table_manager:
  retention_deletes_enabled: false #日志保留周期开关,默认为false
  retention_period: 0s  #日志保留周期
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
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52

这个配置文件没啥需要调整的,直接拷贝使用即可。

promtail-config.yaml:

$cat config/promtail-config.yaml
server:
  http_listen_port: 9081
  grpc_listen_port: 0

positions:
  filename: /tmp/positions.yaml

clients:
  - url: http://loki:3100/loki/api/v1/push

scrape_configs:
- job_name: access
  static_configs:
  - targets:
      - localhost
    labels:
      job: nginx-access-log
      __path__: /logs/tmp.log
  pipeline_stages:
  - match:
      selector: '{job="nginx-access-log"}'
      stages:
      - json:  # 日志为json格式 选择需要的字段
          expressions:
            remote_addr:
            request_uri:
            verb:
            httpversion:
            response:
            body_bytes_sent:
            referrer:
            user_agent:
            http_x_forwarded_for:
            server_name:
            request_time:
            upstream_response_time:
            upstream_addr:
            realpath_root:
            cookie:
            nginx_version:
            scheme:
            time:
      - labels:
            remote_addr:
            request_uri:
            verb:
            httpversion:
            response:
            body_bytes_sent:
            referrer:
            user_agent:
            http_x_forwarded_for:
            server_name:
            request_time:
            upstream_response_time:
            upstream_addr:
            realpath_root:
            cookie:
            nginx_version:
            scheme:
            time:
      - timestamp:
          format: '2006-01-02T15:04:05+08:00'
          source:  time
          location: Asia/Shanghai

- job_name: nginx-error
  static_configs:
  - targets:
      - localhost
    labels:
      job: nginx-error-log
      __path__: /logs/error.log
  pipeline_stages:
  - match:
      selector: '{job="nginx-error-log"}'
      stages:
      - regex:  # 使用正则选择要提取的字段
          expression: '^(?P<timestamp>\d{4}/\d{2}/\d{2} \d{2}:\d{2}:\d{2}) \[(?P<level>\S+)\] (?P<pid>\d+)#(?P<tid>\d+): \*(?P<cid>\d+) (?P<msg>.*) client: (?P<client_ip>[^,]+), server: (?P<server_name>[^,]+), request: "(?P<request_method>\S+) (?P<request_path>\S+) (?P<request_protocol>\S+)", upstream: "(?P<upstream>[^"]+)", host: "(?P<host>[^"]+)"$'
      - labels:
          level:
          pid:
          tid:
          cid:
          client_ip:
          server_name:
          request_method:
          request_path:
          request_protocol:
          upstream:
          host:
      - timestamp:
          format: "2006/01/02 15:04:05"
          source: time  # 正则提取的字段
          location: Asia/Shanghai
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
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96

这里主要有几个注意点,需要单独拎出来说明:

  • clients.url : 配置指向为容器名称进行连接。
  • __path__: /logs/tmp.log :此路径与 docker-compose 中挂载到容器内的日志路径对应,请注意。
  • expressions :这里配置要采集的字段。
  • labels :作为在 grafana 检索的字段 key。
  • timestamp.format : 是 go 语言风格的格式化方式,这个尤其需要注意。
  • 错误日志因为没有 json 化,因此通过正则拿到一些关键信息。

启动查看:

docker-compose up -d
1

启动之后,就可以在 grafana 中配置链接并查看日志了。

申明

原创文章eryajf,未经授权,严禁转载,侵权必究!此乃文中随机水印,敬请读者谅解。

Copyright 二丫讲梵 (opens new window) 版权所有

# 其他内容

# 调试日志

一开始配置了日志采集之后,发现一个问题,在 grafana 看到的日志时间,并不是日志中的时间,后来发现,原因出在 format 没有匹配成功。

一个简单的调试办法是,你可以取一条日志在一个文件内:

$ tail -n1 /data/log/tmp.log > tmp.log
1

下载 promtail 二进制,在这里 (opens new window)(有时候可能最新版本没有 promtail 二进制,可以往前翻一下版本)下载。

然后将配置文件也放置在同一目录,接着执行如下命令进行调试:

$ cat tmp.log | ./promtail --stdin -config.file promtail-config.yaml -log.level=debug -dry-run

Clients configured:
----------------------
url: http://loki:3100/loki/api/v1/push
batchwait: 1s
batchsize: 1048576
follow_redirects: false
enable_http2: false
backoff_config:
  min_period: 500ms
  max_period: 5m0s
  max_retries: 10
timeout: 10s
tenant_id: ""
drop_rate_limited_batches: false
stream_lag_labels: ""

2023-05-13T12:44:59+0800	{__path__="/logs/tmp.log", body_bytes_sent="12", cookie="grafana_session=5d279fee02d9b14e16562ba0444273b3; grafana_session_expiry=1684037372", http_x_forwarded_for="", httpversion="HTTP/1.1", job="nginx-access-log", nginx_version="1.19.9", realpath_root="/usr/local/openresty/nginx/html", referrer="", remote_addr="122.231.226.2", request_time="0.006", request_uri="/api/live/ws", response="400", scheme="https", server_name="grafana.eryajf.net", time="2023-05-13T12:44:59+08:00", upstream_addr="127.0.0.1:3000", upstream_response_time="0.006", user_agent="Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/113.0.0.0 Safari/537.36", verb="GET"}	{"remote_addr": "122.231.226.2","@timestamp": "2023-05-14T12:44:59+08:00","time": "2023-05-13T12:44:59+08:00","request_uri": "/api/live/ws","verb": "GET","httpversion": "HTTP/1.1","response": "400", "body_bytes_sent": "12", "referrer": "", "user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/113.0.0.0 Safari/537.36", "http_x_forwarded_for": "", "server_name": "grafana.eryajf.net","request_time": "0.006","upstream_response_time": "0.006","upstream_addr": "127.0.0.1:3000","realpath_root": "/usr/local/openresty/nginx/html","cookie": "grafana_session=5d279fee02d9b14e16562ba0444273b3; grafana_session_expiry=1684037372","nginx_version": "1.19.9","scheme": "https"}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

注意日志中的 time 字段是我故意改成 5 月 13 日,然后解析出来的时间,与这个字段的时间一致,说明匹配成功。

# 采集容器日志

Loki 官方提供了 docker 的插件,可以通过给 docker 安装 loki 插件,实现统一的采集,或者配置注入的方式进行单独采集。

安装插件:

$ docker plugin install docker.mirrors.sjtug.sjtu.edu.cn/grafana/loki-docker-driver:latest --alias loki --grant-all-permissions
1

安装完成之后,需要重启 docker:

$ systemctl restart docker
1

重启成功之后,运行新的容器时,增加如下指令,即可实现日志自动 push 到 Loki:

$ docker run -itd --name=test-nginx --log-driver=loki \
  --log-opt loki-url="http://10.0.0.17:3100/loki/api/v1/push" \
  --log-opt max-size=200m --log-opt max-file=10 \
   grafana/grafana
1
2
3
4

使用 docker-compose 的配置如下:

services:
  logger:
 image: grafana/grafana
 logging:
   driver: loki
   options:
     loki-url: "http://10.0.0.17:3100/loki/api/v1/push"
     max-size: "50m"
     max-file: "10"
1
2
3
4
5
6
7
8
9

这样就实现了采集单个容器的日志能力,在页面中,则是通过 container_name 进行区分检索。

如果想要实现全局的容器日志的采集,则可以通过在 docker 主配置文件中添加如下配置:

$ cat /etc/docker/daemon.json

{
    "log-driver": "loki",
    "log-opts": {
        "loki-url": "http://10.0.0.17:3100/loki/api/v1/push",
        "max-size": "50m",
        "max-file": "10"
    }
}
1
2
3
4
5
6
7
8
9
10

这样重启 docker 之后,所有 docker 容器的标准输出日志就会 push 给 Loki 了。

微信 支付宝
上次更新: 2024/09/26, 21:41:44
grafana绘图使用插件或表盘等资料收集整理
Linux好用命令之w命令

← grafana绘图使用插件或表盘等资料收集整理 Linux好用命令之w命令→

最近更新
01
学习周刊-总第212期-2025年第21周
05-22
02
从赵心童世锦赛夺冠聊聊我的斯诺克情缘
05-16
03
学习周刊-总第211期-2025年第20周
05-15
更多文章>
Theme by Vdoing | Copyright © 2017-2025 | 点击查看十年之约 | 浙ICP备18057030号
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式