Hướng dẫn cài đặt và sử dụng Grafana Alloy: Thay thế Prometheus Agent, Promtail và OpenTelemetry Collector bằng một công cụ thu thập Telemetry duy nhất

Monitoring tutorial - IT technology blog
Monitoring tutorial - IT technology blog

Mình đã chạy stack Prometheus Agent + Promtail + OpenTelemetry Collector song song trên production gần một năm. Ba binary, ba config file, ba systemd service — mỗi lần update là một lần đau đầu. Khi chuyển sang Grafana Alloy, toàn bộ pipeline thu thập telemetry gói gọn trong một binary duy nhất. Đây là những gì mình học được sau 6 tháng chạy thực tế.

Cài đặt và chạy Alloy trong 5 phút

Cài đặt trên Ubuntu/Debian

# Thêm Grafana APT repository
sudo mkdir -p /etc/apt/keyrings/
wget -q -O - https://apt.grafana.com/gpg.key | gpg --dearmor | sudo tee /etc/apt/keyrings/grafana.gpg > /dev/null
echo "deb [signed-by=/etc/apt/keyrings/grafana.gpg] https://apt.grafana.com stable main" | sudo tee /etc/apt/sources.list.d/grafana.list

# Cài đặt Alloy
sudo apt-get update
sudo apt-get install -y alloy

Config tối giản — thu thập metrics và logs ngay lập tức

Tạo file /etc/alloy/config.alloy với nội dung sau:

// Thu thập metrics từ node_exporter (thay thế Prometheus scrape)
prometheus.scrape "node_exporter" {
  targets    = [{"__address__" = "localhost:9100"}]
  forward_to = [prometheus.remote_write.main.receiver]
}

// Gửi metrics lên Prometheus/Mimir
prometheus.remote_write "main" {
  endpoint {
    url = "https://your-mimir-endpoint/api/prom/push"
    basic_auth {
      username = "your-username"
      password = "your-api-key"
    }
  }
}

// Thu thập logs từ systemd journal (thay thế Promtail)
loki.source.journal "systemd" {
  forward_to = [loki.write.main.receiver]
}

// Gửi logs lên Loki
loki.write "main" {
  endpoint {
    url = "https://your-loki-endpoint/loki/api/v1/push"
    basic_auth {
      username = "your-username"
      password = "your-api-key"
    }
  }
}
# Khởi động và enable Alloy
sudo systemctl enable alloy
sudo systemctl start alloy

# Kiểm tra trạng thái
sudo systemctl status alloy

# Theo dõi logs
sudo journalctl -u alloy -f

Xong. Alloy đang scrape node_exporter metrics và forward logs từ systemd — hai việc trước đây cần hai agent riêng biệt, giờ chạy trong một process duy nhất.

Alloy là gì và tại sao kiến trúc của nó khác

Grafana Alloy ra mắt năm 2024, kế thừa Grafana Agent (Flow mode). Khác với Prometheus Agent hay Promtail, Alloy được xây trên nền OpenTelemetry Collector rồi mở rộng thêm component native cho cả Prometheus lẫn Loki ecosystem — một binary duy nhất xử lý cả ba loại telemetry.

Trước Alloy, một monitoring stack điển hình trên mỗi server cần:

  • Prometheus Agent — scrape metrics, remote write
  • Promtail — thu thập logs, ship lên Loki
  • OpenTelemetry Collector — thu thập traces từ application

Ba process riêng biệt, ba config syntax khác nhau. Khi một trong ba crash lúc 3 giờ sáng, bạn phải debug từng cái một. Alloy hợp nhất tất cả.

Mọi thứ đều là component

Config syntax của Alloy dùng cú pháp HCL-like, mỗi thành phần là một component có input và output. Bạn nối chúng lại thành pipeline:

// Component A tạo data → forward sang Component B
component_type_a "my_label" {
  forward_to = [component_type_b.my_label.receiver]
}

component_type_b "my_label" {
  // tự động nhận data từ component_a
}

Giống Lego — ghép block theo thứ tự pipeline muốn. Cách này dễ debug hơn config YAML flat của Promtail: nhìn vào graph là biết ngay data đang bị stuck ở component nào, không cần đọc log mò từng dòng.

Cấu hình nâng cao

Thu thập logs từ nhiều nguồn đồng thời

// Đọc file log application
loki.source.file "app_logs" {
  targets = [
    {__path__ = "/var/log/nginx/access.log", job = "nginx", env = "production"},
    {__path__ = "/var/log/myapp/*.log",      job = "myapp", env = "production"},
  ]
  forward_to = [loki.write.local.receiver]
}

// Đọc systemd journal và thêm label từ journal fields
loki.source.journal "system" {
  forward_to    = [loki.write.local.receiver]
  relabel_rules = loki.relabel.journal_labels.rules
}

loki.relabel "journal_labels" {
  rule {
    source_labels = ["__journal__systemd_unit"]
    target_label  = "unit"
  }
  forward_to = []
}

loki.write "local" {
  endpoint {
    url = "http://loki:3100/loki/api/v1/push"
  }
}

Nhận OpenTelemetry traces từ application

// Nhận traces qua gRPC (4317) và HTTP (4318)
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]
  }
}

// Forward traces lên Tempo
otelcol.exporter.otlp "tempo" {
  client {
    endpoint = "tempo:4317"
    tls { insecure = true }
  }
}

Service discovery cho Docker

// Tự động scrape tất cả container đang chạy
discovery.docker "containers" {
  host = "unix:///var/run/docker.sock"
}

prometheus.scrape "docker_targets" {
  targets         = discovery.docker.containers.targets
  forward_to      = [prometheus.remote_write.main.receiver]
  scrape_interval = "30s"
}

Debugging bằng built-in UI

Tính năng mình dùng nhiều nhất mà ít người để ý: Alloy có web UI tại port 12345. Vào http://localhost:12345 để xem graph toàn bộ component pipeline dạng flow chart, health status từng component, và data đang chạy qua từng stage.

# Truy cập an toàn qua SSH tunnel
ssh -L 12345:localhost:12345 user@your-server
# Sau đó mở http://localhost:12345 trên máy local

Tips thực tế sau 6 tháng production

1. Thêm context labels để chống alert fatigue

Khi mới setup monitoring, mình từng nhận alert liên tục vì threshold đặt sai — CPU 70% trên staging cũng báo động giống hệt production. Giải pháp: inject context labels ngay tại Alloy trước khi ship lên Mimir, sau đó viết Alertmanager rule filter theo environment:

// Thêm environment labels vào tất cả metrics trước khi remote write
prometheus.relabel "add_context" {
  rule {
    target_label = "environment"
    replacement  = "production"
  }
  rule {
    target_label = "region"
    replacement  = "ap-northeast-1"
  }
  forward_to = [prometheus.remote_write.main.receiver]
}

Kết quả: alert chỉ fire khi CPU > 80% environment là “production”. Staging với dev im thin thít.

2. Validate và reload config không downtime

# Format và kiểm tra syntax
alloy fmt /etc/alloy/config.alloy

# Reload config không cần restart service
sudo systemctl reload alloy

# Hoặc qua HTTP API
curl -X POST http://localhost:12345/-/reload

3. Migration từ Promtail tự động

Grafana có sẵn tool convert config Promtail sang Alloy format:

alloy convert \
  --source-format=promtail \
  --output=/etc/alloy/config.alloy \
  /etc/promtail/config.yml

Tool này giúp mình migrate 12 server trong một buổi chiều. Output không hoàn hảo 100% — một số label rule cần chỉnh tay — nhưng tiết kiệm khoảng 70% thời gian so với viết tay từ đầu.

4. Resource usage thực tế

Đo trên server 2 vCPU / 4GB RAM, chạy ~50 scrape targets cộng log collection từ ba service:

  • Alloy: ~80MB RAM, ~2% CPU trung bình
  • 3 agent riêng trước đây: ~250MB RAM tổng cộng

Chênh ~170MB. Nghe nhỏ, nhưng mấy VPS 1GB hoặc edge node trên Raspberry Pi thì đây là con số thực sự cảm nhận được — vài server nhỏ của mình từng swap vì agent ăn RAM, chuyển sang Alloy là hết.

5. Chạy bằng Docker

docker run -d \
  --name alloy \
  --network host \
  -v /etc/alloy:/etc/alloy \
  -v /var/log:/var/log:ro \
  -v /run/log/journal:/run/log/journal:ro \
  -v /etc/machine-id:/etc/machine-id:ro \
  grafana/alloy:latest \
  run /etc/alloy/config.alloy

Grafana Alloy không phải silver bullet. Stack chỉ cần scrape metrics đơn thuần và không đụng Loki hay traces thì Prometheus thuần vẫn đơn giản hơn — ít moving part hơn, community lớn hơn. Nhưng khi cần cả ba loại telemetry, Alloy giúp bớt được một mớ việc vận hành mà không đánh đổi tính linh hoạt.

Share: