Prometheus

Kubernetesとクラウドネイティブ環境の事実上の標準監視システム。多次元データモデルとPromQLクエリ言語を提供し、HTTPプルモデルでメトリクスを収集。

監視サーバーメトリクス収集時系列データベースPromQLKubernetesCNCFオープンソース

監視サーバー

Prometheus

概要

Prometheusは、Kubernetesとクラウドネイティブ環境の事実上の標準監視システムです。多次元データモデルとPromQLクエリ言語を提供し、HTTPプルモデルでメトリクスを収集する時系列データベースです。SoundCloudで開発され、現在はCloud Native Computing Foundation(CNCF)の卒業プロジェクトとして、コンテナ化された環境でのアプリケーション監視に最適化されています。

詳細

Prometheusは2012年にSoundCloudで開発が開始され、2016年にCNCFの2番目の卒業プロジェクトとなりました。現在では採用率79%でKubernetes監視の事実上の標準となっており、2024年には7年ぶりのメジャーリリースであるPrometheus 3.0がリリースされ、OpenTelemetry統合が強化されました。

主要な技術的特徴

  • 多次元データモデル: ラベルによる柔軟なメトリクス分類
  • PromQLクエリ言語: 強力な時系列データクエリ機能
  • HTTPプルモデル: スケーラブルなメトリクス収集方式
  • Service Discovery: 動的な監視対象の自動発見
  • Alertmanager連携: 柔軟なアラート管理機能

用途

  • Kubernetesクラスター監視
  • マイクロサービス監視
  • アプリケーション性能監視(APM)
  • インフラストラクチャ監視
  • SLI/SLO管理

メリット・デメリット

メリット

  • Kubernetes標準: K8s環境での事実上の標準監視システム
  • 柔軟なクエリ: PromQLによる強力な分析機能
  • スケーラビリティ: 大規模環境での高いパフォーマンス
  • 豊富なエコシステム: 多数のExporterとサードパーティツール
  • オープンソース: 無料で高機能な監視システム
  • Cloud Native対応: コンテナ環境に最適化された設計

デメリット

  • 学習コスト: PromQLの習得が必要
  • 長期保存の制限: デフォルトでは長期データ保存に制限
  • 高可用性設定の複雑さ: HA構成の設定が複雑
  • リソース消費: 大量メトリクス収集時の高いリソース消費
  • ダッシュボード機能: 可視化にはGrafana等の別ツールが必要

参考ページ

書き方の例

基本的なPrometheus設定

# prometheus.yml
global:
  scrape_interval: 15s
  evaluation_interval: 15s
  external_labels:
    monitor: 'prometheus-monitor'

rule_files:
  - "alert_rules.yml"
  - "recording_rules.yml"

alerting:
  alertmanagers:
    - static_configs:
        - targets:
          - alertmanager:9093

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

  # Node Exporter
  - job_name: 'node'
    static_configs:
      - targets:
        - 'node1:9100'
        - 'node2:9100'
        - 'node3:9100'

  # Kubernetes API Server
  - job_name: 'kubernetes-apiservers'
    kubernetes_sd_configs:
      - role: endpoints
    scheme: https
    tls_config:
      ca_file: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt
    bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token
    relabel_configs:
      - source_labels: [__meta_kubernetes_namespace, __meta_kubernetes_service_name, __meta_kubernetes_endpoint_port_name]
        action: keep
        regex: default;kubernetes;https

  # Application monitoring
  - job_name: 'spring-boot-app'
    metrics_path: '/actuator/prometheus'
    static_configs:
      - targets:
        - 'app1:8080'
        - 'app2:8080'

PromQLクエリ例

# 基本的なメトリクス取得
up

# 特定のジョブの稼働状況
up{job="node"}

# レート計算(5分間の平均レート)
rate(http_requests_total[5m])

# 集計関数の使用
sum(rate(http_requests_total[5m])) by (job)

# パーセンタイル計算
histogram_quantile(0.95, rate(http_request_duration_seconds_bucket[5m]))

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

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

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

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

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

アラートルール設定

# alert_rules.yml
groups:
  - name: basic.rules
    rules:
      # インスタンスダウン
      - alert: InstanceDown
        expr: up == 0
        for: 1m
        labels:
          severity: critical
        annotations:
          summary: "Instance {{ $labels.instance }} down"
          description: "{{ $labels.instance }} of job {{ $labels.job }} has been down for more than 1 minute."

      # 高CPU使用率
      - alert: HighCPUUsage
        expr: 100 - (avg by(instance) (rate(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 above 80% for more than 5 minutes on {{ $labels.instance }}"

      # 高メモリ使用率
      - 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 above 90% on {{ $labels.instance }}"

      # ディスク容量不足
      - alert: DiskSpaceLow
        expr: 100 - ((node_filesystem_avail_bytes * 100) / node_filesystem_size_bytes) > 85
        for: 5m
        labels:
          severity: warning
        annotations:
          summary: "Disk space low on {{ $labels.instance }}"
          description: "Disk usage is above 85% on {{ $labels.instance }}"

      # HTTPエラー率
      - alert: HighErrorRate
        expr: rate(http_requests_total{status=~"5.."}[5m]) / rate(http_requests_total[5m]) * 100 > 5
        for: 5m
        labels:
          severity: critical
        annotations:
          summary: "High error rate on {{ $labels.instance }}"
          description: "Error rate is above 5% for more than 5 minutes"

Recording Rules設定

# recording_rules.yml
groups:
  - name: cpu_memory_rules
    interval: 30s
    rules:
      # CPU使用率の記録ルール
      - record: instance:cpu_usage:rate5m
        expr: 100 - (avg by(instance) (rate(node_cpu_seconds_total{mode="idle"}[5m])) * 100)

      # メモリ使用率の記録ルール
      - record: instance:memory_usage:ratio
        expr: (1 - (node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes)) * 100

  - name: http_rules
    interval: 30s
    rules:
      # HTTPリクエストレートの記録ルール
      - record: job:http_requests:rate5m
        expr: sum(rate(http_requests_total[5m])) by (job)

      # HTTPエラー率の記録ルール
      - record: job:http_errors:rate5m
        expr: sum(rate(http_requests_total{status=~"5.."}[5m])) by (job) / sum(rate(http_requests_total[5m])) by (job)

Kubernetes環境でのDeployment

# prometheus-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: prometheus
  namespace: monitoring
spec:
  replicas: 1
  selector:
    matchLabels:
      app: prometheus
  template:
    metadata:
      labels:
        app: prometheus
    spec:
      serviceAccountName: prometheus
      containers:
      - name: prometheus
        image: prom/prometheus:v2.45.0
        args:
          - '--config.file=/etc/prometheus/prometheus.yml'
          - '--storage.tsdb.path=/prometheus/'
          - '--web.console.libraries=/etc/prometheus/console_libraries'
          - '--web.console.templates=/etc/prometheus/consoles'
          - '--storage.tsdb.retention.time=30d'
          - '--web.enable-lifecycle'
          - '--web.enable-admin-api'
        ports:
        - containerPort: 9090
        resources:
          limits:
            memory: "2Gi"
            cpu: "1000m"
          requests:
            memory: "1Gi"
            cpu: "500m"
        volumeMounts:
        - name: prometheus-config
          mountPath: /etc/prometheus/
        - name: prometheus-storage
          mountPath: /prometheus/
      volumes:
      - name: prometheus-config
        configMap:
          name: prometheus-config
      - name: prometheus-storage
        persistentVolumeClaim:
          claimName: prometheus-pvc

---
apiVersion: v1
kind: Service
metadata:
  name: prometheus
  namespace: monitoring
spec:
  selector:
    app: prometheus
  ports:
    - port: 9090
      targetPort: 9090
  type: ClusterIP

カスタムメトリクス(Go言語例)

package main

import (
    "net/http"
    "time"

    "github.com/prometheus/client_golang/prometheus"
    "github.com/prometheus/client_golang/prometheus/promhttp"
    "github.com/prometheus/client_golang/prometheus/promauto"
)

var (
    // Counter メトリクス
    httpRequestsTotal = promauto.NewCounterVec(
        prometheus.CounterOpts{
            Name: "http_requests_total",
            Help: "Total number of HTTP requests",
        },
        []string{"method", "endpoint", "status"},
    )

    // Histogram メトリクス
    httpDuration = promauto.NewHistogramVec(
        prometheus.HistogramOpts{
            Name: "http_request_duration_seconds",
            Help: "Duration of HTTP requests",
            Buckets: prometheus.DefBuckets,
        },
        []string{"method", "endpoint"},
    )

    // Gauge メトリクス
    activeConnections = promauto.NewGauge(
        prometheus.GaugeOpts{
            Name: "active_connections",
            Help: "Number of active connections",
        },
    )
)

func recordMetrics() {
    go func() {
        for {
            activeConnections.Set(float64(time.Now().Unix() % 100))
            time.Sleep(2 * time.Second)
        }
    }()
}

func main() {
    recordMetrics()

    http.Handle("/metrics", promhttp.Handler())
    http.HandleFunc("/api/users", func(w http.ResponseWriter, r *http.Request) {
        timer := prometheus.NewTimer(httpDuration.WithLabelValues(r.Method, "/api/users"))
        defer timer.ObserveDuration()

        // ビジネスロジック処理
        time.Sleep(100 * time.Millisecond)

        httpRequestsTotal.WithLabelValues(r.Method, "/api/users", "200").Inc()
        w.WriteHeader(http.StatusOK)
        w.Write([]byte("OK"))
    })

    http.ListenAndServe(":8080", nil)
}