私はPrometheus Agent + Promtail + OpenTelemetry Collectorのスタックを本番環境でほぼ1年間並行して運用していました。3つのバイナリ、3つの設定ファイル、3つのsystemdサービス — アップデートのたびに頭を悩ませていました。Grafana Alloyに移行してから、テレメトリ収集パイプライン全体が1つのバイナリに収まりました。6ヶ月の実運用から学んだことをまとめます。
5分でAlloyをインストールして起動する
Ubuntu/Debianへのインストール
# Grafana APTリポジトリを追加
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
# Alloyをインストール
sudo apt-get update
sudo apt-get install -y alloy
最小限のConfig — すぐにメトリクスとログを収集する
以下の内容で/etc/alloy/config.alloyファイルを作成します:
// node_exporterからメトリクスを収集(Prometheusスクレイプの代替)
prometheus.scrape "node_exporter" {
targets = [{"__address__" = "localhost:9100"}]
forward_to = [prometheus.remote_write.main.receiver]
}
// Prometheus/Mimirへメトリクスを送信
prometheus.remote_write "main" {
endpoint {
url = "https://your-mimir-endpoint/api/prom/push"
basic_auth {
username = "your-username"
password = "your-api-key"
}
}
}
// systemdジャーナルからログを収集(Promtailの代替)
loki.source.journal "systemd" {
forward_to = [loki.write.main.receiver]
}
// Lokiへログを送信
loki.write "main" {
endpoint {
url = "https://your-loki-endpoint/loki/api/v1/push"
basic_auth {
username = "your-username"
password = "your-api-key"
}
}
}
# Alloyを起動してenableにする
sudo systemctl enable alloy
sudo systemctl start alloy
# 状態を確認
sudo systemctl status alloy
# ログを監視
sudo journalctl -u alloy -f
完了です。Alloyはnode_exporterのメトリクスをスクレイプし、systemdからログを転送しています — 以前は2つの別々のエージェントが必要だったことが、1つのプロセスで動作しています。
Alloyとは何か、そのアーキテクチャが異なる理由
Grafana Alloyは2024年にリリースされ、Grafana Agent(Flowモード)を継承しています。Prometheus AgentやPromtailとは異なり、AlloyはOpenTelemetry Collectorをベースに構築され、PrometheusとLokiエコシステム両方のネイティブコンポーネントを追加しています — 1つのバイナリで3種類すべてのテレメトリを処理します。
Alloy以前、各サーバー上の典型的なモニタリングスタックには以下が必要でした:
- Prometheus Agent — メトリクスのスクレイプ、remote write
- Promtail — ログの収集、Lokiへの送信
- OpenTelemetry Collector — アプリケーションからtracesを収集
3つの別々のプロセス、3つの異なる設定構文。午前3時にどれかがクラッシュすると、1つずつデバッグしなければなりません。Alloyはこれらすべてを統合します。
すべてがコンポーネント
AlloyのConfig構文はHCL風の構文を使用し、各要素はinputとoutputを持つコンポーネントです。これらをつなぎ合わせてパイプラインを構成します:
// コンポーネントAがデータを生成 → コンポーネントBへforward
component_type_a "my_label" {
forward_to = [component_type_b.my_label.receiver]
}
component_type_b "my_label" {
// component_aからデータを自動受信
}
まるでLego — パイプラインの順序に従ってブロックを組み合わせるだけです。この方法は、Promtailのフラットなconfig YAMLよりもデバッグが容易です:グラフを見るだけで、データがどのコンポーネントで滞っているかがすぐにわかり、ログを1行ずつ追う必要がありません。
高度な設定
複数のソースから同時にログを収集する
// アプリケーションのログファイルを読み込む
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]
}
// systemdジャーナルを読み込み、journalフィールドからラベルを追加
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"
}
}
アプリケーションからOpenTelemetry tracesを受信する
// gRPC(4317)とHTTP(4318)でtracesを受信
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]
}
}
// Tempoへtracesを転送
otelcol.exporter.otlp "tempo" {
client {
endpoint = "tempo:4317"
tls { insecure = true }
}
}
DockerのService discovery
// 実行中のすべてのコンテナを自動スクレイプ
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"
}
組み込みUIによるデバッグ
私が最もよく使っていて、あまり注目されていない機能:Alloyにはポート12345でWeb UIが用意されています。http://localhost:12345にアクセスすると、コンポーネントパイプライン全体のグラフをフローチャート形式で確認でき、各コンポーネントのヘルス状態や各ステージを流れるデータも確認できます。
# SSHトンネル経由で安全にアクセス
ssh -L 12345:localhost:12345 user@your-server
# その後、ローカルマシンでhttp://localhost:12345を開く
6ヶ月の本番運用で得た実践的なTips
1. アラート疲れを防ぐコンテキストラベルを追加する
モニタリングをセットアップしたばかりの頃、閾値の設定を誤って頻繁にアラートを受け取っていました — stagingでのCPU 70%がproductionと同じようにアラートを出していたのです。解決策:Mimirに送信する前にAlloyでコンテキストラベルをinjectし、その後environmentでフィルタリングするAlertmanagerルールを記述しました:
// remote write前にすべてのメトリクスにenvironmentラベルを追加
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]
}
結果:CPUが80%を超え、かつenvironmentが「production」の場合にのみアラートが発火するようになりました。stagingとdevは静かなままです。
2. ダウンタイムなしでConfigを検証・リロードする
# フォーマットと構文チェック
alloy fmt /etc/alloy/config.alloy
# サービスを再起動せずにconfigをリロード
sudo systemctl reload alloy
# またはHTTP API経由で
curl -X POST http://localhost:12345/-/reload
3. Promtailからの自動マイグレーション
GrafanaにはPromtailの設定をAlloyフォーマットに変換するツールが用意されています:
alloy convert \
--source-format=promtail \
--output=/etc/alloy/config.alloy \
/etc/promtail/config.yml
このツールのおかげで、ある午後に12台のサーバーをマイグレーションできました。出力は100%完璧ではなく — いくつかのラベルルールは手動で調整が必要でしたが — 最初から手書きする場合と比べて約70%の時間を節約できました。
4. 実際のリソース使用量
2 vCPU / 4GB RAMのサーバーで、約50のスクレイプターゲットと3つのサービスからのログ収集を実行した場合の測定値:
- Alloy:RAM約80MB、平均CPU約2%
- 以前の3つの別エージェント:合計RAM約250MB
差は約170MB。小さく聞こえますが、1GB VPSやRaspberry Pi上のエッジノードでは実際に体感できる数値です — 私の小さなサーバーのいくつかはエージェントがRAMを食いつぶしてswapしていましたが、Alloyに移行してからはそれがなくなりました。
5. 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は万能薬ではありません。メトリクスのスクレイプだけが必要で、LokiやtracesにさわらないスタックならシンプルなPrometheusの方がシンプルです — 可動部品が少なく、コミュニティも大きい。しかし3種類すべてのテレメトリが必要な場合、Alloyは柔軟性を犠牲にすることなく、多くの運用上の手間を削減してくれます。

