Grafana監視ダッシュボード構築ガイド - Prometheus連携とアラート設定


Grafanaは、メトリクスやログを可視化するオープンソースの監視プラットフォームです。Prometheusと組み合わせることで、システムの状態をリアルタイムで監視し、問題を早期発見できます。本記事では、Grafanaの導入から実践的なダッシュボード構築まで解説します。

Grafanaとは

Grafanaは、時系列データを美しく可視化するダッシュボードツールです。

主な特徴

  • 多様なデータソース対応: Prometheus、MySQL、PostgreSQL、Elasticsearch等
  • リアルタイム可視化: メトリクスを即座にグラフ化
  • 柔軟なダッシュボード: ドラッグ&ドロップで簡単作成
  • アラート機能: 閾値超過時に通知
  • 無料・オープンソース: 商用利用も可能

ユースケース

  • インフラ監視(CPU、メモリ、ディスク)
  • アプリケーションパフォーマンス監視
  • ビジネスメトリクス可視化
  • ログ分析
  • IoTデータ可視化

Prometheusとは

Prometheusは、メトリクス収集・保存に特化した時系列データベースです。

主な特徴

  • Pull型アーキテクチャ: 定期的にメトリクスを取得
  • 多次元データモデル: ラベルで柔軟にフィルタリング
  • PromQL: 強力なクエリ言語
  • サービスディスカバリ: 動的な監視対象検出

アーキテクチャ

┌─────────────┐     ┌──────────────┐     ┌─────────────┐
│ Application │────→│  Prometheus  │────→│   Grafana   │
│  (Exporter) │     │   (Storage)  │     │ (Visualize) │
└─────────────┘     └──────────────┘     └─────────────┘


                    ┌──────────────┐
                    │  Alertmanager│
                    └──────────────┘

環境構築

Docker Composeで一括セットアップ

# docker-compose.yml
version: '3.8'

services:
  prometheus:
    image: prom/prometheus:latest
    container_name: prometheus
    ports:
      - "9090:9090"
    volumes:
      - ./prometheus/prometheus.yml:/etc/prometheus/prometheus.yml
      - prometheus-data:/prometheus
    command:
      - '--config.file=/etc/prometheus/prometheus.yml'
      - '--storage.tsdb.path=/prometheus'
      - '--web.console.libraries=/usr/share/prometheus/console_libraries'
      - '--web.console.templates=/usr/share/prometheus/consoles'

  grafana:
    image: grafana/grafana:latest
    container_name: grafana
    ports:
      - "3000:3000"
    volumes:
      - grafana-data:/var/lib/grafana
      - ./grafana/provisioning:/etc/grafana/provisioning
    environment:
      - GF_SECURITY_ADMIN_PASSWORD=admin
      - GF_USERS_ALLOW_SIGN_UP=false

  node-exporter:
    image: prom/node-exporter:latest
    container_name: node-exporter
    ports:
      - "9100:9100"
    command:
      - '--path.rootfs=/host'
    volumes:
      - '/:/host:ro,rslave'

volumes:
  prometheus-data:
  grafana-data:

Prometheus設定

# prometheus/prometheus.yml
global:
  scrape_interval: 15s
  evaluation_interval: 15s

scrape_configs:
  # Prometheus自身を監視
  - job_name: 'prometheus'
    static_configs:
      - targets: ['localhost:9090']

  # Node Exporter(サーバーメトリクス)
  - job_name: 'node'
    static_configs:
      - targets: ['node-exporter:9100']

  # カスタムアプリケーション
  - job_name: 'my-app'
    static_configs:
      - targets: ['my-app:8080']

起動

# Docker Composeで起動
docker-compose up -d

# アクセス確認
# Prometheus: http://localhost:9090
# Grafana: http://localhost:3000 (admin/admin)

Grafanaの初期設定

1. ログイン

URL: http://localhost:3000
Username: admin
Password: admin

初回ログイン後、パスワード変更を求められます。

2. データソース追加

1. 左メニュー「Configuration」→「Data Sources」
2. 「Add data source」
3. 「Prometheus」を選択
4. URL: http://prometheus:9090
5. 「Save & Test」

3. ダッシュボードインポート

1. 左メニュー「+」→「Import」
2. Grafana.comのダッシュボードIDを入力
   - Node Exporter Full: 1860
   - Docker Monitoring: 893
3. 「Load」→データソース選択→「Import」

メトリクスの可視化

基本的なパネル作成

1. 「+」→「Dashboard」→「Add new panel」
2. Query設定:
   - Metric: up
   - Legend: {{job}}
3. Visualization設定:
   - Type: Time series
   - Title: Service Uptime
4. 「Apply」で保存

PromQLクエリ例

# CPU使用率
100 - (avg by (instance) (irate(node_cpu_seconds_total{mode="idle"}[5m])) * 100)

# メモリ使用率
(1 - (node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes)) * 100

# ディスク使用率
(1 - (node_filesystem_avail_bytes / node_filesystem_size_bytes)) * 100

# HTTPリクエスト数(5分間の平均)
rate(http_requests_total[5m])

# レスポンスタイム(95パーセンタイル)
histogram_quantile(0.95, rate(http_request_duration_seconds_bucket[5m]))

# エラー率
rate(http_requests_total{status=~"5.."}[5m]) / rate(http_requests_total[5m])

ダッシュボード例:システム監視

{
  "dashboard": {
    "title": "System Overview",
    "panels": [
      {
        "title": "CPU Usage",
        "targets": [
          {
            "expr": "100 - (avg by (instance) (irate(node_cpu_seconds_total{mode=\"idle\"}[5m])) * 100)"
          }
        ],
        "type": "timeseries"
      },
      {
        "title": "Memory Usage",
        "targets": [
          {
            "expr": "(1 - (node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes)) * 100"
          }
        ],
        "type": "gauge"
      },
      {
        "title": "Disk I/O",
        "targets": [
          {
            "expr": "rate(node_disk_read_bytes_total[5m])",
            "legendFormat": "Read"
          },
          {
            "expr": "rate(node_disk_written_bytes_total[5m])",
            "legendFormat": "Write"
          }
        ],
        "type": "timeseries"
      }
    ]
  }
}

アプリケーションの監視

Node.jsアプリケーションのメトリクス公開

npm install prom-client express
// server.js
const express = require('express');
const client = require('prom-client');

const app = express();
const register = new client.Registry();

// デフォルトメトリクス(CPU、メモリ等)を収集
client.collectDefaultMetrics({ register });

// カスタムメトリクス
const httpRequestDuration = new client.Histogram({
  name: 'http_request_duration_seconds',
  help: 'Duration of HTTP requests in seconds',
  labelNames: ['method', 'route', 'status'],
  buckets: [0.1, 0.3, 0.5, 0.7, 1, 3, 5, 7, 10],
});

const httpRequestCounter = new client.Counter({
  name: 'http_requests_total',
  help: 'Total number of HTTP requests',
  labelNames: ['method', 'route', 'status'],
});

register.registerMetric(httpRequestDuration);
register.registerMetric(httpRequestCounter);

// ミドルウェア
app.use((req, res, next) => {
  const start = Date.now();

  res.on('finish', () => {
    const duration = (Date.now() - start) / 1000;
    const labels = {
      method: req.method,
      route: req.route?.path || req.path,
      status: res.statusCode,
    };

    httpRequestDuration.observe(labels, duration);
    httpRequestCounter.inc(labels);
  });

  next();
});

// メトリクスエンドポイント
app.get('/metrics', async (req, res) => {
  res.set('Content-Type', register.contentType);
  res.end(await register.metrics());
});

// アプリケーションのルート
app.get('/', (req, res) => {
  res.send('Hello World');
});

app.listen(8080, () => {
  console.log('Server running on port 8080');
});

Prometheusに追加

# prometheus/prometheus.yml
scrape_configs:
  - job_name: 'node-app'
    static_configs:
      - targets: ['host.docker.internal:8080']

Grafanaで可視化

# リクエスト数(1分あたり)
sum(rate(http_requests_total[1m])) by (route)

# 平均レスポンスタイム
avg(rate(http_request_duration_seconds_sum[5m]) / rate(http_request_duration_seconds_count[5m]))

# エラー率
sum(rate(http_requests_total{status=~"5.."}[5m])) / sum(rate(http_requests_total[5m])) * 100

アラート設定

Grafana Alertの作成

1. ダッシュボードのパネルを編集
2. 「Alert」タブを選択
3. 「Create Alert」

条件設定:
- WHEN: avg()
- OF: query(A, 5m, now)
- IS ABOVE: 80

通知設定:
- Send to: Email / Slack / PagerDuty
- Message: CPU使用率が80%を超えています

Prometheus Alertmanager

# alertmanager/config.yml
global:
  smtp_smarthost: 'smtp.gmail.com:587'
  smtp_from: 'alerts@example.com'
  smtp_auth_username: 'your-email@gmail.com'
  smtp_auth_password: 'your-password'

route:
  group_by: ['alertname']
  group_wait: 30s
  group_interval: 5m
  repeat_interval: 12h
  receiver: 'email'

receivers:
  - name: 'email'
    email_configs:
      - to: 'admin@example.com'
        headers:
          Subject: 'Alert: {{ .GroupLabels.alertname }}'

Prometheusアラートルール

# prometheus/alerts.yml
groups:
  - name: system
    rules:
      - alert: HighCPUUsage
        expr: 100 - (avg by (instance) (irate(node_cpu_seconds_total{mode="idle"}[5m])) * 100) > 80
        for: 5m
        labels:
          severity: warning
        annotations:
          summary: "High CPU usage on {{ $labels.instance }}"
          description: "CPU usage is {{ $value }}%"

      - alert: HighMemoryUsage
        expr: (1 - (node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes)) * 100 > 90
        for: 5m
        labels:
          severity: critical
        annotations:
          summary: "High memory usage on {{ $labels.instance }}"
          description: "Memory usage is {{ $value }}%"

      - alert: DiskSpaceLow
        expr: (1 - (node_filesystem_avail_bytes / node_filesystem_size_bytes)) * 100 > 85
        for: 10m
        labels:
          severity: warning
        annotations:
          summary: "Disk space low on {{ $labels.instance }}"
          description: "Disk usage is {{ $value }}%"
# prometheus/prometheus.yml
rule_files:
  - 'alerts.yml'

alerting:
  alertmanagers:
    - static_configs:
        - targets: ['alertmanager:9093']

ログ分析(Loki連携)

Loki + Promtail追加

# docker-compose.yml
services:
  loki:
    image: grafana/loki:latest
    ports:
      - "3100:3100"
    volumes:
      - ./loki/loki-config.yml:/etc/loki/local-config.yaml
    command: -config.file=/etc/loki/local-config.yaml

  promtail:
    image: grafana/promtail:latest
    volumes:
      - /var/log:/var/log
      - ./promtail/promtail-config.yml:/etc/promtail/config.yml
    command: -config.file=/etc/promtail/config.yml

Grafanaにログデータソース追加

1. Configuration → Data Sources → Add data source
2. Loki を選択
3. URL: http://loki:3100
4. Save & Test

ログクエリ例

# エラーログ検索
{job="my-app"} |= "error"

# 特定のステータスコードを含むログ
{job="nginx"} | json | status="500"

# ログの集計(1分間のエラー数)
sum(count_over_time({job="my-app"} |= "error" [1m]))

ダッシュボード設計のベストプラクティス

1. レイアウト設計

┌─────────────────────────────────────────┐
│  タイトル: Production System Overview  │
├─────────────────────────────────────────┤
│  [CPU]  [Memory]  [Disk]  [Network]     │  ← Stat/Gauge
├─────────────────────────────────────────┤
│  Request Rate (Time Series)             │
├─────────────────────────────────────────┤
│  Response Time (Heatmap)                │
├─────────────────────────────────────────┤
│  [Error Log]        [Access Log]        │  ← Logs
└─────────────────────────────────────────┘

2. 変数の活用

Settings → Variables → Add variable

Name: instance
Type: Query
Query: label_values(node_cpu_seconds_total, instance)

パネルで使用:
node_cpu_seconds_total{instance="$instance"}

3. カラー設定

緑: 正常(< 70%)
黄: 注意(70-85%)
赤: 危険(> 85%)

まとめ

Grafana + Prometheusによる監視システムは以下の点で優れています。

メリット:

  • リアルタイム可視化
  • 柔軟なクエリ言語(PromQL)
  • 多様なデータソース対応
  • 無料・オープンソース
  • アラート機能充実

構成要素:

  • Grafana: 可視化
  • Prometheus: メトリクス収集・保存
  • Alertmanager: アラート通知
  • Loki: ログ集約

ベストプラクティス:

  • メトリクスは15秒〜1分間隔で収集
  • アラートは適切な閾値と待機時間を設定
  • ダッシュボードは役割別に分ける
  • 変数を活用して柔軟なダッシュボードを構築

本格的な監視システムを構築して、システムの健全性を保ちましょう。

参考リンク: