Logs 可观测性 | Grafana Loki 架构窥探与实践

247 阅读10分钟

相关阅读:

可观测性 | Grafana Loki 日志聚合方案快速体验

前言

在相关阅读中,通过快速部署示例项目,体验通过 Grafana WebUI 查询日志。本文介绍 Loki 栈的配置实现,适用于可观测能力建设的开发人员。

日志聚合系统架构

一个最基本的日志聚合系统通常包含以下四个核心模块:

  1. 日志生成模块,产生日志数据的源头,通常是应用程序、服务器、网络设备等,如 Web 服务器(如 Nginx、Apache)生成的访问日志和错误日志,应用程序(如 Java 应用、Python 应用)通过日志库(如 Log4j、Python 的 logging 模块)生成的日志。

  2. 日志收集模块,负责从日志生成源中收集日志数据,并且能够处理日志的格式化和初步解析,如 Fluentd、Filebeat、Promtail、Logstash 等。

  3. 日志存储模块,用于存储收集到的日志数据,支持高效查询和长期保留,如 Loki、ElasticSearch。日志聚合系统的核心模块,决定了日志的存储效率、查询效率。

  4. 日志查询与可视化模块,提供用户界面,允许用户查询、分析和可视化日志数据,如 Grafana、Kibana。

以下是这四个模块的基本架构示意图,使用 Mermaid 语法表示:

graph TD
    A[日志生成模块] --> B[日志收集模块]
    B --> C[日志存储模块]
    D[日志查询与可视化模块] --> C

Loki 栈聚合 Nginx 日志

graph TD
    A["Nginx 服务<br>(日志生成模块)"] --> B["Promtail 服务<br>(日志收集模块)"]
    B --> C["Loki 服务<br>(日志存储模块)"]
    D["Grafana<br>(日志查询与可视化模块)"] --> C

日志生成模块:Nginx 服务

Nginx 的日志能力主要包括:访问日志(Access Log)错误日志(Error Log) 两大类,开发和运维人员通常通过这些日志来监控服务器状态、排查问题、优化性能和分析用户行为。

Nginx 日志由配置文件 nginx.conf 定义,日志默认存储路径:

  • /var/log/nginx/access.log
  • /var/log/nginx/error.log

也可以在配置文件中显示定义:

server {
    // 忽略其他代码
    access_log  /var/log/nginx/access.log  main;
    error_log  /var/log/nginx/error.log  error;
}

access.log 示例:

172.19.0.1 - - [18/Jun/2025:14:55:11 +0000] "GET /api/core/video/slide HTTP/1.1" 404 53893 "http://localhost/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/137.0.0.0 Safari/537.36" "-"
172.19.0.1 - - [18/Jun/2025:14:55:11 +0000] "GET /api/core/collection/list HTTP/1.1" 404 53893 "http://localhost/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/137.0.0.0 Safari/537.36" "-"
172.19.0.1 - - [18/Jun/2025:14:55:12 +0000] "GET / HTTP/1.1" 304 0 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/137.0.0.0 Safari/537.36" "-"

在使用 Docker 启动 Nginx 容器时,容器内部的日志默认存储在其文件系统中,而容器的文件系统是隔离的,为了暴露给其他服务,需要挂载到宿主机。

因此,可以在docker-compose.yaml中设置配置文件:

我极力推荐任何情况下都使用 docker-compose.yaml 启动项目服务,即使是单容器

volumes:
  - ./volumes/logs:/var/log/nginx # 将 Nginx 容器的 /var/log/nginx目录挂在宿主机相对路径

日志采集模块:Promtail

日志采集工具如 Promtail 的主要任务是把服务器上的日志文件内容收集起来,然后发送给日志存储模块如 Loki。可以把它想象成一个“日志搬运工”,它把日志从一个地方(服务器上的文件)搬到另一个地方(Loki)。

从开发人员的角度来看,日志采集工具 Promtail 的工作包括 找到日志文件解析日志文件发送日志文件 这三个部分。

采集 Nginx 日志的 Promtail 配置文件:

server:
  http_listen_port: 9080
  grpc_listen_port: 0

positions:
  filename: /tmp/positions.yaml

clients: # 发送日志文件到 Loki 服务
  - url: http://loki-front:3100/loki/api/v1/push

scrape_configs:
  - job_name: 'magic-nginx'
    static_configs:
      - targets: # 找到日志文件
          - localhost
        labels:
          job: nginx-access
          __path__: /var/log/access.log
      - targets:
          - localhost
        labels:
          job: nginx-error
          __path__: /var/log/error.log

    pipeline_stages: # 解析日志文件
      # 处理访问日志
      - match:
          selector: '{job="nginx-access"}'
          stages:
            - regex:
                expression: '(?P<remote_addr>\S+) \S+ \S+ [(?P<time_local>[^]]+)] "(?P<request>[^"]+)" (?P<status>\d+) (?P<body_bytes_sent>\d+) "(?P<http_referer>[^"]*)" "(?P<http_user_agent>[^"]*)"'
            - timestamp:
                source: time_local
                format: "02/Jan/2006:15:04:05 -0700"
            - labels: # 为日志项添加 label 标签
                remote_addr:
                status:
                http_user_agent:
      # 处理错误日志
      - match:
          selector: '{job="nginx-error"}'
          stages:
            - regex:
                expression: '[(?P<time_local>[^]]+)] (?P<level>\w+): (?P<message>.+)'
            - timestamp:
                source: time_local
                format: "YYYY/MM/DD HH:mm:ss"
            - labels:
                level:

上述配置文件中需要关注的是,容器间文件系统相互独立,宿主机承担了文件共享的桥梁。

需要将宿主机上的 Nginx 日志挂载到 Promtail 容器内。

- targets:
  - localhost # Promtail 容器的 localhost
  labels:
    job: nginx-access
    __path__: /var/log/access.log

docker-compose.yaml 中挂载

promtail-front:
  image: grafana/promtail:3.4
  volumes:
    # 设置目录挂载
    - ./volumes/logs:/var/log # 挂载宿主机上的的日志到 promtail 容器

容器间是否可以直接访问呢?即 Nginx 容器和 Promtail 共享磁盘空间。

答案是否定的。

在 Docker 网络设计理念中,同一网桥(bridge)下的容器服务在网络上互相联通,其核心实现原理基于 Linux 的虚拟网桥(bridge)和虚拟以太网对(veth pair)技术。

对开发者来说,可以通过服务名(service-name)进行网络通信,但是磁盘空间是隔离的。

我的验证:将 promtail 配置文件中 targets 变更为 nginx 容器服务名,无法正常使用

static_configs:
  - targets:
      - front-nginx # 1. nginx 服务名称 
    labels:
      job: nginx-access
      __path__: /var/log/nginx/access.log # 2.1 nginx 服务内的访问日志位置
  - targets:
      - front-nginx
    labels:
      job: nginx-error
      __path__: /var/log/nginx/error.log # 2.2  nginx 服务内的错误日志位置

日志存储模块:Loki

日志存储模块主要承担 2 个功能:Log Server 和 Log Storage,即为日志服务器和日志存储。

Loki-Architecture-Components:

loki_architecture_components.svg

Loki 的架构设计使其可以高效地处理大规模日志数据,同时保持较低的资源消耗。

Log Server,Loki 的核心组件,负责接收来自 Alloy、Promtail 等代理的日志数据,并将其存储到后端存储系统中。Log Server 包含多个微服务组件,如 Distributor、Ingester、Query Frontend 和 Querier。

Log Storage,Loki 的存储后端,用于存储压缩的日志块(chunks)和索引(index)。 支持多种存储后端,包括本地文件系统、AWS S3、Google Cloud Storage 等。Loki 仅索引日志的元数据(标签),而不是日志内容本身,这大大减少了存储空间和查询时间。

最简单地,使用单体模式部署,本地磁盘存储。

生产环境中,推荐微服务(组件化)部署,S3 对象存储。

创建 loki/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: tsdb
      object_store: filesystem
      schema: v13
      index:
        prefix: index_
        period: 24h

storage_config:
  filesystem: # 文件系统,本地磁盘
    directory: /tmp/loki/chunks

启动 Loki 服务时,设置配置文件,容器内配置文件为 /etc/loki/config.yaml

volumes:
  - ./loki/config.yaml:/etc/loki/config.yaml:ro
command:
  - "--config.file=/etc/loki/config.yaml"

日志查询模块:Grafana

Grafana 最初与 Prometheus 协同工作,迅速在系统监控领域崭露头角,并逐渐成为事实上的标准。现在,Grafana 在可观测性上全面出击,其中就包括日志服务。

Grafana 是一个开箱即用的 WebUI 服务,只需要2步即可检索日志:

  1. 配置数据源 DataSource
  2. 基于标签 Label 和日志查询语言 LogQL 检索

配置数据源

方式一:手动在 Grafana WebUI 的 Data sources 选项中配置。

image.png

增加日志源 Loki,可以看到 Grafana 对数据源的支持非常广泛。

DataSources.png

方式二(推荐):使用配置文件定义数据源 Grafana Provisioning,优势是可跟随 Git 版本管理提交,易于迁移。

Grafana Provisioning 支持配置数据源 Data sources 和 仪表盘 Dashboards。

创建配置文件 loki-datasource.yaml

apiVersion: 1
datasources:
  - name: loki
    type: loki  # 数据源类型
    access: proxy
    origId: 1
    url: http://loki-service:3100 # Loki Server 地址,同一 bridge 下使用服务名访问 
    basicAuth: false
    version: 1
    editable: false

在 Grafana 启动时,将其作为 provisioning 配置文件挂载到容器中

# Grafana
# 默认端口 3000
grafana-service:
  image: grafana/grafana:11.3.2-ubuntu
  volumes:
    # 挂载 provisioning 数据源配置
    - ./grafana/provisioning/etc/datasources:/etc/grafana/provisioning/datasources:ro
  environment:
    TZ: Asia/Shanghai # 中国时区
    # 匿名登陆
    GF_AUTH_ANONYMOUS_ENABLED: true 
    GF_AUTH_ANONYMOUS_ORG_ROLE: Admin
    GF_USERS_ALLOW_SIGN_UP: false

将以上配置提交到代码仓库,可以很方便地实现配置迁移,避免繁琐的手动配置过程,且对于使用者来说可以忽略不相关步骤。

日志检索 Explore | Drilldown

在 Grafana 的 Web UI 中,Explore 是一个强大的交互式界面,用于实时探索和分析数据。它提供了快速查询、可视化和调试数据的功能,支持多种数据源,包括 Prometheus 和 Loki。

在 Prometheus 系统监控中,Explore 主要承担调试和临时分析的作用,监控仪表盘在 Dashboards 中构建,并供展示。

在 Loki 日志服务中,Explore 主要作为日志查询的入口,用于故障诊断和日志分析等。

Grafana 家族的产品都是用标签 label 来汇聚数据条目,同时支持时间范围界定。

grafana-label.png

不同的是,Prometheus 基于 PromQL 查询语言,Loki 基于 LogQL 查询语言。

除了最基本地基于时间、标签索引聚合日志,也支持模糊查询,并使用逻辑与、或、非等表达式来过滤。

在 Loki 日志服务中,Drilldown 是 Grafana 提供的一种功能,全称为 Grafana Logs Drilldown。它提供一种无查询(queryless)体验,允许用户在不编写复杂 LogQL 查询的情况下浏览和分析 Loki 日志。

Drilldown 与 Explore 对比

特性Grafana Logs DrilldownGrafana Explore
查询方式无需手动编写 LogQL 查询,自动可视化需要用户输入 LogQL 查询语句
功能定位简化日志浏览和分析,适合初学者提供更灵活的查询和分析工具,适合高级用户
适用场景快速定位和分析日志,无需深入了解 LogQL开发监控仪表板、告警规则,验证查询语句
可视化能力自动生成可视化图表支持多种视图(日志流、表格、图表等)
灵活性功能较为固定,适合快速分析功能丰富,支持复杂查询和自定义视图

总的来说,Grafana Logs Drilldown 专注于简化日志分析过程,通过自动化的可视化和过滤功能,让用户无需编写复杂查询即可快速获取日志洞察,特别适合初学者或需要快速分析的场景。

后续将对 Drilldown 功能做专门的介绍,在此文中不做过多描述。

总结

一个完整的日志聚合系统(日志服务)通常包含以下四大核心模块:日志生成模块、日志采集模块、日志存储模块以及日志查询模块。本文对每个模块作了简要介绍和功能概述。

通过构建一个入门级别的 Loki-Nginx 项目,描述了其核心配置的实现过程,帮助读者从架构层面理解 Loki 日志服务的工作原理和设计思路。

在后续的篇章中,我们将从业务需求的角度出发,深入探讨每个模块的配置和实现细节。我们希望通过这些内容,能够更全面地理解 Grafana Loki 日志服务的构建过程,并掌握如何针对实际业务场景进行优化和扩展。

关注微信公众号,获取运维资讯

如果此篇文章对你有所帮助,感谢你的点赞收藏,也欢迎在评论区友好交流。

微信搜索关注公众号:持续运维

参考

  1. Grafana Logs Drilldown, grafana.com/docs/grafan…
  2. Grafana 官方网站, grafana.com/