Loki + Promtail 集中日志实战:给 VPS 全家桶容器装上一双排障的眼睛


服务器出问题时,最快的定位方式还是翻日志——但前提是你找得到日志在哪。十几台容器各自把 stdout 写到本机,真要排障就是一台台 docker logs 来回问,还跨不过历史的窗口。前面我们用 Prometheus 管好了"指标"(数值型状态),这轮用 Loki 补齐"日志"(文本型事件)这一半:统一采集、集中存储、一个表达式搜索全量日志。

一、Loki 和它的老对手:为什么"便宜"不是它唯一的优点

日志通常很大,所以 Elasticsearch/ELK 这类方案的习惯是把日志全文索引起来(费磁盘、费内存)。Loki 走了另一条路:它不去全文索引每条日志,只索引日志的"元数据标签"(label),正文只在查询时临时扫描。这带来两个直接结果:存储占用小一两个量级、单机就能日常扛住;代价是"随机全文检索"不如 ES 快,但配合时间范围和标签收敛,日常排障完全够用。理解了这一点,你就明白为什么 Loki 主打"日志 + 指标同源""体量小",而不是"我要秒查任意一条日志"。

整套组件通常是:Promtail(在每台目标机上采集日志并打标签发上来)+ Loki(聚合存储)+ Grafana(查询与看板)。Promtail 天然对接 Docker 的 stdout/json 日志,装一台主机的 LogQL 就能看到它们的实时流。

二、用 Compose 把 Loki + Promtail 起起来

services:
  loki:
    image: grafana/loki:2.9.2
    volumes:
      - ./loki-config.yml:/etc/loki/local-config.yml:ro
      - loki_data:/loki
  promtail:
    image: grafana/promtail:2.9.2
    volumes:
      - /var/log:/var/log:ro
      - /var/lib/docker/containers:/var/lib/docker/containers:ro
    command: -config.file=/etc/promtail/config.yml
    volumes_from:
      - loki:ro   # 只是表示配置挂载,可换成宿主机 config
volumes:
  loki_data: {}

关键落在两个 config 上。Loki 侧的核心参数是存储位置与告警接收;Promtail 侧的文件是采集入口——它决定"读哪些文件、用什么标签、如何推送"。日志落盘到命名卷 loki_data 才能持久化,这也意味着它应纳入 restic 那套备份,别让"排障数据"自己先消失。

三、给日志打标签:决定"能不能查得快"

Loki 的性能关键是 label 选择。两个反例:把每条日志的 message 提成高基数的 label(会炸索引)、或全都不打 label 纯搜(查询慢)。正确的做法是只给"这个服务是谁、来自哪台机器、什么级别"这类低基数、语义稳定的维度打 label,把 "App=nginx"、"host=web1"、"level=error" 作为搜索入口;真正的内容留在条目正文里用 |= 过滤。这样查询时先按 label 快速收敛,再对收敛出的少量日志做内容匹配。

Promtail 通常依赖 Docker 容器标签自动生成 container_name 标签,等于每个容器的日志天然按名字分区。给不同应用的服务贴稳定的 label,能直接决定"我想看哪个服务"这条查询的成本。

四、LogQL:像查 PromQL 一样查日志

LogQL 的语法跟 PromQL 高度同源,好处是"会看指标的人,上手日志只要半小时"。最常用的就是标签选择器加内容过滤:{app=~"nginx|php"} |= "error" |~ "5\\d{2}",前面 {} 选定标签,后面 |=(包含)、|~(正则)、!~(排除)做正文过滤。更进一步它能对匹配到的日志做聚合运算(rate、count_over_time),把"错误出现的频率"直接算出来,和 Prometheus 的指标拉进同一张图。这条能力正是"日志和指标同源"的甜点:先看错误速率曲线,再点进那一段的原始日志,两步完成定位。

五、让"日志里有异常"变成告警而不是"等它挂"

日志最大的价值在主动预警:应用抛出的错误开始变多、某个 user-agent 在反复探测——这些往往发生在磁盘打满前。你可以照着 Prometheus 的规则格式,在 Loki 里写一个基于 LogQL 聚合的 alerting rule(例如"5 分钟内 5xx 日志条数超过 N 就触发"),再走 Alertmanager 分发到 Telegram/Webhook。这不是把 ES 的先进功能搬过来,而是把"排障翻日志"变成"被日志主动叫来"。设置阈值的原则跟指标一样:先用看板观察一周正常基线的量,再设成"接近但不出抢"的值。

六、体量与成本:别把单机玩成大数据集群

Loki 单机可以很轻,但别无限堆。控制日志体量的手段主要有:a) limit_config 限制单条日志最大字节数与最大 line 数;b) Promtail 的 pipeline_stages 用 drop 丢弃明显无用的日志(健康检查、debug 流水);c) 设好 retention(默认 21 天足够,可调)。记住磁盘终究有限,超前保留几十 GB 的历史不如把"有用与否"的判断做好。日志和指标一样要备份,别让排障数据成为单点故障。

结语

Loki + Promtail + Grafana 把"多台机器、十几容器的日志"收成"一个可搜索的时间线",且与上一轮的指标体系共用同一套标签和查询习惯,排障路径自然缩短:指标先报警 → 看板看趋势 → 顺着标签点进日志原文。它的取舍——不全文索引所有日志,而是在低基数标签上收敛——正好适合自托管规模,单机十余 TB 日志仍在可控范围。把日志当成一等公民,和指标、告警串成同一条可观测链路之后,你会发现自己处理线上问题的平均用时明显下降。


手机扫码阅读

微信或手机浏览器扫一扫,随时随地随心阅读与分享

Frp 内网穿透实战:一台公网 VPS 把内网服务安全地搬到互联网

Ollama 自托管本地大模型实战:模型部署、量化与 OpenAI 兼容 API 全解析

评 论
更换验证码