香港服务器部署Grafana Alloy:统一遥测数据采集替代Prometheus+Loki多Agent方案
随着可观测性体系的建设,服务器上往往运行着多个采集 Agent:Prometheus Node Exporter 采集指标、Promtail 采集日志、Jaeger Agent 采集链路追踪……每个 Agent 独立运行,各自消耗资源,配置分散难以管理。Grafana Alloy(Grafana Agent 的继任者)将所有遥测数据的采集统一到一个 Agent 中,用 River 配置语言编写声明式管道,显著简化可观测性栈的运维复杂度。
一、Alloy 的能力范围
| 遥测类型 | 传统方案 | Grafana Alloy 替代 |
|---|---|---|
| 系统指标 | Prometheus Node Exporter | 内置 prometheus.exporter.unix |
| 应用指标 | 各类 Exporter | prometheus.scrape + 内置 Exporter |
| 日志采集 | Promtail | loki.source.file / loki.source.docker |
| 链路追踪 | Jaeger/OTEL Agent | otelcol.receiver.otlp |
| Profiles | Pyroscope Agent | pyroscope.scrape |
二、安装 Grafana Alloy
<code"># Ubuntu/Debian 安装(官方仓库) wget -q -O - https://apt.grafana.com/gpg.key | gpg --dearmor > /usr/share/keyrings/grafana.gpg echo "deb [signed-by=/usr/share/keyrings/grafana.gpg] https://apt.grafana.com stable main" \ > /etc/apt/sources.list.d/grafana.list apt update && apt install -y alloy # 验证安装 alloy --version # 或者 Docker 安装 docker run -d \ --name alloy \ --restart unless-stopped \ --network host \ -v /opt/alloy/config:/etc/alloy \ -v /var/log:/var/log:ro \ -v /var/run/docker.sock:/var/run/docker.sock:ro \ grafana/alloy:latest \ run /etc/alloy/config.alloy
三、River 配置文件(config.alloy)
<code"># /etc/alloy/config.alloy
# River 语言:声明式,模块化,类似 Terraform HCL
# ══════════════════════════════════════════
# 第一部分:系统指标采集(替代 Node Exporter)
# ══════════════════════════════════════════
prometheus.exporter.unix "node" {
# 启用所需的指标收集器
enable_collectors = [
"cpu", "diskstats", "filesystem",
"loadavg", "meminfo", "netdev",
"stat", "time", "uname",
]
}
prometheus.scrape "node" {
targets = prometheus.exporter.unix.node.targets
forward_to = [prometheus.remote_write.grafana.receiver]
scrape_interval = "30s"
}
# ══════════════════════════════════════════
# 第二部分:应用指标采集(Nginx、Redis 等)
# ══════════════════════════════════════════
prometheus.exporter.redis "redis_local" {
redis_addr = "redis://localhost:6379"
}
prometheus.scrape "redis" {
targets = prometheus.exporter.redis.redis_local.targets
forward_to = [prometheus.remote_write.grafana.receiver]
}
# 从 Nginx stub_status 采集
prometheus.scrape "nginx" {
targets = [{
__address__ = "localhost:8888",
__metrics_path__ = "/nginx_status",
instance = env("HOSTNAME"),
job = "nginx",
}]
forward_to = [prometheus.remote_write.grafana.receiver]
}
# ══════════════════════════════════════════
# 第三部分:日志采集(替代 Promtail)
# ══════════════════════════════════════════
# Nginx 访问日志
loki.source.file "nginx_access" {
targets = [{
__path__ = "/var/log/nginx/access.log",
job = "nginx",
log_type = "access",
host = env("HOSTNAME"),
}]
forward_to = [loki.write.grafana.receiver]
}
# Nginx 错误日志
loki.source.file "nginx_error" {
targets = [{
__path__ = "/var/log/nginx/error.log",
job = "nginx",
log_type = "error",
host = env("HOSTNAME"),
}]
forward_to = [loki.write.grafana.receiver]
}
# Docker 容器日志
loki.source.docker "docker" {
host = "unix:///var/run/docker.sock"
targets = discovery.docker.containers.targets
forward_to = [loki.write.grafana.receiver]
}
discovery.docker "containers" {
host = "unix:///var/run/docker.sock"
}
# ══════════════════════════════════════════
# 第四部分:OTLP 链路追踪接收器
# ══════════════════════════════════════════
otelcol.receiver.otlp "default" {
grpc { endpoint = "0.0.0.0:4317" }
http { endpoint = "0.0.0.0:4318" }
output {
traces = [otelcol.exporter.otlp.tempo.input]
}
}
otelcol.exporter.otlp "tempo" {
client {
endpoint = "https://tempo-prod.grafana.net:443"
auth = otelcol.auth.basic.grafana_cloud.handler
}
}
otelcol.auth.basic "grafana_cloud" {
username = env("GRAFANA_CLOUD_INSTANCE_ID")
password = env("GRAFANA_CLOUD_API_KEY")
}
# ══════════════════════════════════════════
# 第五部分:数据输出目标
# ══════════════════════════════════════════
# 方案A:发送到 Grafana Cloud(托管)
prometheus.remote_write "grafana" {
endpoint {
url = "https://prometheus-prod.grafana.net/api/prom/push"
basic_auth {
username = env("GRAFANA_CLOUD_METRICS_INSTANCE_ID")
password = env("GRAFANA_CLOUD_API_KEY")
}
}
}
loki.write "grafana" {
endpoint {
url = "https://logs-prod.grafana.net/loki/api/v1/push"
basic_auth {
username = env("GRAFANA_CLOUD_LOGS_INSTANCE_ID")
password = env("GRAFANA_CLOUD_API_KEY")
}
}
}
# 方案B:发送到自托管 Grafana 栈
# prometheus.remote_write "local" {
# endpoint {
# url = "http://prometheus:9090/api/v1/write"
# }
# }
# loki.write "local" {
# endpoint { url = "http://loki:3100/loki/api/v1/push" }
# }四、环境变量配置
<code"># /etc/default/alloy(systemd 环境变量文件) HOSTNAME=hk-web-server GRAFANA_CLOUD_API_KEY=glc_xxxxxxxxxxxxx GRAFANA_CLOUD_METRICS_INSTANCE_ID=123456 GRAFANA_CLOUD_LOGS_INSTANCE_ID=789012 GRAFANA_CLOUD_INSTANCE_ID=345678 # 启动 Alloy systemctl enable --now alloy systemctl status alloy # 查看日志 journalctl -u alloy -f
五、Alloy UI(本地调试)
<code"># Alloy 内置调试 UI,默认在 :12345 端口
# http://服务器IP:12345
# UI 功能:
# - 可视化 River 配置的数据流图(组件关系)
# - 实时查看各组件的状态和指标
# - 调试配置问题(哪个组件未运行)
# 通过 Nginx 安全暴露(加 Basic Auth)
server {
listen 127.0.0.1:12346;
location / {
auth_basic "Alloy Debug UI";
auth_basic_user_file /etc/nginx/.htpasswd;
proxy_pass http://127.0.0.1:12345;
}
}六、与传统方案资源对比
| 方案 | 进程数 | 内存占用 | 配置文件数 |
|---|---|---|---|
| Node Exporter + Promtail + OTEL Agent | 3 | 约 150MB | 3个文件 |
| Grafana Alloy(统一) | 1 | 约 60MB | 1个文件 |
| 节省 | -2 进程 | -60% | -67% |
七、总结
Grafana Alloy 是可观测性栈走向成熟的标志性工具:一个 Agent、一个配置文件、一套声明式管道,替代了过去需要分别安装、配置、维护的多个 Agent。对于已经使用 Grafana 生态(Prometheus + Loki + Tempo)的团队,迁移到 Alloy 几乎是无缝的——原有的 Prometheus scrape 配置和 Promtail pipeline_stages 都可以直接在 River 语言中使用,但管理复杂度大幅降低。