Loki + Promtail 日志管理:VPS 上的轻量 ELK 替代品

概述

服务器出了问题,第一件事就是翻日志。但翻日志这事儿很痛苦——dmesgjournalctl/var/log/nginx/、Docker 容器的 stdout 散落在各处,找一条报错像大海捞针。

ELK 全家桶确实强大,但一套跑下来至少 2GB 内存,普通 VPS 扛不住。

Loki 是 Grafana 团队做的日志聚合系统,设计哲学就一个:不索引日志内容,只索引标签。省下的存储和计算资源,让它跑起来轻如燕。配合 Promtail 采集器,整套方案内存占用不到 200MB。

今天教你用 Docker Compose 在 VPS 上搭一套完整的 Loki + Promtail + Grafana 日志系统。


准备工作

你需要这些:

  • 一台 VPS(1核 2GB 起步,Loki 本身很省内存)
  • Docker 和 Docker Compose 已安装
  • 一个域名(可选,后面配 Nginx 反代会用到)

检查环境:

docker --version
docker compose version
df -h /  # 确保磁盘空间够,Loki 默认存 /loki/data

步骤

第一步:创建项目目录

mkdir -p ~/loki-stack && cd ~/loki-stack

第二步:编写 docker-compose.yml

创建一个 docker-compose.yml,包含三个服务:Loki、Promtail、Grafana。

services:
  loki:
    image: grafana/loki:3.0.0
    container_name: loki
    restart: unless-stopped
    ports:
      - "3100:3100"
    volumes:
      - ./loki:/loki
    command: -config.file=/etc/loki/local-config.yaml

  promtail:
    image: grafana/promtail:3.0.0
    container_name: promtail
    restart: unless-stopped
    volumes:
      - /var/lib/docker/containers:/var/lib/docker/containers:ro
      - /var/log:/var/log:ro
      - ~/.docker/compose:/root/.docker/compose:ro
    command: -config.file=/etc/promtail/config.yml

  grafana:
    image: grafana/grafana:11.1.0
    container_name: grafana
    restart: unless-stopped
    ports:
      - "3001:3000"
    volumes:
      - ./grafana:/var/lib/grafana
    environment:
      - GF_SECURITY_ADMIN_PASSWORD=admin123

这里做了三件事:

  • Loki 监听 3100 端口,数据存在 ./loki 目录
  • Promtail 挂载了 Docker 容器日志目录和系统 /var/log,以只读方式采集
  • Grafana 监听 3001 端口(避开本机 3000),初始密码设为 admin123

第三步:配置 Promtail 采集规则

创建 promtail-config.yml

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: docker
    static_configs:
      - targets:
          - localhost
        labels:
          job: containerlogs
          __path__: /var/lib/docker/containers/*/*

  - job_name: system
    static_configs:
      - targets:
          - localhost
        labels:
          job: syslogs
          __path__: /var/log/*.log

把这个配置挂载到 Promtail 容器中。修改 docker-compose.yml 中 promtail 部分:

  promtail:
    image: grafana/promtail:3.0.0
    container_name: promtail
    restart: unless-stopped
    volumes:
      - /var/lib/docker/containers:/var/lib/docker/containers:ro
      - /var/log:/var/log:ro
      - ./promtail-config.yml:/etc/promtail/config.yml:ro
    command: -config.file=/etc/promtail/config.yml

第四步:启动服务

docker compose up -d

等十几秒,检查容器状态:

docker compose ps

三个容器都应该处于 Running 状态。

第五步:配置 Grafana 数据源

浏览器打开 http://你的IP:3001,用 admin / admin123 登录。

  1. 左侧菜单点 Connections → Data Sources → Add data source
  2. 搜索 Loki,点击添加
  3. URL 填 http://loki:3100
  4. 滚动到底部点 Save & Test,看到绿色提示就说明连接成功

第六步:开始查日志

回到 Grafana 主页,点左侧 Explore,数据源选 Loki,你就能用 LogQL 语法查日志了。

常用查询示例:

# 查所有容器日志
{job="containerlogs"}

# 查特定容器的日志(替换为你的容器名)
{job="containerlogs", container_name="nginx"}

# 查包含 error 关键字的日志
{job="syslogs"} |= "error"

# 最近一分钟的错误日志
{job="containerlogs"} |= "error" | line_format "{{.log}}"

验证

验证搭建成功的方法很简单:

  1. 往某个容器打几条日志:docker exec -it nginx echo "test log entry"
  2. 在 Grafana Explore 里搜 {job="containerlogs"}
  3. 能看到刚才那条 test log entry,说明采集链路通了

再试一下系统日志:

echo "manual test" >> /var/log/syslog 2>/dev/null || echo "manual test" | tee -a /var/log/messages

在 Explore 里搜 {job="syslogs"} |= "manual test",能搜到就说明系统日志也在正常采集。


常见问题

Q1:Promtail 启动失败,报权限错误?

确保当前用户有读取 /var/lib/docker/containers 的权限。如果是 rootless Docker,路径可能不同,用 docker info 查看 Docker 根目录。

Q2:Loki 占磁盘越来越大怎么办?

Loki 自带生命周期管理。在 Loki 配置里加一段 retention 设置就行:

storage_config:
  tsdb_shipper:
    active_index_directory: /loki/boltdb-shipper-active
    cache_location: /loki/boltdb-shipper-cache
  boltdb_shipper:
    active_index_directory: /loki/boltdb-shipper-active
    cache_location: /loki/boltdb-shipper-cache
  fs:
    directory: /loki/chunks

limits_config:
  reject_old_samples: true
  reject_old_samples_max_age: 168h

这里设置了保留 7 天(168小时)的日志,自动清理旧数据。

Q3:外网能直接访问 Grafana 吗?

不建议。Grafana 默认没有强认证机制。如果你要暴露到公网,建议加一层 Nginx 反代并配 HTTP Basic Auth:

location /grafana/ {
    auth_basic "Restricted";
    auth_basic_user_file /etc/nginx/.htpasswd;
    proxy_pass http://127.0.0.1:3001/;
}

Q4:容器太多日志量太大,Loki 能扛住吗?

Loki 的设计就是压标签不压内容,单节点处理几百个容器的日志没问题。如果日日志量特别大(TB 级别),可以考虑上 S3 后端存储或者多副本集群,但那属于生产级部署了,个人 VPS 用单机版完全够用。


搭完这套,以后排查问题再也不用 ssh 上去翻文件了。Grafana 里搜一下关键字,几秒出结果。比 grep 高效十倍。

你的服务器上都跑着哪些服务?把这些服务的日志都接入 Loki,你会发现监控盲区少了一大半。

这篇文章对你有帮助吗?