Docker 生产环境日志收集方案 ELK 还是 Loki 对比

文章导读
对于大多数 Docker 生产环境,如果主要目的是故障排查和基础监控,优先推荐 Loki;如果需要复杂的全文检索、数据分析或已有 Elastic 架构,则选择 ELK。
📋 目录
  1. 核心架构与部署示例
  2. 采集配置关键点
  3. 查询语言实战对比
  4. 资源限制与运维保障
  5. 验证与排查
  6. 生产环境常见风险
A A

对于大多数 Docker 生产环境,如果主要目的是故障排查和基础监控,优先推荐 Loki;如果需要复杂的全文检索、数据分析或已有 Elastic 架构,则选择 ELK。

先说结论:资源敏感选 Loki,分析深度选 ELK,不要盲目跟风。

  • 适合:Loki 适合云原生、K8s/Docker swarm 及资源受限场景;ELK 适合需要复杂聚合分析的企业级场景。
  • 重点看:索引机制差异,Loki 只索引标签导致存储更低,ELK 全文索引导致查询更强但资源消耗大。
  • 别忽略:查询语言学习成本(LogQL vs Lucene)以及长期存储的磁盘规划。

核心架构与部署示例

选型阶段不需要立刻部署,先通过架构草图评估复杂度。Loki 通常配合 Promtail 和 Grafana,ELK 通常需要 Filebeat、Logstash(可选)、Elasticsearch 和 Kibana。以下是基于 Docker Compose 的最小化生产部署参考。

前提条件:确保 Docker 守护进程配置为默认 json-file 日志驱动,否则 /var/lib/docker/containers 路径无效。若使用 journald 则需通过 systemd 采集,本文示例基于 json-file。

# Loki 栈 docker-compose.yml 示例
version: '3.8'
services:
  loki:
    image: grafana/loki:2.9.0
    ports:
      - "3100:3100"
    command: -config.file=/etc/loki/local-config.yaml
    volumes:
      - ./loki-config:/etc/loki
      - loki-data:/loki
    deploy:
      resources:
        limits:
          memory: 1G

  promtail:
    image: grafana/promtail:2.9.0
    volumes:
      - /var/lib/docker/containers:/var/lib/docker/containers:ro
      - /var/run/docker.sock:/var/run/docker.sock
      - ./promtail-config:/etc/promtail
    command: -config.file=/etc/promtail/config.yaml
    user: root  # 读取宿主机日志目录通常需要 root 权限

  grafana:
    image: grafana/grafana:10.0.0
    ports:
      - "3000:3000"
    volumes:
      - grafana-data:/var/lib/grafana

volumes:
  loki-data:
  grafana-data:

# ELK 栈 docker-compose.yml 示例 (简化版)
version: '3.8'
services:
  elasticsearch:
    image: docker.elastic.co/elasticsearch/elasticsearch:8.9.0
    environment:
      - discovery.type=single-node
      - ES_JAVA_OPTS=-Xms1g -Xmx1g  # 生产环境需根据内存调整
    volumes:
      - es-data:/usr/share/elasticsearch/data
    deploy:
      resources:
        limits:
          memory: 2G  # ES 建议至少 2GB 起步

  filebeat:
    image: docker.elastic.co/beats/filebeat:8.9.0
    user: root
    volumes:
      - /var/lib/docker/containers:/var/lib/docker/containers:ro
      - /var/run/docker.sock:/var/run/docker.sock:ro
      - ./filebeat.yml:/usr/share/filebeat/filebeat.yml:ro

  kibana:
    image: docker.elastic.co/kibana/kibana:8.9.0
    ports:
      - "5601:5601"
    environment:
      - ELASTICSEARCH_HOSTS=http://elasticsearch:9200

volumes:
  es-data:

采集配置关键点

日志采集配置直接决定数据质量。注意挂载宿主机日志目录时,若开启 Docker 用户命名空间重映射(userns-remap),可能需要调整权限或使用特权模式。

Docker 生产环境日志收集方案 ELK 还是 Loki 对比

Promtail 配置片段 (config.yaml):

scrape_configs:
  - job_name: containers
    static_configs:
      - targets:
          - localhost
        labels:
          job: varlogs
          __path__: /var/lib/docker/containers/*/*-json.log
    pipeline_stages:
      - json:
          expressions:
            output: log
            stream: stream
            attrs:
      - labels:
          stream:
      - output:
          source: output

Filebeat 配置片段 (filebeat.yml):

filebeat.inputs:
  - type: container
    paths:
      - /var/lib/docker/containers/*/*.log
    processors:
      - add_docker_metadata:
          host: "unix:///var/run/docker.sock"
output.elasticsearch:
  hosts: ["http://elasticsearch:9200"]

日志轮转配置:避免单个日志文件过大影响采集性能,建议在宿主机配置 /etc/logrotate.d/docker-containers

/var/lib/docker/containers/*/*.log {
    rotate 7
    daily
    compress
    size=100M
    missingok
    delaycompress
    copytruncate
}

查询语言实战对比

查询效率直接影响排查速度。Loki 使用 LogQL,ELK 使用 KQL (Kibana Query Language) 或 Lucene。

场景:查找过去 5 分钟内包含 "ERROR" 且容器名为 "api-server" 的日志。

Docker 生产环境日志收集方案 ELK 还是 Loki 对比
  • Loki (LogQL):{container_name="api-server"} |= "ERROR"
  • ELK (KQL):container.name : "api-server" AND message : "ERROR"

场景:统计错误级别分布。

  • Loki: 支持聚合但性能受限于标签基数,复杂聚合不如 ELK。
  • ELK: GET /_search { "aggs": { "levels": { "terms": { "field": "log.level" } } } } 原生支持高效聚合。

资源限制与运维保障

生产环境必须设置资源限制,防止日志组件耗尽宿主机资源。

  • 内存配置:Elasticsearch 默认堆内存较大,需根据文档调整 JVM 配置;Loki 相对轻量,但仍需限制缓存大小以防 OOM。
  • 时间同步:确保所有 Docker 宿主机和日志服务器开启 NTP 时间同步,否则日志顺序混乱会导致排查困难。
  • 磁盘告警:未配置保留策略(Retention Policy)的日志系统会无限占用磁盘。务必设置基于时间或大小的删除策略,并配置磁盘使用率告警(如超过 80% 触发)。

验证与排查

1. 连通性检查

在 Grafana 或 Kibana 界面添加数据源,执行简单查询。确认能看到最近 5 分钟内的容器日志。

Docker 生产环境日志收集方案 ELK 还是 Loki 对比
# 手动测试 Loki 接入
curl -G http://localhost:3100/loki/api/v1/query_range `--data-urlencode` 'query={job="varlogs"}' `--data-urlencode` 'start=$(date -d "5 minutes ago" +%s)000000000' `--data-urlencode` 'end=$(date +%s)000000000'

2. 资源监控

观察日志组件所在的容器资源使用率。在正常日志写入压力下,CPU 使用率应保持稳定,无持续飙升;内存使用不应触及限制值。

3. 日志完整性

故意在业务容器中输出一条带特定标识的测试日志,确认能在查询界面检索到,且时间戳误差在可接受范围内(通常秒级)。

生产环境常见风险

  • Loki 标签基数过高:不要将用户 ID、请求 ID 等高基数信息作为 Loki 的标签(Labels),这会导致索引爆炸。这些信息应放在日志内容中,通过查询语句过滤。
  • Elasticsearch 内存溢出:生产环境不要使用默认配置运行 Elasticsearch。需根据数据量调整堆内存,通常建议不超过 31GB,并关闭 swaps 以保证稳定性。
  • 权限不足:直接挂载宿主机目录可能需要特权模式或特定用户组权限,若遇到 Permission Denied,检查容器 user 配置或宿主机目录 ACL。