概述
服务器出了问题,第一件事就是翻日志。但翻日志这事儿很痛苦——dmesg、journalctl、/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 登录。
- 左侧菜单点 Connections → Data Sources → Add data source
- 搜索 Loki,点击添加
- URL 填
http://loki:3100 - 滚动到底部点 Save & Test,看到绿色提示就说明连接成功
第六步:开始查日志
回到 Grafana 主页,点左侧 Explore,数据源选 Loki,你就能用 LogQL 语法查日志了。
常用查询示例:
# 查所有容器日志
{job="containerlogs"}
# 查特定容器的日志(替换为你的容器名)
{job="containerlogs", container_name="nginx"}
# 查包含 error 关键字的日志
{job="syslogs"} |= "error"
# 最近一分钟的错误日志
{job="containerlogs"} |= "error" | line_format "{{.log}}"
验证
验证搭建成功的方法很简单:
- 往某个容器打几条日志:
docker exec -it nginx echo "test log entry" - 在 Grafana Explore 里搜
{job="containerlogs"} - 能看到刚才那条 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,你会发现监控盲区少了一大半。