Loki 中文教程
1. 项目概述
Loki 是一个开源的日志聚合系统,由 Grafana Labs 开发,专为云原生环境设计。它采用了与 Prometheus 类似的设计理念,提供了高效、可扩展的日志存储和查询解决方案。
主要功能
- 基于标签的日志索引:与 Prometheus 类似,使用标签进行日志索引和查询
- 高效存储:只索引元数据,原始日志数据压缩存储
- 与 Prometheus 和 Grafana 无缝集成
- 水平可扩展:支持分布式部署
- 多租户支持:适合大型组织和多团队环境
- 丰富的查询语言:支持 LogQL 进行复杂的日志查询和分析
- 支持多种数据源:通过 Promtail、Docker 驱动等采集日志
技术栈特点
- 用 Go 语言编写,性能优异
- 基于 Apache Cassandra 或 Amazon DynamoDB 存储索引
- 基于对象存储(如 S3、GCS)存储原始日志
- 与 Kubernetes 深度集成
适用环境
- 云原生环境日志管理
- 容器化应用日志聚合
- 微服务架构日志分析
- 大型分布式系统日志处理
2. 安装与配置
2.1 完整安装(Loki + Promtail + Grafana)
使用 Docker Compose 安装完整的 Loki 栈:
# docker-compose.yml
version: "3"
services:
loki:
image: grafana/loki:2.8.0
ports:
- "3100:3100"
volumes:
- ./loki-config.yaml:/etc/loki/local-config.yaml
command: -config.file=/etc/loki/local-config.yaml
promtail:
image: grafana/promtail:2.8.0
volumes:
- ./promtail-config.yaml:/etc/promtail/config.yml
- /var/log:/var/log
command: -config.file=/etc/promtail/config.yml
grafana:
image: grafana/grafana:9.1.0
ports:
- "3000:3000"
volumes:
- grafana-storage:/var/lib/grafana
volumes:
grafana-storage:2.2 Loki 配置
# loki-config.yaml
auth_enabled: false
server:
http_listen_port: 3100
ingester:
lifecycler:
address: 127.0.0.1
ring:
kvstore:
store: inmemory
replication_factor: 1
schema_config:
configs:
- from: 2020-10-24
store: boltdb-shipper
object_store: filesystem
schema: v11
index:
prefix: index_
period: 24h
storage_config:
boltdb_shipper:
active_index_directory: /tmp/loki/boltdb-shipper-active
cache_location: /tmp/loki/boltdb-shipper-cache
cache_ttl: 24h
shared_store: filesystem
filesystem:
directory: /tmp/loki/chunks
compactor:
working_directory: /tmp/loki/boltdb-shipper-compactor
shared_store: filesystem
limits_config:
reject_old_samples: true
reject_old_samples_max_age: 168h
chunk_store_config:
max_look_back_period: 0s
table_manager:
retention_deletes_enabled: false
retention_period: 0s2.3 Promtail 配置
# promtail-config.yaml
server:
http_listen_port: 9080
grpc_listen_port: 0
positions:
filename: /tmp/positions.yaml
clients:
- url: http://loki:3100/loki/api/v1/push
scrape_configs:
- job_name: system
static_configs:
- targets:
- localhost
labels:
job: varlogs
__path__: /var/log/*log
- job_name: docker
docker_sd_configs:
- host: unix:///var/run/docker.sock
refresh_interval: 5s
relabel_configs:
- source_labels: ['__meta_docker_container_name']
regex: '/(.*)'
target_label: 'container'
- source_labels: ['__meta_docker_container_log_stream']
target_label: 'stream'
- source_labels: ['__meta_docker_container_image']
target_label: 'image'2.4 Kubernetes 安装
使用 Helm 安装 Loki 栈:
helm repo add grafana https://grafana.github.io/helm-charts
helm repo update
helm install loki grafana/loki-stack --set grafana.enabled=true3. 基本使用
3.1 启动 Loki 栈
docker-compose up -d3.2 访问 Grafana
Loki 栈启动后,可以通过 http://localhost:3000 访问 Grafana Web UI。默认用户名和密码都是 admin。
3.3 添加 Loki 数据源
- 登录 Grafana Web UI
- 点击左侧菜单的 "配置" -> "数据源"
- 点击 "添加数据源"
- 选择 "Loki"
- 配置数据源 URL 为
http://loki:3100 - 点击 "保存并测试"
3.4 基本日志查询
在 Grafana 的 "Explore" 页面,选择 Loki 数据源,使用 LogQL 进行日志查询:
# 查询所有日志
{job="varlogs"}
# 按容器名称过滤日志
{container="nginx"}
# 搜索包含特定文本的日志
{job="varlogs"} |= "error"
# 搜索不包含特定文本的日志
{job="varlogs"} != "debug"
# 搜索正则匹配的日志
{job="varlogs"} =~ "[Ee]rror"
# 组合多个条件
{job="varlogs", host="localhost"} |= "error" != "debug"3.5 日志可视化
在 Grafana 中创建日志仪表盘:
- 点击左侧菜单的 "+" -> "创建仪表盘"
- 点击 "添加新面板"
- 选择 Loki 数据源
- 编写 LogQL 查询
- 选择 "日志" 可视化类型
- 配置面板选项
- 点击 "应用"
4. 高级特性
4.1 LogQL 高级查询
4.1.1 范围查询
# 查询过去5分钟的错误日志
{job="varlogs"} |= "error" |~ "[0-9]{3}" [5m]
# 查询过去1小时的日志,按时间聚合
sum(count_over_time({job="varlogs"} |= "error" [5m])) by (level) [1h]4.1.2 聚合函数
# 计算每分钟的错误数
sum(count_over_time({job="varlogs"} |= "error" [1m])) by (level)
# 计算日志行数的百分位数
topk(5, sum(count_over_time({job="varlogs"} [5m])) by (container))
# 计算日志大小的直方图
histogram_over_time(sum(bytes_over_time({job="varlogs"} [5m])) by (container), 1000, 0, 10000)4.1.3 提取字段
# 提取 HTTP 状态码并计算每个状态码的出现次数
sum(count_over_time(
{job="varlogs"} |= "HTTP"
| regexp `HTTP/1\.1\" (?P<status>\d{3})`
[5m]
)) by (status)4.2 多租户配置
# loki-config.yaml 中的多租户配置
auth_enabled: true
server:
http_listen_port: 3100
limits_config:
enforce_metric_name: false
reject_old_samples: true
reject_old_samples_max_age: 168h
per_stream_rate_limit: 3MB
per_stream_rate_limit_burst: 10MB
ingestion_rate_mb: 15
ingestion_burst_size_mb: 20
chunk_store_config:
max_look_back_period: 0s
ingester:
lifecycler:
ring:
kvstore:
store: inmemory
replication_factor: 1
schema_config:
configs:
- from: 2020-10-24
store: boltdb-shipper
object_store: filesystem
schema: v11
index:
prefix: index_
period: 24h
storage_config:
boltdb_shipper:
active_index_directory: /tmp/loki/boltdb-shipper-active
cache_location: /tmp/loki/boltdb-shipper-cache
cache_ttl: 24h
shared_store: filesystem
filesystem:
directory: /tmp/loki/chunks
compactor:
working_directory: /tmp/loki/boltdb-shipper-compactor
shared_store: filesystem
ruler:
storage:
type: local
local:
directory: /etc/loki/rules
rule_path: /tmp/loki/rules-temp
alertmanager_url: http://localhost:9093
ring:
kvstore:
store: inmemory
enable_api: true4.3 告警配置
在 Loki 中配置基于日志的告警:
# /etc/loki/rules/alerts.yaml
groups:
- name: example
rules:
- alert: HighErrorRate
expr: |
sum(count_over_time({job="varlogs"} |= "error" [5m])) by (job) > 10
for: 5m
labels:
severity: warning
annotations:
summary: "High error rate detected"
description: "Job {{ $labels.job }} has {{ $value }} errors in the last 5 minutes"4.4 性能优化
4.4.1 存储优化
# 存储优化配置
storage_config:
boltdb_shipper:
active_index_directory: /tmp/loki/boltdb-shipper-active
cache_location: /tmp/loki/boltdb-shipper-cache
cache_ttl: 24h
shared_store: s3
aws:
s3:
bucketnames: loki-logs
endpoint: s3.amazonaws.com
region: us-east-1
access_key_id: ${AWS_ACCESS_KEY_ID}
secret_access_key: ${AWS_SECRET_ACCESS_KEY}4.4.2 摄入优化
# 摄入优化配置
limits_config:
ingestion_rate_mb: 30
ingestion_burst_size_mb: 40
per_stream_rate_limit: 5MB
per_stream_rate_limit_burst: 15MB
ingester:
chunk_idle_period: 3m
max_chunk_age: 1h
chunk_target_size: 1536000
chunk_retain_period: 1m
max_transfer_retries: 05. 最佳实践
5.1 标签设计
- 使用有意义的标签名称,遵循
namespace_subsystem格式 - 避免使用高基数标签(如用户 ID、会话 ID 等)
- 为所有日志流添加统一的基础标签(如环境、应用名称、版本等)
- 标签值应保持一致,避免大小写混用
5.2 日志格式
- 使用结构化日志格式(如 JSON),便于字段提取和分析
- 包含必要的上下文信息(如请求 ID、用户 ID、时间戳等)
- 统一日志级别格式(如 debug、info、warn、error)
- 避免在日志中包含敏感信息(如密码、API 密钥等)
5.3 采集配置
- 为不同类型的应用配置不同的采集作业
- 使用 relabel_configs 优化标签
- 配置适当的批处理大小和刷新间隔
- 监控 Promtail 的健康状态
5.4 查询优化
- 使用具体的标签过滤减少查询范围
- 避免使用
|=操作符在大量日志中搜索 - 使用时间范围限制减少查询数据量
- 对于频繁的查询,考虑使用 Loki 的查询缓存
5.5 存储管理
- 配置适当的保留策略
- 定期运行压缩以优化存储
- 监控存储使用情况
- 考虑使用对象存储服务降低存储成本
6. 实际应用场景
6.1 Kubernetes 集群日志管理
使用 Loki 管理 Kubernetes 集群日志:
配置 Promtail 采集 Kubernetes 日志:
# promtail-config.yaml
server:
http_listen_port: 9080
grpc_listen_port: 0
positions:
filename: /tmp/positions.yaml
clients:
- url: http://loki:3100/loki/api/v1/push
kubernetes_sd_configs:
- role: pod
relabel_configs:
- source_labels: [__meta_kubernetes_pod_namespace]
action: replace
target_label: namespace
- source_labels: [__meta_kubernetes_pod_name]
action: replace
target_label: pod
- source_labels: [__meta_kubernetes_container_name]
action: replace
target_label: container
- source_labels: [__meta_kubernetes_pod_label_app]
action: replace
target_label: app
- replacement: /var/log/pods/*$1/*.log
separator: /
source_labels: [__meta_kubernetes_pod_uid, __meta_kubernetes_container_name]
regex: ^([^/]+)/.*$ # 替换为 /var/log/pods/<pod_uid>/<container_name>/*.log
target_label: __path__查询 Kubernetes 日志:
# 查询特定命名空间的日志
{namespace="default"}
# 查询特定应用的日志
{app="nginx"}
# 查询特定容器的错误日志
{container="app"} |= "error"
# 统计每个应用的错误数
sum(count_over_time({namespace="default"} |= "error" [5m])) by (app)6.2 微服务架构日志分析
使用 Loki 分析微服务架构的日志:
结构化日志示例(JSON 格式):
{
"timestamp": "2023-06-01T12:00:00Z",
"level": "error",
"service": "user-service",
"version": "1.0.0",
"trace_id": "abc123",
"span_id": "def456",
"message": "Failed to fetch user data",
"error": "User not found",
"user_id": "12345",
"method": "GET",
"path": "/api/users/12345",
"status_code": 404,
"response_time": 150
}查询结构化日志:
# 解析 JSON 日志并提取字段
{service="user-service"} |= "error" | json
# 按错误类型统计
{service="user-service"} |= "error" | json | sum(count_over_time({service="user-service"} [5m])) by (error)
# 查找响应时间超过 500ms 的请求
{service="user-service"} | json | response_time > 500
# 跟踪特定请求的完整调用链
{trace_id="abc123"} | json | sort by timestamp6.3 安全事件监控
使用 Loki 监控安全事件:
查询安全相关日志:
# 查找认证失败事件
{service="auth-service"} |= "authentication failed"
# 查找越权访问事件
{service="api-gateway"} |= "unauthorized access"
# 查找异常登录位置
{service="auth-service"} |= "login" | json | country != "CN"
# 统计认证失败次数
sum(count_over_time({service="auth-service"} |= "authentication failed" [1h])) by (ip_address)7. 总结
Loki 是一个现代化、高效的日志聚合系统,特别适合云原生环境和容器化应用。它采用了与 Prometheus 类似的设计理念,通过标签索引和压缩存储,提供了高性能、低成本的日志管理解决方案。
关键优势
- 高效存储:只索引元数据,原始日志压缩存储
- 与 Grafana 无缝集成:提供丰富的可视化和分析能力
- 强大的查询语言:LogQL 支持复杂的日志查询和分析
- 水平可扩展:支持分布式部署,适合大型系统
- 多租户支持:适合大型组织和多团队环境
应用场景
- Kubernetes 集群日志管理
- 容器化应用日志聚合
- 微服务架构日志分析
- 安全事件监控
- 业务指标分析
Loki 与 Prometheus 和 Grafana 一起,构成了完整的可观测性解决方案,帮助您更好地理解系统状态,及时发现和解决问题。