2605 字
13 分钟
Grafana Loki + Fluent Bit/Alloy 内网部署完全指南

为什么需要日志聚合#

单台服务器上 tail -f /var/log/syslog 还能应付,多台服务器加几十个容器时就失控了。日志聚合系统解决三个核心问题:

  • 集中检索:不用逐个登录服务器翻日志
  • 结构化过滤:按服务、级别、时间范围快速定位
  • 持久化存储:容器重启日志不丢失,支持长期保留

本文介绍用 Grafana Loki + Fluent Bit / Grafana Alloy 在内网环境搭建一套完整的日志聚合方案。

架构概览#

┌──────────┐ ┌──────────┐ ┌──────────┐
│ Server A │ │ Server B │ │ Server C │
│ Fluent Bit│ │ Alloy │ │ Fluent Bit│
│ (采集器) │ │ (采集器) │ │ (采集器) │
└─────┬─────┘ └─────┬─────┘ └─────┬─────┘
│ │ │
└───────────────┬───────────────┘
│ Loki API
┌───────┴───────┐
│ Loki │
│ (日志存储/查询) │
└───────┬───────┘
┌───────┴───────┐
│ Grafana │
│ (可视化) │
└───────────────┘

Loki 是什么#

Grafana Loki 是一套轻量级日志聚合系统,设计理念类似 Prometheus:只对标签(labels)建索引,日志正文以 chunk 形式压缩存储。相比 Elasticsearch,Loki 对资源的需求大幅降低。

特性LokiElasticsearch
索引方式仅索引标签全文索引
存储效率高(gzip/snappy 压缩)中等
内存占用高(JVM heap)
查询语言LogQL(类 PromQL)Lucene/KQL
Kubernetes 集成原生支持需额外插件
适用规模中小型到大型大型到超大型

采集器对比:Fluent Bit vs Grafana Alloy#

维度Fluent BitGrafana Alloy
语言/运行时C(极低开销)Go(Grafana Agent 继任者)
吞吐量~31,000 logs/s~15,700 logs/s
CPU 效率0.26 核 @ 10k/s0.58 核 @ 10k/s
内存占用~78 MiB @ 10k/s~66 MiB @ 10k/s
生态集成广泛,支持多种输出LGTM 生态原生整合
功能范围纯日志/指标采集日志+指标+追踪统一采集
配置语法经典 INI 格式River(类 HCL)

数据来源:VictoriaMetrics 2026 年 Kubernetes 日志采集器基准测试(日志格式包含完整结构化字段)。Fluent Bit 吞吐量约 31k logs/s,CPU 占用 0.26 核 @10k logs/s;Grafana Alloy 吞吐量约 15.7k logs/s,CPU 占用 0.58 核 @10k logs/s,内存 66 MiB。该基准测试同时指出:不同采集器在日志交付正确性(丢失/重复)上存在显著差异,生产部署需关注此项。

选型建议

  • 纯日志采集,追求极致性能 → Fluent Bit
  • 已使用 Grafana 生态,需要日志+指标+追踪统一采集 → Grafana Alloy
  • 从 Promtail / Grafana Agent 迁移 → Grafana Alloy
  • 已有 Fluent Bit 部署 → 继续使用,无需切换

系统要求#

项目最低要求推荐配置
CPU2 核4 核+
内存4 GB8 GB+
磁盘50 GB SSD200 GB+ SSD(取决于日志量和保留期)
Docker20.10+最新稳定版
Lokiv3.xv3.7+
Fluent Bitv4.0+v5.0+
Alloyv1.xv1.15+

部署准备#

创建项目目录结构:

Terminal window
mkdir -p ~/logging-stack/{loki,fluent-bit,alloy,grafana/datasources}

目录说明:

logging-stack/
├── docker-compose.yml # 主部署文件
├── loki/
│ └── loki-config.yaml # Loki 配置
├── fluent-bit/
│ ├── fluent-bit.conf # Fluent Bit 配置
│ └── parsers.conf # 自定义解析器(可选)
├── alloy/
│ └── config.alloy # Alloy 配置
└── grafana/
└── datasources/
└── loki-ds.yaml # Grafana 数据源

Docker Compose 部署#

以下 Docker Compose 文件同时包含 Fluent Bit 和 Alloy,实际使用时二选一即可。

docker-compose.yml
services:
loki:
image: grafana/loki:3.7
container_name: loki
volumes:
- ./loki/loki-config.yaml:/etc/loki/config.yaml
- loki-data:/loki
command: -config.file=/etc/loki/config.yaml
ports:
- "3100:3100"
restart: unless-stopped
healthcheck:
test: ["CMD-SHELL", "wget -q --spider http://localhost:3100/ready || exit 1"]
interval: 10s
timeout: 5s
retries: 5
fluent-bit:
image: fluent/fluent-bit:3.0
container_name: fluent-bit
volumes:
- ./fluent-bit/fluent-bit.conf:/fluent-bit/etc/fluent-bit.conf
- /var/log:/var/log:ro # 宿主机日志目录
- /var/lib/docker/containers:/var/lib/docker/containers:ro # Docker 容器日志
ports:
- "2020:2020" # Fluent Bit 监控端点
- "24224:24224" # Forward 协议端口(供其他服务推送日志)
restart: unless-stopped
depends_on:
loki:
condition: service_healthy
# 若选择 Alloy 替代 Fluent Bit
alloy:
image: grafana/alloy:latest
container_name: alloy
volumes:
- ./alloy/config.alloy:/etc/alloy/config.alloy
- /var/log:/var/log:ro
- /var/lib/docker/containers:/var/lib/docker/containers:ro
- /run/systemd/journal:/run/systemd/journal:ro # systemd journal
user: "0:0" # 需要 root 权限读取系统日志
restart: unless-stopped
depends_on:
loki:
condition: service_healthy
grafana:
image: grafana/grafana:latest
container_name: grafana
volumes:
- ./grafana/datasources:/etc/grafana/provisioning/datasources
- grafana-data:/var/lib/grafana
environment:
- GF_SECURITY_ADMIN_USER=admin
- GF_SECURITY_ADMIN_PASSWORD=changeme
ports:
- "3000:3000"
restart: unless-stopped
depends_on:
- loki
volumes:
loki-data:
grafana-data:

Loki 配置详解#

⚠️ 生产环境注意:下方配置使用 filesystem 对象存储,仅适用于测试/POC。生产环境推荐使用 S3/GCS/MinIO 等对象存储(见下文 MinIO 配置示例),以支持水平扩展、数据高可用和更好的性能。

loki/loki-config.yaml
auth_enabled: false
server:
http_listen_port: 3100
common:
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:
ingestion_rate_mb: 16
ingestion_burst_size_mb: 32
max_streams_per_user: 10000
max_entries_limit_per_query: 5000
reject_old_samples: true
reject_old_samples_max_age: 168h
retention_period: 720h # 30 天,需与 compactor.retention_enabled 配合使用
compactor:
working_directory: /loki/compactor
retention_enabled: true
retention_delete_delay: 2h
delete_request_store: filesystem
query_range:
results_cache:
cache:
embedded_cache:
enabled: true
max_size_mb: 100
analytics:
reporting_enabled: false

关键配置说明:

配置项说明
schema: v13推荐 schema 版本,使用 TSDB 索引
ingestion_rate_mb单租户每秒最大摄入量,内网环境可适当调高
max_streams_per_user最大 stream 数量上限,超过会被限流
reject_old_samples_max_age拒绝超过此时间的旧日志
retention_enabled: true开启自动日志过期删除

使用 MinIO 作为 S3 存储#

当需要扩展存储或数据备份时,可将 filesystem 替换为 S3 兼容对象存储:

common:
path_prefix: /loki
storage:
s3:
endpoint: minio:9000
bucketnames: loki-data
access_key_id: minioadmin
secret_access_key: minioadmin
insecure: true
s3forcepathstyle: true

对应的 MinIO 服务:

minio:
image: minio/minio:latest
container_name: minio
command: server /data --console-address ":9001"
environment:
- MINIO_ROOT_USER=minioadmin
- MINIO_ROOT_PASSWORD=minioadmin
volumes:
- minio-data:/data
ports:
- "9000:9000"
- "9001:9001"
restart: unless-stopped

Fluent Bit 配置详解#

fluent-bit/fluent-bit.conf
[SERVICE]
Flush 1
Log_Level info
Daemon off
Parsers_File parsers.conf
# ---- 系统日志 ----
[INPUT]
Name tail
Path /var/log/syslog
Tag system.syslog
Parser syslog-rfc3164
Mem_Buf_Limit 5MB
Skip_Long_Lines On
[INPUT]
Name tail
Path /var/log/auth.log
Tag system.auth
Mem_Buf_Limit 5MB
# ---- Docker 容器日志 ----
[INPUT]
Name tail
Path /var/lib/docker/containers/*/*.log
Tag docker.*
Parser docker
Mem_Buf_Limit 10MB
Skip_Long_Lines On
# ---- Nginx 访问日志(示例)----
[INPUT]
Name tail
Path /var/log/nginx/access.log
Tag nginx.access
Parser nginx
Mem_Buf_Limit 5MB
# ---- Nginx 错误日志 ----
[INPUT]
Name tail
Path /var/log/nginx/error.log
Tag nginx.error
Mem_Buf_Limit 5MB
# ---- 输出到 Loki ----
[OUTPUT]
Name loki
Match *
Host loki
Port 3100
Labels job=fluent-bit
Label_keys service,level
structured_metadata container_id,node_name
Line_format json
Auto_kubernetes_labels off

Label_keys 中的字段会作为 Loki 标签建索引。注意控制标签基数——不要把 container_idtrace_id 等唯一值设为标签,否则会导致性能问题。

自定义解析器#

fluent-bit/parsers.conf
[PARSER]
Name nginx
Format regex
Regex ^(?<remote>[^ ]*) - (?<user>[^ ]*) \[(?<time>[^\]]*)\] "(?<method>\S+)(?: +(?<path>[^\"]*?)(?: +\S*)?)?" (?<code>[^ ]*) (?<size>[^ ]*)(?: "(?<referer>[^\"]*)" "(?<agent>[^\"]*)")?$
Time_Key time
Time_Format %d/%b/%Y:%H:%M:%S %z
[PARSER]
Name docker
Format json
Time_Key time
Time_Format %Y-%m-%dT%H:%M:%S.%L
[PARSER]
Name syslog-rfc3164
Format regex
Regex ^\<(?<pri>[0-9]+)\>(?<time>[^ ]* {1,2}[^ ]* [^ ]*) (?<host>[^ ]*) (?<ident>[a-zA-Z0-9_\/\.\-]*)(?:\[(?<pid>[0-9]+)\])?(?:[^\:]*\:)? *(?<message>.*)$
Time_Key time
Time_Format %b %d %H:%M:%S

Grafana Alloy 配置详解#

Alloy 使用 River 语法,配置更现代化,通过组件管道组合实现日志采集→处理→输出。

config.alloy
// ---- 发现日志文件 ----
local.file_match "syslog" {
path_targets = [{"__path__" = "/var/log/syslog"}]
}
local.file_match "auth" {
path_targets = [{"__path__" = "/var/log/auth.log"}]
}
local.file_match "nginx_access" {
path_targets = [{"__path__" = "/var/log/nginx/access.log"}]
}
local.file_match "nginx_error" {
path_targets = [{"__path__" = "/var/log/nginx/error.log"}]
}
// ---- Docker 容器日志 ----
local.file_match "docker_logs" {
path_targets = [{"__path__" = "/var/lib/docker/containers/*/*.log"}]
}
// ---- systemd journal ----
loki.source.journal "journal" {
forward_to = [loki.write.default.receiver]
relabel_rules = loki.relabel.journal.rules
labels = {job = "systemd-journal"}
}
loki.relabel "journal" {
rule {
source_labels = ["__journal__systemd_unit"]
target_label = "unit"
}
rule {
source_labels = ["__journal__hostname"]
target_label = "host"
}
rule {
source_labels = ["__journal_priority_keyword"]
target_label = "level"
}
}
// ---- 日志文件采集 ----
loki.source.file "system_logs" {
targets = concat(
local.file_match.syslog.targets,
local.file_match.auth.targets,
)
forward_to = [loki.write.default.receiver]
}
loki.source.file "nginx_logs" {
targets = concat(
local.file_match.nginx_access.targets,
local.file_match.nginx_error.targets,
)
forward_to = [loki.write.default.receiver]
}
loki.source.file "docker_containers" {
targets = local.file_match.docker_logs.targets
forward_to = [loki.process.docker_parse.receiver]
}
// ---- Docker JSON 日志解析 ----
loki.process "docker_parse" {
stage.json {
expressions = {log = "log", time = "time", stream = "stream"}
}
stage.timestamp {
source = "time"
format = "RFC3339"
}
stage.labels {
values = {stream = ""}
}
forward_to = [loki.write.default.receiver]
}
// ---- 写入 Loki ----
loki.write "default" {
endpoint {
url = "http://loki:3100/loki/api/v1/push"
}
external_labels = {agent = "alloy"}
}

Alloy 支持通过 --config.format=alloy 在启动时校验配置:alloy run --config.format=alloy /etc/alloy/config.alloy

Grafana 数据源配置#

grafana/datasources/loki-ds.yaml
apiVersion: 1
datasources:
- name: Loki
type: loki
access: proxy
url: http://loki:3100
isDefault: true
editable: true

启动与验证#

Terminal window
# 启动(二选一:注释掉不需要的采集器)
docker compose up -d
# 检查各服务状态
docker compose ps
# 验证 Loki 就绪
curl -s http://localhost:3100/ready
# 检查 Fluent Bit 运行状态
curl -s http://localhost:2020/api/v1/metrics | grep -E "input_bytes|output_bytes"
# 检查 Loki 接收到的日志量
curl -s http://localhost:3100/metrics | grep log_entries_total

打开浏览器访问 http://<服务器IP>:3000

  1. 使用 admin / changeme 登录 Grafana
  2. 左侧菜单 → Explore → 数据源选择 Loki
  3. 输入 LogQL 查询日志:
{job="fluent-bit"} # 查看所有 Fluent Bit 采集的日志
{job="fluent-bit"} |= "error" # 包含 "error" 的日志
{job="systemd-journal"} |~ "(?i)fail" # systemd journal 中不区分大小写匹配 fail
{stream="stdout"} # 容器的 stdout 日志

生产环境调优#

Loki 调优#

参数默认值建议值说明
ingestion_rate_mb416~32提高日志摄入速率上限
ingestion_burst_size_mb832~64突发流量缓冲区
max_streams_per_user不限10000防止标签爆炸
max_entries_limit_per_query50005000~10000单次查询最大条目数
query_timeout1m1m~5m长时间范围查询允许超时
retention_period0(不过期)720h(30 天)日志保留期

Fluent Bit 调优#

参数默认值建议值说明
Flush11~5刷新间隔(秒),低延迟用 1
Mem_Buf_Limit无限制5MB~50MB单个 input 的内存缓冲区
storage.max_chunks_up128128~256同时上传的最大 chunk 数
net.connect_timeout10s5s连接超时
net.keepaliveonon保持长连接

Alloy 调优#

参数建议值说明
tail_from_endtrue仅采集新日志(重启后不重复发送)
max_log_size"2MB"单行最大日志长度
sync_period"10s"文件发现同步周期
batch.size16384批量发送大小(字节)
batch.timeout"1s"批量发送超时

Nginx 反向代理(可选)#

如果需要通过域名访问 Loki API 和 Grafana:

server {
listen 80;
server_name logs.example.local;
# Grafana
location / {
proxy_pass http://127.0.0.1:3000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
# Loki API(供采集器推送)
location /loki/ {
proxy_pass http://127.0.0.1:3100;
proxy_set_header Host $host;
}
}

常见问题#

Q:Loki 提示 too many labelsmax_streams_per_user 错误

避免将唯一值(如 container_id、trace_id、request_id)设为 Loki 标签。标签应保持低基数,可取值有限(如 service、level、host、namespace)。高基数字段用 structured_metadata 存储。

# Fluent Bit:使用 structured_metadata 替代 label_keys
[OUTPUT]
Name loki
structured_metadata container_id,trace_id
Label_keys service,level

Q:Fluent Bit 读取 Docker 日志出现乱码

Docker 使用 JSON 格式存储日志,配置 docker parser 解析:

[INPUT]
Name tail
Path /var/lib/docker/containers/*/*.log
Parser docker

Q:Alloy 启动报权限错误

Terminal window
# 将 alloy 用户加入相关组
sudo usermod -aG adm,systemd-journal alloy
# 或直接以 root 运行(docker-compose 中设置 user: "0:0")

Q:Loki 占用磁盘空间过大

# 在 Loki 配置中启用自动压缩和保留
compactor:
retention_enabled: true
retention_delete_delay: 2h
limits_config:
retention_period: 720h # 30 天后自动删除

Q:多台服务器的日志如何汇聚

在每台服务器上运行 Fluent Bit 或 Alloy,配置 output 指向中央 Loki 的 API 地址:

# Fluent Bit OUTPUT 配置
[OUTPUT]
Name loki
Host <LOKI_SERVER_IP>
Port 3100
Labels job=fluent-bit, host=server-a

Q:Fluent Bit 日志中有 OOM 或内存不足

检查 Mem_Buf_Limit 设置,降低单个 input 的缓冲区。也可整体限制容器内存:

fluent-bit:
deploy:
resources:
limits:
memory: 512M

Q:部分日志丢失,如何排查?

  1. 检查采集器缓冲区:curl localhost:2020/api/v1/metrics | grep mem_buf_limit
  2. 查看 Loki 限流指标:sum(rate(loki_discarded_samples_total[5m])) by (reason)
  3. 确认采集器与 Loki 之间的网络连通性,以及 depends_on 健康检查是否生效
  4. 验证日志行长度是否超过 Loki 限制(默认 256KB),超长日志会被截断

参考资源#

Grafana Loki + Fluent Bit/Alloy 内网部署完全指南
https://blog.syomega.top/posts/grafana-loki-fluent-bit-alloy-deployment/
作者
酱w
发布于
2026-05-27
许可协议
CC BY-NC-SA 4.0