Grafana Beylaのインストールと設定ガイド:eBPFを使ってGo、Python、Node.jsアプリをコード変更なしで自動監視する

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

アプリごとにインストルメンテーションする手間

自分のPrometheus + Grafanaで構成された監視システムは15台のサーバーを監視しており、ユーザーからの報告より先に障害を検知するのに何度も役立ってきた。しかし、ずっと解決できなかったブラインドスポットがあった:各アプリケーションの内部監視 — エンドポイントごとのレイテンシー、エラーレート、処理中のリクエスト数だ。

チームが新しいサービスを追加するたびに、従来の手順はこうだった:コードを開き、prometheus_clientまたはOpenTelemetry SDKをインストールし、レイテンシーを計測するミドルウェアを書き、/metricsをエクスポーズし、Prometheusのスクレイプを設定する。Goのサービスはある方法、Pythonは別の方法、Node.jsはさらに違う方法だ。小さいチームにとって、これはサービスごとに2〜3時間かかる作業で、締め切りが迫るとたいてい後回しにされる。

3ヶ月後、気づいたらサービスの40%にメトリクスが全くない状態になっていた — すべて急いで書かれたサービスで、誰もインストルメンテーションに戻る時間がなかった。

なぜ従来の方法は維持しにくいのか

ツールは揃っている。OpenTelemetryは非常に高機能で、Prometheusクライアントライブラリも充実している。しかし、手動インストルメンテーションは見えにくい形でtechnical debtを生み出す:

  • 開発者は各言語ごとにSDKのAPIを学ぶ必要がある
  • ビジネスロジックと監視ロジックがコード内に混在してしまう
  • 新しいサービスには自動的にメトリクスが付かない — 誰かが覚えて追加しなければならない
  • リファクタリング時に古いメトリクスが不正確になっても動き続け、混乱を招く

DatadogやNew RelicのようなコマーシャルAPMには優れた自動インストルメンテーションエージェントがある。しかし15ホストでDatadog Proを使うと月$300〜400ほどかかり、カスタムメトリクスは別料金だ。小さなチームの予算には合わない。

試してみた解決策

方法1:API Gatewayでの集中インストルメンテーション

NginxやEnvoyをゲートウェイとして設置し、そこでレイテンシーとリクエスト数を計測する。この方法は手軽だが、一番外側の層しか見えない — どの内部サービスが遅いかわからず、複数サービスをまたぐトレースもない。

方法2:OpenTelemetry Collector + 自動インストルメンテーションエージェント

Javaには成熟した-javaagentがある。Pythonにはopentelemetry-instrumentがある。Node.jsには@opentelemetry/auto-instrumentations-nodeがある。しかしGoにはない — Goは静的バイナリにコンパイルされるため、JVMのようなランタイムでのエージェント注入の仕組みがない。

PythonとNode.jsにはこの方法を使ったが、各サービスのエントリーポイントを修正する必要があり、Goはまだ手つかずのままだった。

方法3 — 現在使っている方法:eBPFを使ったGrafana Beyla

BeylaはGrafana Labsのオープンソースツールで、eBPF(extended Berkeley Packet Filter)を使ってLinuxカーネルにフックする。実行中のアプリケーションを自動的に観察し、コードを一行も変更する必要がない。Beylaはカーネル層で動作し、HTTP/gRPC関連のsyscallをインターセプトして、REDメトリクス(Rate、Errors、Duration)トレースに集約する。

6ヶ月のプロダクション運用を経て、これが混合言語環境に最も効果的な方法だとわかった。

Grafana Beylaのステップバイステップインストール

前提条件

  • Linux kernel 5.8以上(確認:uname -r
  • rootまたはCAP_BPFCAP_PERFMONCAP_SYS_PTRACEの権限
  • メトリクスを受け取るPrometheusが稼働中(またはGrafana Cloudを使用)

DockerでBeylaをインストール

最も手軽な試し方は、監視対象のアプリと並行してBeylaをコンテナとして実行することだ:

# ホストのポート8080で動作するアプリを監視
docker run --rm \
  --pid=host \
  --privileged \
  -e BEYLA_OPEN_PORT=8080 \
  -e BEYLA_PROMETHEUS_PORT=9400 \
  -p 9400:9400 \
  grafana/beyla:latest

http://localhost:9400/metricsにアクセスすると、アプリを何も変更しなくてもhttp_server_request_duration_secondsメトリクスがすぐに表示される。

バイナリで直接インストール

# 最新バイナリをダウンロード(最新バージョンはreleasesページで確認)
wget https://github.com/grafana/beyla/releases/download/v1.8.0/beyla-linux-amd64
chmod +x beyla-linux-amd64
sudo mv beyla-linux-amd64 /usr/local/bin/beyla

# ポート8080をリッスンしているプロセスを自動検出して実行
sudo BEYLA_OPEN_PORT=8080 BEYLA_PROMETHEUS_PORT=9400 beyla

本番環境向けYAML設定ファイル

環境変数はテスト時には便利だが、本番環境ではYAML設定ファイルのほうがはるかに管理しやすい:

# /etc/beyla/config.yaml
open_port: 8080          # アプリがリッスンしているポート
service_name: my-api     # Grafanaに表示される名前

prometheus_export:
  port: 9400
  path: /metrics

# オプション:トレースをGrafana Tempoにエクスポート
otel_traces_export:
  endpoint: http://tempo:4317

# 追跡不要なパスをフィルタリング(ヘルスチェック、静的ファイル)
filters:
  application:
    - path_pattern: '/health'
      method: GET
# 設定ファイルで実行
sudo beyla --config /etc/beyla/config.yaml

Prometheusとの統合

prometheus.ymlにジョブを追加:

scrape_configs:
  - job_name: 'beyla-my-api'
    static_configs:
      - targets: ['localhost:9400']
    relabel_configs:
      - source_labels: [__address__]
        target_label: instance

systemdサービスとしてBeylaを実行

サーバーと一緒にBeylaを自動起動させるには:

# /etc/systemd/system/beyla.service
[Unit]
Description=Grafana Beyla eBPF 自動インストルメンテーション
After=network.target

[Service]
ExecStart=/usr/local/bin/beyla --config /etc/beyla/config.yaml
Restart=on-failure
User=root

[Install]
WantedBy=multi-user.target
sudo systemctl daemon-reload
sudo systemctl enable --now beyla
sudo systemctl status beyla

各言語でのBeylaの動作

内部的なメカニズムは言語によって異なるが、メトリクスの出力は統一されている:

  • Go:Beylaはuprobesを使ってコンパイル済みバイナリのnet/httpとgRPC関数にフックする。これはGoでは他のエージェントにはできないことだ。
  • Python:WSGIまたはASGIミドルウェア層にフックする(Django、Flask、FastAPIすべて対応)。
  • Node.js:V8ランタイムとhttp/httpsモジュールにフックする。

生成されるメトリクスはすべてOpenTelemetryのセマンティック規約に準拠しているため、Grafanaダッシュボードはカスタマイズなしでそのまま使える。

6ヶ月間の実際の使用結果

驚いたのはBeylaが動くということではなく、誰も触れない古いサービスでもうまく動いたということだ。2021年に書かれたGoのサービスがあり、ユニットテストもなく、チームの誰も完全に把握していない。そのサービスが今やlatencyヒストグラム、エラーレート、リクエストスループットを持つようになり、コードは一行も変更していない。

チームのメトリクスカバレッジは、各ホストにBeylaをデプロイするだけで、半日のうちに60%から100%に上がった。

オーバーヘッドについて:毎秒約500リクエストを処理するホストでCPU 1〜2%、RAM約50MBという計測結果だった。十分許容範囲内だ。

注意点として:Beylaはkernel 5.8以上とprivileged権限が必要だ。厳格なセキュリティポリシーのコンテナ環境(GKE Autopilotなど)で実行する場合は、事前に互換性を確認する必要がある。

BeylaのGrafanaダッシュボード

Grafana LabsはGrafana.comでID 19419(REDメトリクス)と19420(サービスマップ)のダッシュボードを提供している。Grafanaへのインポート手順:

  1. Grafana → Dashboards → Importに移動
  2. ID 19419を入力 → Load
  3. Prometheusデータソースを選択 → Import

インポートが完了すると、サービスマップがすぐに表示される — すべてのサービス、サービス間のトラフィック、リクエストフローが追加設定なしで表示される。エンドポイントごとのリクエストレート、エラーレート、P99レイテンシーもすべて揃っている。PromQLを一行も書く必要はない。

Share: