データベース
Prometheus
概要
Prometheusは、時系列データの収集、保存、クエリに特化したオープンソースの監視・アラートシステムです。Cloud Native Computing Foundation(CNCF)の卒業プロジェクトとして、Kubernetesエコシステムでの標準的な監視ソリューションとして確立されています。高性能な時系列データベースとして、システム・アプリケーション監視、メトリクス収集、リアルタイムアラートを統合的に提供します。
詳細
Prometheusは2012年にSoundCloudで開発が開始され、Googleの内部監視システム「Borgmon」にインスパイアされて設計されました。時系列データに最適化された独自のデータベースエンジンを持ち、Pull型のメトリクス収集、強力なクエリ言語PromQL、柔軟なアラート機能を特徴とします。
2024年11月にリリースされたPrometheus 3.0では、7年ぶりのメジャーアップデートとして、完全に新しいWebUI、UTF-8フルサポート、OpenTelemetry統合、Remote Write 2.0など大幅な機能強化が行われました。
Prometheusの主な特徴:
- 高性能な時系列データベース(TSDB)
- Pull型メトリクス収集アーキテクチャ
- 強力なクエリ言語「PromQL」
- 多次元データモデル(メトリクス名 + ラベル)
- 自動サービスディスカバリー
- アラート・通知機能(Alertmanager連携)
- Grafana等の可視化ツールとの統合
- Kubernetes・Docker・AWS等の豊富な統合
- Agent Mode(軽量なメトリクス収集専用モード)
- Native Histogram対応
- OpenTelemetry(OTLP)統合
メリット・デメリット
メリット
- クラウドネイティブ: Kubernetesでの標準的な監視ソリューション
- 高性能: 独自TSDBによる高速なデータ取り込みと検索
- 柔軟性: PromQLによる強力で柔軟なクエリ機能
- 運用性: Pull型アーキテクチャによる堅牢なメトリクス収集
- エコシステム: Grafana、Alertmanager等の豊富な連携ツール
- 自動化: サービスディスカバリーによる動的環境での自動監視
- 軽量: 単一バイナリでの簡単デプロイ
- 拡張性: Exporter・クライアントライブラリによる豊富な監視対象
デメリット
- 長期保存: 単体では長期データ保存に制限(Remote Storage必要)
- 水平スケーリング: フェデレーション・シャーディングが複雑
- HA構成: 高可用性構成の設計・運用が複雑
- 学習コスト: PromQLの習得コストが高い
- データ型: 数値データ中心(文字列・ログデータは不向き)
- セキュリティ: 認証・認可機能が基本的(外部プロキシ必要)
主要リンク
書き方の例
インストール・セットアップ
# Docker での実行(推奨)
docker run -d --name prometheus \
-p 9090:9090 \
-v ./prometheus.yml:/etc/prometheus/prometheus.yml \
prom/prometheus:latest
# バイナリでの実行
wget https://github.com/prometheus/prometheus/releases/download/v3.0.0/prometheus-3.0.0.linux-amd64.tar.gz
tar xvf prometheus-3.0.0.linux-amd64.tar.gz
cd prometheus-3.0.0.linux-amd64
./prometheus --config.file=prometheus.yml
# Kubernetes での実行(Helm)
helm repo add prometheus-community https://prometheus-community.github.io/helm-charts
helm repo update
helm install prometheus prometheus-community/kube-prometheus-stack
# Agent Mode での実行(軽量)
./prometheus --agent --config.file=prometheus.yml --storage.agent.path=./agent-data
# systemd サービス登録
sudo useradd --no-create-home --shell /bin/false prometheus
sudo mkdir /etc/prometheus /var/lib/prometheus
sudo chown prometheus:prometheus /etc/prometheus /var/lib/prometheus
sudo cp prometheus promtool /usr/local/bin/
sudo chown prometheus:prometheus /usr/local/bin/prometheus /usr/local/bin/promtool
cat > /etc/systemd/system/prometheus.service << EOF
[Unit]
Description=Prometheus
Wants=network-online.target
After=network-online.target
[Service]
User=prometheus
Group=prometheus
Type=simple
ExecStart=/usr/local/bin/prometheus \
--config.file /etc/prometheus/prometheus.yml \
--storage.tsdb.path /var/lib/prometheus/ \
--web.console.templates=/etc/prometheus/consoles \
--web.console.libraries=/etc/prometheus/console_libraries \
--web.listen-address=0.0.0.0:9090 \
--web.enable-lifecycle
[Install]
WantedBy=multi-user.target
EOF
sudo systemctl daemon-reload
sudo systemctl enable prometheus
sudo systemctl start prometheus
基本設定ファイル
# prometheus.yml
global:
scrape_interval: 15s
evaluation_interval: 15s
rule_files:
- "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: ['localhost:9100']
# アプリケーション監視
- job_name: 'myapp'
static_configs:
- targets: ['localhost:8080']
metrics_path: /metrics
scrape_interval: 10s
# Kubernetes自動発見
- job_name: 'kubernetes-pods'
kubernetes_sd_configs:
- role: pod
relabel_configs:
- source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_scrape]
action: keep
regex: true
- source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_path]
action: replace
target_label: __metrics_path__
regex: (.+)
# Docker Swarm自動発見
- job_name: 'dockerswarm'
dockerswarm_sd_configs:
- host: unix:///var/run/docker.sock
role: tasks
relabel_configs:
- source_labels: [__meta_dockerswarm_task_desired_state]
regex: running
action: keep
# OpenTelemetry統合設定(Prometheus 3.0)
otlp:
promote_resource_attributes:
- service.name
- service.instance.id
- service.namespace
- service.version
- k8s.cluster.name
- k8s.namespace.name
- k8s.pod.name
# ストレージ設定
storage:
tsdb:
retention.time: 15d
retention.size: 10GB
out_of_order_time_window: 30m # アウト・オブ・オーダーサンプル許可
PromQLクエリ
# 基本的なインスタントベクター
up
# ラベルマッチング
up{job="prometheus"}
# 時間範囲指定(Range Vector)
rate(http_requests_total[5m])
# 集約関数
sum(rate(http_requests_total[5m])) by (instance)
# CPU使用率計算
100 - (avg by(instance) (rate(node_cpu_seconds_total{mode="idle"}[5m])) * 100)
# メモリ使用率
(1 - (node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes)) * 100
# トップKクエリ
topk(5, rate(http_requests_total[5m]))
# 四則演算
rate(http_requests_total[5m]) * 60
# 条件分岐
up == 1
# 正規表現マッチング
http_requests_total{job=~"api.*"}
# 複数メトリクスの結合
rate(http_requests_total[5m]) / rate(http_request_duration_seconds_count[5m])
# しきい値超過アラート用
avg_over_time(cpu_usage[5m]) > 80
# パーセンタイル計算
histogram_quantile(0.95, rate(http_request_duration_seconds_bucket[5m]))
# 時系列の存在確認
absent(up{job="critical-service"})
# 予測クエリ
predict_linear(node_filesystem_free_bytes[1h], 4*3600) < 0
アラートルール
# rules/alerts.yml
groups:
- name: system
rules:
- 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 detected"
description: "CPU usage is above 80% for instance {{ $labels.instance }}"
- alert: HighMemoryUsage
expr: (1 - (node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes)) * 100 > 90
for: 2m
labels:
severity: critical
annotations:
summary: "High memory usage detected"
description: "Memory usage is above 90% for instance {{ $labels.instance }}"
- alert: DiskSpaceLow
expr: (node_filesystem_avail_bytes / node_filesystem_size_bytes) * 100 < 10
for: 1m
labels:
severity: critical
annotations:
summary: "Low disk space"
description: "Disk space is below 10% for {{ $labels.mountpoint }} on {{ $labels.instance }}"
- alert: ServiceDown
expr: up == 0
for: 1m
labels:
severity: critical
annotations:
summary: "Service is down"
description: "Service {{ $labels.job }} on {{ $labels.instance }} is down"
- alert: HighErrorRate
expr: rate(http_requests_total{status=~"5.."}[5m]) / rate(http_requests_total[5m]) > 0.05
for: 3m
labels:
severity: warning
annotations:
summary: "High error rate"
description: "Error rate is above 5% for {{ $labels.job }}"
- name: application
rules:
- alert: SlowResponse
expr: histogram_quantile(0.95, rate(http_request_duration_seconds_bucket[5m])) > 0.5
for: 5m
labels:
severity: warning
annotations:
summary: "Slow response time"
description: "95th percentile response time is above 500ms"
- alert: HighRequestRate
expr: rate(http_requests_total[5m]) > 1000
for: 2m
labels:
severity: info
annotations:
summary: "High request rate"
description: "Request rate is above 1000 req/s"
# keep_firing_for機能(Prometheus 3.0新機能)
- alert: TransientIssue
expr: error_rate > 0.1
for: 1m
keep_firing_for: 5m # 条件が満たされなくなっても5分間アラートを継続
labels:
severity: warning
annotations:
summary: "Transient issue detected"
Recording Rules
# rules/recording.yml
groups:
- name: cpu_recording_rules
interval: 30s
rules:
- record: instance:cpu_usage_rate
expr: 100 - (avg by(instance) (rate(node_cpu_seconds_total{mode="idle"}[5m])) * 100)
- record: job:cpu_usage_rate:avg
expr: avg by(job) (instance:cpu_usage_rate)
- name: http_recording_rules
interval: 15s
rules:
- record: job:http_requests_rate
expr: sum by(job) (rate(http_requests_total[5m]))
- record: job:http_error_rate
expr: sum by(job) (rate(http_requests_total{status=~"5.."}[5m])) / sum by(job) (rate(http_requests_total[5m]))
- record: instance:http_latency_p95
expr: histogram_quantile(0.95, sum by(instance, le) (rate(http_request_duration_seconds_bucket[5m])))
HTTP API使用例
# メトリクス一覧取得
curl http://localhost:9090/api/v1/label/__name__/values
# インスタントクエリ
curl -G http://localhost:9090/api/v1/query \
--data-urlencode 'query=up'
# 範囲クエリ
curl -G http://localhost:9090/api/v1/query_range \
--data-urlencode 'query=rate(http_requests_total[5m])' \
--data-urlencode 'start=2024-01-01T00:00:00Z' \
--data-urlencode 'end=2024-01-01T01:00:00Z' \
--data-urlencode 'step=60s'
# ラベル値取得
curl http://localhost:9090/api/v1/label/job/values
# シリーズメタデータ
curl -G http://localhost:9090/api/v1/series \
--data-urlencode 'match[]=up'
# アラート一覧
curl http://localhost:9090/api/v1/alerts
# ルール一覧
curl http://localhost:9090/api/v1/rules
# 設定情報
curl http://localhost:9090/api/v1/status/config
# ビルド情報
curl http://localhost:9090/api/v1/status/buildinfo
# TSDBステータス
curl http://localhost:9090/api/v1/status/tsdb
# 設定リロード(--web.enable-lifecycle必要)
curl -X POST http://localhost:9090/-/reload
# ヘルスチェック
curl http://localhost:9090/-/healthy
# レディネスチェック
curl http://localhost:9090/-/ready
クライアントライブラリ(Go)
package main
import (
"log"
"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"},
)
// Gauge - 現在値(CPU使用率、メモリ使用量等)
cpuUsage = promauto.NewGaugeVec(
prometheus.GaugeOpts{
Name: "cpu_usage_percent",
Help: "Current CPU usage percentage",
},
[]string{"core"},
)
// Histogram - 分布(レスポンス時間、リクエストサイズ等)
httpDuration = promauto.NewHistogramVec(
prometheus.HistogramOpts{
Name: "http_request_duration_seconds",
Help: "Duration of HTTP requests",
Buckets: prometheus.DefBuckets,
},
[]string{"method", "endpoint"},
)
// Summary - 分位数(レスポンス時間の分位数等)
httpSummary = promauto.NewSummaryVec(
prometheus.SummaryOpts{
Name: "http_request_duration_summary",
Help: "Summary of HTTP request durations",
Objectives: map[float64]float64{0.5: 0.05, 0.9: 0.01, 0.99: 0.001},
},
[]string{"method"},
)
)
func httpHandler(w http.ResponseWriter, r *http.Request) {
start := time.Now()
// Counter増加
httpRequestsTotal.WithLabelValues(r.Method, r.URL.Path, "200").Inc()
// 処理時間記録
duration := time.Since(start).Seconds()
httpDuration.WithLabelValues(r.Method, r.URL.Path).Observe(duration)
httpSummary.WithLabelValues(r.Method).Observe(duration)
w.WriteHeader(http.StatusOK)
w.Write([]byte("Hello World"))
}
func main() {
// CPUモニタリングのサンプル
go func() {
for {
// 実際のCPU使用率取得ロジック
cpuUsage.WithLabelValues("0").Set(45.2)
cpuUsage.WithLabelValues("1").Set(67.8)
time.Sleep(10 * time.Second)
}
}()
http.HandleFunc("/", httpHandler)
http.Handle("/metrics", promhttp.Handler())
log.Println("Server starting on :8080")
log.Fatal(http.ListenAndServe(":8080", nil))
}
Python クライアント
from prometheus_client import Counter, Gauge, Histogram, Summary, start_http_server
import time
import random
# メトリクス定義
REQUEST_COUNT = Counter('http_requests_total', 'Total HTTP requests', ['method', 'endpoint'])
CPU_USAGE = Gauge('cpu_usage_percent', 'CPU usage percentage', ['core'])
REQUEST_DURATION = Histogram('http_request_duration_seconds', 'HTTP request duration')
RESPONSE_SIZE = Summary('http_response_size_bytes', 'HTTP response size')
def process_request():
"""リクエスト処理のシミュレーション"""
start_time = time.time()
# ランダムな処理時間
time.sleep(random.uniform(0.1, 0.5))
# メトリクス更新
REQUEST_COUNT.labels(method='GET', endpoint='/api').inc()
REQUEST_DURATION.observe(time.time() - start_time)
RESPONSE_SIZE.observe(random.randint(100, 1000))
def update_system_metrics():
"""システムメトリクスの更新"""
while True:
# CPU使用率のシミュレーション
CPU_USAGE.labels(core='0').set(random.uniform(20, 80))
CPU_USAGE.labels(core='1').set(random.uniform(20, 80))
time.sleep(10)
if __name__ == '__main__':
# メトリクスサーバー開始
start_http_server(8000)
# システムメトリクス更新スレッド開始
import threading
threading.Thread(target=update_system_metrics, daemon=True).start()
# リクエスト処理シミュレーション
while True:
process_request()
time.sleep(1)
Node Exporter設定
# Node Exporter インストール
wget https://github.com/prometheus/node_exporter/releases/download/v1.7.0/node_exporter-1.7.0.linux-amd64.tar.gz
tar xvf node_exporter-1.7.0.linux-amd64.tar.gz
cd node_exporter-1.7.0.linux-amd64
# 実行
./node_exporter
# サービス登録
sudo useradd --no-create-home --shell /bin/false node_exporter
sudo cp node_exporter /usr/local/bin/
sudo chown node_exporter:node_exporter /usr/local/bin/node_exporter
cat > /etc/systemd/system/node_exporter.service << EOF
[Unit]
Description=Node Exporter
Wants=network-online.target
After=network-online.target
[Service]
User=node_exporter
Group=node_exporter
Type=simple
ExecStart=/usr/local/bin/node_exporter \
--collector.systemd \
--collector.processes \
--web.listen-address=:9100
[Install]
WantedBy=multi-user.target
EOF
sudo systemctl daemon-reload
sudo systemctl enable node_exporter
sudo systemctl start node_exporter
# カスタムメトリクス(textfile collector)
mkdir -p /var/lib/node_exporter/textfile_collector
# カスタムメトリクス作成スクリプト
cat > /usr/local/bin/custom_metrics.sh << 'EOF'
#!/bin/bash
echo "# HELP custom_disk_usage Custom disk usage metric
# TYPE custom_disk_usage gauge" > /var/lib/node_exporter/textfile_collector/custom.prom
df -h | grep '^/dev/' | awk '{print "custom_disk_usage{device=\""$1"\",mountpoint=\""$6"\"} " ($5+0)/100}' >> /var/lib/node_exporter/textfile_collector/custom.prom
EOF
chmod +x /usr/local/bin/custom_metrics.sh
# cron設定
echo "*/5 * * * * /usr/local/bin/custom_metrics.sh" | crontab -
Remote Storage設定
# Remote Write設定(長期保存用)
remote_write:
- url: "https://cortex.example.com/api/v1/push"
basic_auth:
username: user
password: pass
queue_config:
max_samples_per_send: 2000
batch_send_deadline: 5s
max_retries: 3
metadata_config:
send: true
# Grafana Cloud
- url: "https://prometheus-prod-01-eu-west-0.grafana.net/api/prom/push"
basic_auth:
username: "123456"
password: "YOUR_API_KEY"
# Remote Read設定
remote_read:
- url: "https://cortex.example.com/api/v1/read"
basic_auth:
username: user
password: pass
Alertmanager設定
# alertmanager.yml
global:
smtp_smarthost: 'smtp.gmail.com:587'
smtp_from: '[email protected]'
smtp_auth_username: '[email protected]'
smtp_auth_password: 'password'
route:
group_by: ['alertname']
group_wait: 10s
group_interval: 10s
repeat_interval: 1h
receiver: 'web.hook'
routes:
- match:
severity: critical
receiver: 'critical-alerts'
- match:
severity: warning
receiver: 'warning-alerts'
receivers:
- name: 'web.hook'
webhook_configs:
- url: 'http://localhost:5001/webhook'
- name: 'critical-alerts'
email_configs:
- to: '[email protected]'
subject: 'Critical Alert: {{ .GroupLabels.alertname }}'
body: |
{{ range .Alerts }}
Alert: {{ .Annotations.summary }}
Description: {{ .Annotations.description }}
{{ end }}
slack_configs:
- api_url: 'YOUR_SLACK_WEBHOOK_URL'
channel: '#critical-alerts'
title: 'Critical Alert'
text: '{{ range .Alerts }}{{ .Annotations.summary }}{{ end }}'
- name: 'warning-alerts'
slack_configs:
- api_url: 'YOUR_SLACK_WEBHOOK_URL'
channel: '#alerts'
title: 'Warning Alert'
運用・最適化
# データベースサイズ確認
du -sh /var/lib/prometheus/
# TSDBブロック情報
promtool tsdb list /var/lib/prometheus/
# 設定ファイル検証
promtool check config prometheus.yml
# ルールファイル検証
promtool check rules rules/*.yml
# メトリクス削除
curl -X POST http://localhost:9090/api/v1/admin/tsdb/delete_series \
--data-urlencode 'match[]=up{job="old-job"}'
# スナップショット作成
curl -X POST http://localhost:9090/api/v1/admin/tsdb/snapshot
# バックアップ
tar czf prometheus-backup-$(date +%Y%m%d).tar.gz /var/lib/prometheus/
# パフォーマンス監視用クエリ
# メモリ使用量
process_resident_memory_bytes{job="prometheus"}
# 取り込み率
rate(prometheus_tsdb_symbol_table_size_bytes[5m])
# チャンク数
prometheus_tsdb_head_chunks
# WALサイズ
prometheus_tsdb_wal_storage_size_bytes