ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Ubuntu 24.04 部署 Loki + Alloy + Grafana 轻量日志监控系统

Ubuntu 24.04 部署 Loki + Alloy + Grafana 轻量日志监控系统 不少朋友都在 Ubuntu 服务器上折腾过日志收集早期用 ELK 那套——Elasticsearch 吃内存实在太狠在一台 2G 内存的机器上既要跑 ES 又要跑 Kibana光是存活就已经拼尽全力了。后来 Grafana 生态里出了 Loki主打“低成本、轻量级、跟 Grafana 无缝集成”这套组合一下就吸引了我的注意。只是想用日志排查问题、做简单告警的话真没必要上 ES 全家桶Loki 的压缩存储和 LogQL 查询方式足够覆盖绝大多数场景。这篇就把我在 Ubuntu 24.04 上从零部署 Loki Alloy Grafana 的完整过程写出来含配置文件和踩坑记录可以直接照着抄。1. 项目概述为什么是 Loki Alloy Grafana1.1 这套系统能解决什么问题传统的日志排查最原始的办法就是 SSH 到服务器上tail -f /var/log/app.log单台机器还好说一旦服务变成多个实例、多个容器挨个登录看日志就完全行不通了。我们需要一个集中式的日志平台让所有机器、所有服务的日志都汇到一个地方再用统一的入口去检索和分析。ELK 确实是最经典的方案但它的痛点非常明显Elasticsearch 是 Java 写的默认堆内存就给你吃掉几个 G加上索引存储的副本机制磁盘和内存的压力都不小。对个人开发者、小团队、或者只是几台服务器的小规模场景来说ELK 属于典型的“杀鸡用牛刀”。Loki 的设计思路完全不一样它不建立全文索引而是只对日志的标签建立索引日志原文用压缩块存储。这个思路导致它查询速度和 ES 相比在某些复杂场景下慢一些但换来了极低的内存占用和运维成本。搭配 Grafana 做可视化从采集到展示的链路完整而且 Grafana 本身你大概率已经用它做监控了不用再额外学一套 Kibana 的操作习惯。这套组合最吸引我的一点是部署简单。不用搭 Kafka、不用调 JVM 参数一个 docker-compose 文件就能把三个服务全部拉起来。后续扩容也只是加个 Alloy 采集器的问题非常适合中小规模的基础设施。1.2 Alloy 和 Promtail 的关系为什么选 Alloy老玩家应该知道Loki 官方之前主推的采集器是 Promtail专门为 Loki 设计支持从文件、journald、syslog 等来源采集日志。但 Grafana Labs 后来推出了 Alloy一个统一的采集器目标是替代 Promtail同时还能采集 Prometheus 指标、OpenTelemetry 链路数据通吃 metrics、logs、traces 三类信号。我也用过 Promtail 一段时间它的配置其实挺清晰的但每次看到 Grafana 官方博客和文档都在推 Alloy就已经注定它会是未来的主方向。加上 Alloy 的配置语法用了 HCL和生态里的很多工具一致写起来比 Promtail 的 YAML 格式更灵活一些。这篇就按 Alloy 来写毕竟新项目应该直接上新的东西免得才搭好就要迁移。1.3 Ubuntu 24.04 下的部署方式选择部署这套系统的主流方案有两种一是直接用二进制文件跑二是用 Docker。Linux 上跑二进制还要处理 systemd 服务文件、数据目录权限等问题比较繁琐。Docker 方式一条命令解决依赖问题日志系统的所有组件都有官方镜像基本不需要考虑版本冲突。Ubuntu 24.04 的 Docker 安装也简单官方提供了 apt 源几步就能搞定。所以下面的流程全用 Docker。2. 核心设计思路与方案选型2.1 Loki 的存储机制为什么它这么省资源Loki 的存储分两块索引和块数据。索引默认存在本地文件系统单机模式块数据也默认存在本地文件系统。它把日志按照流stream来组织每个流由一组标签唯一定义比如{jobnginx, instanceweb-01}就是一条流。写入时日志先被压缩、切块再落盘查询时通过标签先过滤流再在流内做内容匹配。这种设计的直接好处是写入路径很轻。ES 写入的时候要做分词、建倒排索引CPU 消耗高Loki 写入基本就是追加压缩对 CPU 和内存的消耗小得多。代价是查询时如果标签过滤不当会扫很多数据所以要有点 LogQL 的使用技巧后面会细说。对应到实际体验同一台 2C4G 的服务器跑 ES 经常内存告警跑 Loki 单机模式却很从容差距非常明显。2.2 目录规划与资源规划部署之前先想清楚文件放哪里。我的建议是单独建一个/opt/loki-stack目录放所有配置文件和数据目录不跟项目代码混在一起也方便备份和迁移。Docker 的 volume 如果不好管理直接做目录挂载最直观。资源规划上单机版 Loki 的最低要求其实很低512M 内存就能跑起来但为了业务高峰期不被打爆建议至少给 Loki 分配 1G 内存。Alloy 比较轻量但它在高吞吐时也会占用不少 CPU建议至少 256M 内存。Grafana 同样很成熟256M 内存起步。整体下来一台 2C4G 的服务器跑这套系统加两三个业务容器资源是完全够用的。在做规划时可以粗略估算日志量每台机器每天产生 1-2GB 原始日志Loki 压缩后能降到十分之一左右所以这个部署方案的存储压力也不大。2.3 采集链路Alloy 如何抓到容器和系统日志Alloy 的日志采集流程可以简单理解成三个环节发现目标 → 读取日志 → 转发给 Loki。在 Docker 环境中每个容器的标准输出stdout/stderr其实都会被 Docker 接管以 JSON 文件形式存在宿主机的/var/lib/docker/containers/容器ID/目录里。Alloy 是通过 Docker 的 API 或者直接读取宿主机文件来发现和采集这些容器日志的。如果采集的是宿主机上的普通文件日志比如 Nginx 的 access.log那就直接指定路径就行。Alloy 会把日志内容按行读取然后按配置好的标签结构推送到 Loki 的 HTTP API 接口。这套链路中比较容易混淆的点是Alloy 不一定非要跑在容器里但它要能访问到日志文件。为了让 Alloy 容器能读到宿主机上的容器日志我们后面会把宿主机的/var/lib/docker/containers目录和/var/log目录挂载进 Alloy 容器里这也是采集容器日志的标准做法。3. 快速部署实战Ubuntu 24.04 Docker3.1 环境准备和基础配置我的环境是一台刚装好 Ubuntu 24.04 LTS 的服务器2C4GIP 是192.168.1.100这里用内网地址来示例。第一步当然是把系统更新到最新然后安装 Docker。# 更新系统软件包索引 sudo apt update sudo apt upgrade -y # 安装 Docker 依赖 sudo apt install -y ca-certificates curl gnupg lsb-release # 添加 Docker 官方 GPG 密钥 curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg # 添加 Docker 官方 apt 源注意 Ubuntu 24.04 的代号是 noble echo deb [arch$(dpkg --print-architecture) signed-by/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu noble stable | sudo tee /etc/apt/sources.list.d/docker.list /dev/null # 安装 Docker Engine sudo apt update sudo apt install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin注意Ubuntu 24.04 的代号是 noble之前网上很多教程写的是 jammy22.04直接抄的话 apt 会报错。我一开始就踩了这个坑后来检查/etc/os-release才反应过来。装完之后确认 Docker 能正常运行sudo systemctl enable --now docker sudo docker version docker compose version如果docker compose version能正常输出版本号说明 compose 插件已经装好了后面可以直接用docker compose命令。然后创建项目目录结构sudo mkdir -p /opt/loki-stack/{config,data/{loki,grafana}}这里的config目录放 Loki 和 Alloy 的配置文件data/loki和data/grafana分别是两个服务的数据持久化目录。一开始就把目录结构规划好后面排错会轻松很多。3.2 编写 docker-compose.yml我习惯把所有服务的编排写在一个docker-compose.yml里这样一条命令就能启动和停止整套环境也方便统一管理网络。来看这个完整的文件version: 3.8 services: loki: image: grafana/loki:3.3.2 container_name: loki restart: unless-stopped ports: - 3100:3100 volumes: - /opt/loki-stack/config/loki-config.yaml:/etc/loki/local-config.yaml - /opt/loki-stack/data/loki:/loki command: -config.file/etc/loki/local-config.yaml networks: - loki-net alloy: image: grafana/alloy:v1.4.1 container_name: alloy restart: unless-stopped ports: - 12345:12345 volumes: - /opt/loki-stack/config/alloy-config.alloy:/etc/alloy/config.alloy - /var/lib/docker/containers:/var/lib/docker/containers:ro - /var/log:/var/log:ro depends_on: - loki networks: - loki-net grafana: image: grafana/grafana:11.2.0 container_name: grafana restart: unless-stopped ports: - 3000:3000 environment: - GF_SECURITY_ADMIN_USERadmin - GF_SECURITY_ADMIN_PASSWORDadmin123 - GF_USERS_ALLOW_SIGN_UPfalse volumes: - /opt/loki-stack/data/grafana:/var/lib/grafana depends_on: - loki networks: - loki-net networks: loki-net: driver: bridge几个细节需要说明一下第一restart: unless-stopped很关键服务器重启后容器会自动拉起来省去手动恢复的麻烦。第二Alloy 容器把宿主机的/var/lib/docker/containers和/var/log以只读方式挂载进去这是采集容器日志和宿主机日志的前提。第三depends_on只保证启动顺序不保证服务已经就绪Loki 启动速度很快一般不会有问题但如果 Alloy 报连接拒绝可以手动重启一下 alloy 容器。Grafana 的环境变量里我直接设置了初始账号密码生产环境建议改成强密码并通过环境变量文件或者 Docker secret 管理而不是直接写在 compose 文件里。3.3 Loki 配置文件详解Loki 的配置项非常多但快速部署时只需要一个最精简的单机模式配置。我在/opt/loki-stack/config/loki-config.yaml写入以下内容auth_enabled: false server: http_listen_port: 3100 common: instance_addr: 127.0.0.1 path_prefix: /loki storage: filesystem: chunks_directory: /loki/chunks rules_directory: /loki/rules replication_factor: 1 ring: kvstore: store: inmemory schema_config: configs: - from: 2024-01-01 store: tsdb object_store: filesystem schema: v13 index: prefix: index_ period: 24h limits_config: allow_structured_metadata: true volume_enabled: true retention_period: 168h这里面的几个关键点要理解auth_enabled: false表示关闭多租户认证。单机自用场景不需要租户隔离如果关掉之后所有日志都归到默认的 fake 租户里查询和写入都不用带认证头。如果是多人共用可以开启多租户但要对每个租户做鉴权复杂度上来了。schema_config里store: tsdb是 Loki 3.x 的新默认存储比之前的 boltdb-shipper 性能更好schema: v13也是当前版本推荐的值不要手动改成别的。如果参考老的教程用 v11 schema虽然也能跑但没法享受新版特性而且将来升级更麻烦。limits_config.retention_period是日志保留时间我设置为168h也就是 7 天。这个值直接决定磁盘占用日志量大而磁盘有限的话可以改成 72h或者干脆只在 Grafana 里对数据做持久化裁剪。值得提醒的是单机模式下 Loki 不会自动做物理删除只在查询时过滤掉过期数据所以磁盘回收效果有限。如果对磁盘占用极度敏感得配置专门的 retention 清理策略这是另一个话题了。3.4 Alloy 配置文件详解Alloy 的配置语法是 HCL 风格和 Promtail 的 YAML 完全不同。我的采集需求有两个一是采集宿主机所有 Docker 容器的标准输出二是采集宿主机/var/log/下的 syslog 日志。下面是与之对应的/opt/loki-stack/config/alloy-config.alloylogging { level info } // 发现所有 Docker 容器的日志目标 discovery.docker containers { host unix:///var/run/docker.sock } // 从 Docker API 获取容器的日志流 loki.source.docker container_logs { host unix:///var/run/docker.sock targets discovery.docker.containers.targets forward_to [loki.write.default.receiver] } // 读取宿主机系统日志文件 loki.source.file system_logs { targets [ {__path__ /var/log/syslog, job system}, {__path__ /var/log/auth.log, job system}, ] forward_to [loki.write.default.receiver] } // 统一写入 Loki loki.write default { endpoint { url http://loki:3100/loki/api/v1/push } }这里有个容易踩坑的地方Alloy 容器如果要通过 Docker API 发现容器必须把宿主机的 docker socket 挂载进来。上面的 compose 文件里我故意没写这一行需要补一下。修改后 Alloy 的 volumes 部分要加上volumes: - /opt/loki-stack/config/alloy-config.alloy:/etc/alloy/config.alloy - /var/lib/docker/containers:/var/lib/docker/containers:ro - /var/log:/var/log:ro - /var/run/docker.sock:/var/run/docker.sock等等这里有两个采集容器日志的方案loki.source.docker依赖 Docker APIloki.source.journal依赖 systemd journal。前者的好处是能自动拿到容器的标签容器名、镜像名等后者的好处是不依赖 Docker socket安全性更高。我前面用了discovery.dockerloki.source.docker就需要 docker.sock。如果你对挂载 docker.sock 有安全顾虑可以改成直接读文件方式但会丢失容器标签的自动发现能力。socket 挂载的安全风险我自己评估过Alloy 容器如果被攻破攻击者可以直接控制宿主机的 Docker 进程。但这是在单机自用场景风险可控。如果多人共用同一个 Alloy那就需要慎重了。另外Alloy 的每个组件都可以独立设置日志级别排查问题的时候可以把logging { level debug }打开但平时建议保持 info避免日志刷屏。3.5 启动与验证配置文件都准备好了先检查一下语法然后启动服务cd /opt/loki-stack # 验证 Alloy 配置语法需要先拉取镜像第一次会比较慢 docker compose run --rm alloy run --config.file/etc/alloy/config.alloy --server.http.listen-addr0.0.0.0:12345 --dry-run实际中 Alloy 没有直接的 dry-run 参数我更常用的是打开容器日志看有没有报错。所以直接启动再验证docker compose up -d docker compose ps正常情况下三个容器都是 Up 状态。首次拉取镜像可能需要几分钟耐心等。启动完成后验证 Loki 是否正常接收数据# 查看 Loki 的 ready 接口 curl http://localhost:3100/ready # 通过 Loki API 查询日志流 curl -s http://localhost:3100/loki/api/v1/labels | head -20如果看到ready返回ready并且labels接口返回了一堆 label 键比如container_name、job等说明 Alloy 已经把容器日志采集进 Loki 了。到这里核心链路已经通了剩下的是在 Grafana 里把它用起来。4. Grafana 接入与日志查询实践4.1 添加 Loki 数据源打开浏览器访问http://192.168.1.100:3000用前面设置的 admin/admin123 登录。进入后左侧菜单选择 Connections → Data sources → Add data source找到 Loki 并点击。关键配置只有一项URL。因为 Grafana 和 Loki 在同一个 docker 网络里所以可以直接用服务名http://loki:3100。如果你只是想测试也可以填http://服务器IP:3100效果一样但走的是宿主机端口转发。填完后点击 Save test如果看到绿色的 Successfully queried the Loki API 提示就说明数据源配置成功了。这里唯一可能出错的就是网络不通或者 Loki 没起来按提示排查即可。4.2 LogQL 基础查询示例LogQL 是 Loki 的查询语言和 PromQL 长得有点像核心分两部分日志流选择器和过滤器。日志流选择器用大括号包着一组标签例如{jobsystem}这表示查询所有 job 标签为 system 的日志流。更进一步可以按容器名过滤{container_namealloy}如果只想看包含特定关键字的日志加一个管道符{container_namenginx} | error| error是包含过滤还有几个常用的# 不包含 error {container_namenginx} ! error # 正则匹配 {container_namenginx} |~ ERROR|FATAL # 提取 JSON 字段后过滤适合结构化日志 {container_nameapp} | json | levelerror实际排障中最常用的姿势是先用标签过滤流再按关键字搜。比如应用报错了我一般先查{container_nameapi-gateway} | Exception如果结果太多再加时间范围或者再加一层过滤| NullPointer逐步缩小范围。掌握这几个 LogQL 语法日常工作基本够用了。4.3 快速搭建一个日志可视化面板Loki 的数据主要用于检索和趋势分析不像 Prometheus 的指标数据那样适合做复杂的仪表盘。但有一个场景很实用统计错误日志的数量趋势。在 Dashboards → New dashboard → Add visualization 中数据源选择 Loki然后输入以下 LogQLsum(count_over_time({container_namenginx} | error [5m]))这条查询的含义是统计 nginx 容器最近 5 分钟内包含 error 的日志条数。用 count_over_time 把日志转为时间序列再 sum 汇总就能画出一张错误日志趋势图。配合 Grafana 的告警功能当错误数量超过阈值时自动发通知这就是一个简单可用的日志告警链路。Grafana 的 Explore 页面是日常排查日志的主战场可以快速切换数据源、设置时间范围、按标签筛选。建议把常用的查询保存下来下次排查直接一键打开效率高很多。5. 常见问题与排查技巧实录5.1 Alloy 采集不到日志怎么办这是最常见的问题。先用下面的命令确认 Alloy 是否真的发现了日志目标docker logs alloy --tail 50如果日志里没有报错但还是查不到数据多半是目标发现有问题。Alloy 提供了一个内置的 UI 界面在浏览器里访问http://192.168.1.100:12345可以看到所有组件的运行状态、目标列表以及每个目标的标签信息。这是排查采集问题最直观的手段。打开 UI 后找到loki.source.docker.container_logs这个组件点进去能看到发现的所有容器目标。如果这里显示的目标列表为空说明discovery.docker没有拿到容器列表检查 docker.sock 挂载是否正常如果能看到目标但 Loki 里没数据检查loki.write的 endpoint 地址是否能通。另外还有一个常见原因是容器日志驱动不是 json-file。Docker 默认的日志驱动是 json-fileAlloy 能直接读到。但如果有人把某个容器的日志驱动改成journald或者syslog/var/lib/docker/containers下就不会有对应的日志文件自然采集不到。排查时可以用docker inspect 容器名 --format {{.HostConfig.LogConfig.Type}}确认。5.2 Loki 内存占用过高单机版 Loki 默认会缓存很多块索引内存占用会随着日志量缓慢上涨。如果发现 Loki 容器 RSS 居高不下可以从这几个方向优化。首先在loki-config.yaml里限制缓存大小chunk_store_config: chunk_cache_config: enable_fifocache: true fifocache: max_size_bytes: 500MB max_entries: 5000其次限制每个查询的最大日志量防止一次查询扫太多数据把内存打爆limits_config: max_entries_limit_per_query: 5000 max_query_series: 500另外压缩率也很影响内存可以开启 gzip 压缩。常见做法是在 Loki 的配置里对 HTTP 响应开启压缩Grafana 端会透明处理这样网络开销也能降下来。在实际使用中我遇到过 Grafana 查询一个跨度很大的时间范围比如查 30 天日志时Loki 内存飙升到近 2G 的情况。后来把查询范围控制在 24 小时内配合分批次查询就基本不会再触顶了。这不是系统缺陷而是 Loki 的架构特性决定的所以查询习惯也要跟着调整。5.3 Grafana 提示数据源报错或连接到 Loki 失败如果 Grafana 的数据源测试报错先分清楚是网络问题还是配置问题。在 Grafana 容器里手动测试一下能不能访问 Lokidocker exec -it grafana curl http://loki:3100/ready如果不能通检查三个容器是不是在同一个 docker 网络里。我用docker network ls确认过如果 compose 里定义了自定义网络Grafana 和 Loki 通常会自动加入。但如果你手动创建过容器或者改过网络就可能出现跨网络不通的问题。如果网络通了还是报错看一下 Grafana 日志docker logs grafana --tail 50有时候是版本兼容性问题。比如老版本的 Grafana 用默认设置去连接 Loki 3.x 新增的端点会报datasource not found之类的错误。解决方案很简单把 Grafana 升级到较新版本或者确保 Loki 配置中auth_enabled: false避免多租户问题。5.4 日志时间不对差 8 小时怎么办这是一个时区问题。很多容器里的日志时间默认是 UTC而中文用户习惯用北京时间UTC8导致 Grafana 里看到的时间总是“少了 8 小时”。这个问题要从两头解决。一头是 Alloy 读取日志时需要把时间戳正确传递。另一头是 Loki 的配置里默认时间字段是纳秒级如果日志里带的时间戳是秒级Loki 会当成纳秒解析时间就会变得很奇怪。常见的做法是让 Alloy 的loki.source.file组件解析日志中的时间字段或在写入前用stage.timestamp统一格式。对我这种用 Docker 容器标准输出的场景最简单的方式是给容器设置TZAsia/Shanghai环境变量看日志时把 Grafana 的时间显示切换成本地时区就能直接对齐。要注意的是Loki 存储的一律是 UTC 时间戳Grafana 展示时可以按浏览器时区转换这并不影响数据准确性。排查问题时心里要清楚系统内部是 UTC展示层是本地时间就不会被差 8 小时搞懵了。6. 个人实操心得与后续扩展整套系统从装 Docker 到跑通日志查询我大概花了不到一个小时对喜欢折腾的人来说这已经算很快了。对比之前部署 ELK 的经历——光是调 Elasticsearch 的 JVM 堆就折腾了半天Loki 这套确实是省心不少。如果你手里正有几台服务器日志排查全靠 ssh 加 grep我强烈建议照这篇部署一套体验一下“在一个页面里搜所有机器日志”的爽感。几个我踩坑后的经验再啰嗦一遍第一版本尽量选新的Loki 3.x 的 schema 和 Alloy 的配置语法变化都比较大网上老教程容易把你带沟里。第二Alloy 的 UI 界面是排查采集问题的利器别忽略它。第三日志保留时间设置务必在部署时就定好数据量上来之后再改 retention要等很久才生效。第四生产环境给 Grafana 和 Loki 设置独立的强密码不要把 admin/admin123 留到上线。后续如果想扩展可以按这几个方向走一是给 Alloy 增加更多采集源比如 Java 应用的 logback 直接推送日志或者抓取 Kubernetes 集群日志二是在 Grafana 里配置告警规则让 Loki 的错误日志数量触发告警通知到钉钉或企业微信三是接入 Prometheus 指标监控把日志和指标联动分析比如看到错误日志峰值的同时观察 CPU 和内存指标变化定位问题的能力会强很多。这套组合的想象空间不小值得慢慢玩。
返回列表