Loki 是 Grafana 体系里的日志聚合系统,设计思路和 Prometheus 很像,但处理对象是日志。它和传统全文检索型日志系统的最大区别是: 默认只索引标签(labels),不索引整条日志正文 ,所以存储成本通常更低,扩展性也更好,特别适合 Kubernetes、Docker、主机系统日志、应用日志统一汇聚场景。
截至 2026-04-16,Promtail 已经 EOL,新的采集端优先建议使用 Grafana Alloy ;另外,Loki 本身不内置认证层,生产环境应放在 Nginx 等反向代理或网关之后。
它的典型链路是:
日志源 → 采集器(Alloy)→ Loki → Grafana 查询与展示
其中:
- Loki 负责接收、压缩、存储、查询日志。
- Alloy 负责在主机或 K8s 节点上收集日志、打标签、做预处理,再推送到 Loki。
- Grafana 负责可视化、检索、告警。
Loki 核心架构逻辑上常见有这些组件:
- Distributor :接收写入请求
- Ingester :缓存并写入日志块
- Querier :执行查询
- Query Frontend :查询拆分与缓存
- Compactor :压缩、整理、保留策略
- Index / Storage :索引和日志对象存储
标签设计建议
Loki 的性能很大程度取决于标签设计,因此标签设计非常关键。
建议保留低基数标签 :
- job
- host
- env
- app
- namespace
- pod
- container
不要把高基数内容做成标签 :
- user_id
- request_id
- trace_id
- URL 全路径
- 错误详情
- SQL 文本
官方文档强调 labels 是 Loki 的核心组织方式,但标签过多、基数过高会带来性能和成本问题。
Docker Compose 部署示例
- Loki version 3.7.1
- alloy, version v1.15.1
docker-compose.yamlservices: loki: image: grafana/loki:latest command: - '-config.file=/etc/loki/config.yaml' ports: - "3100:3100" volumes: - "./config/loki/:/etc/loki/:ro" - "./data/loki/:/data/loki"
grafana: image: grafana/grafana ports: - "3000:3000" volumes: - "./config/grafana/:/etc/grafana/" - "./data/grafana/:/var/lib/grafana/"
alloy: image: grafana/alloy container_name: alloy restart: unless-stopped ports: - "12345:12345" command: - run - --server.http.listen-addr=0.0.0.0:12345 - --storage.path=/var/lib/alloy/data - /etc/alloy/config.alloy volumes: - ./config/alloy/:/etc/alloy/:ro - ./data/alloy/:/var/lib/alloy/data - /var/run/docker.sock:/var/run/docker.sock
|
主配置文件 /etc/loki/config.yaml 内容参考:
/etc/loki/config.yamlauth_enabled: false
server: http_listen_port: 3100
common: path_prefix: /loki replication_factor: 1 ring: kvstore: store: inmemory
schema_config: configs: - from: "2024-01-01" store: tsdb object_store: filesystem schema: v13 index: prefix: index_ period: 24h
storage_config: filesystem: directory: /loki/chunks
limits_config: allow_structured_metadata: true retention_period: 168h
compactor: working_directory: /loki/compactor retention_enabled: true delete_request_store: filesystem
|
Alloy 配置文件参考:
config/alloy/config.alloylogging { level = "info" format = "logfmt" }
discovery.docker "containers" { host = "unix:///var/run/docker.sock" }
discovery.relabel "docker_logs" { targets = discovery.docker.containers.targets
rule { source_labels = ["__meta_docker_container_name"] target_label = "container" regex = "/(.*)" replacement = "$1" }
rule { source_labels = ["__meta_docker_container_log_stream"] target_label = "stream" }
rule { source_labels = ["__meta_docker_container_label_com_docker_compose_service"] target_label = "service" } }
loki.source.docker "containers" { host = "unix:///var/run/docker.sock" targets = discovery.relabel.docker_logs.output forward_to = [loki.write.local.receiver] }
loki.write "local" { endpoint { url = "http://loki:3100/loki/api/v1/push" }
external_labels = { host = "prometheus-jumpserver", env = "prod", } }
|
启动成功后,在 Grafana 中添加新的 Data Source。即可在 Grafana 中查看到日志。
配置文件详解
Loki 配置文件
以下配置适用于单机、单副本、本地文件系统、保留 7 天数据的 Liki
/etc/loki/config.yamlauth_enabled: false
server: http_listen_port: 3100
common: path_prefix: /loki replication_factor: 1 ring: kvstore: store: inmemory
schema_config: configs: - from: "2024-01-01" store: tsdb object_store: filesystem schema: v13 index: prefix: index_ period: 24h
storage_config: filesystem: directory: /loki/chunks
limits_config: allow_structured_metadata: true retention_period: 168h
compactor: working_directory: /loki/compactor retention_enabled: true delete_request_store: filesystem
|
Alloy 配置文件详解
Alloy 配置文件本质上是在描述一条 数据流水线
- 发现目标 → 读取数据 → 处理/加标签 → 写到 Loki / Prometheus / OTLP 等后端
Alloy 的配置语法由两类基础元素组成:attributes(属性) 和 blocks(块) 。属性用 key = value 赋值,块用来定义组件实例和嵌套配置。
Alloy 官方把一些顶层块称为 configuration blocks ,它们用于配置 Alloy 进程本身,不是在采集业务日志或者输出日志。比如:
logging
tracing
http
livedebugging
import.*
Linux 下 Alloy 默认配置文件路径是 /etc/alloy/config.alloy
logging { # 配置 Alloy 自己的日志 level = "info" # Alloy 自己输出 info 级别日志 format = "logfmt" # 输出为 logfmt 格式 }
discovery.docker "containers" { # 发现 Docker 容器,discovery.docker 会把每个容器映射成 target。 host = "unix:///var/run/docker.sock" # 连接 Docker daemon、从 Docker 中发现容器目标、暴露出一组可供下游使用的 targets。要生效,你的容器通常要挂载 /var/run/docker.sock }
discovery.relabel "docker_logs" { # 重写或补充标签。把 Docker 自动发现到的元标签,转成在 Loki/Grafana 里更好用的业务标签。labels 是 Loki 的核心组织方式,必须谨慎设计,避免高基数标签。 targets = discovery.docker.containers.targets #
rule { source_labels = ["__meta_docker_container_name"] target_label = "container" regex = "/(.*)" replacement = "$1" }
rule { source_labels = ["__meta_docker_container_label_com_docker_compose_service"] target_label = "service" } }
loki.source.docker "containers" { # 读取 Docker 日志,这是日志采集核心。 host = "unix:///var/run/docker.sock" # 连接哪个 Docker daemon targets = discovery.docker.containers.targets # 从哪里拿目标列表,从 discovery.docker "containers" 获取目标容器列表 forward_to = [loki.write.local.receiver] # 日志下一步发给谁。把当前读到的日志,发给 loki.write "local" 这个组件的 receiver。 }
loki.write "local" { # 接收来自其他 Loki 组件的日志,把日志发到 Loki,这是输出端。 endpoint { # 定义目标 Loki 地址 url = "http://loki:3100/loki/api/v1/push" } external_labels = { # 给所有发出去的日志统一追加静态标签。 host = "prometheus-jumpserver", # 所有日志自动打上 host=prometheus-jumpserver,env=prod 标签 env = "prod", } }
|
可以把 Alloy 理解成 组件图 。比如上面的配置链路:
discovery.docker (用于 Docker 目标发现)去发现 Docker 容器
loki.source.docker 读取这些容器的日志,并转发给其他 loki.* 组件
loki.write 把日志发给 Loki,用于接收日志并通过 Loki logproto 发往远端 Loki
如果不是采集 Docker,而是采集文件日志,这时通常会用:
loki.source.file
local.file_match
loki.source.file "files" { file_match { path_targets = [ {"__path__" = "/var/log/*.log", "job" = "system"}, {"__path__" = "/var/log/nginx/*.log", "job" = "nginx"}, ] }
forward_to = [loki.write.local.receiver] }
|