PrometheusとGrafanaで本番監視スタックを構築
監視は信頼性の高いインフラの要です。このチュートリアルでは、メトリクス収集にPrometheus、可視化にGrafanaを使用した完全なオブザーバビリティスタックをDocker Composeで構築します。
構築するもの
- 複数ターゲットからメトリクスを収集するPrometheusサーバー
- リアルタイム可視化のGrafanaダッシュボード
- システムメトリクス(CPU、メモリ、ディスク)用のNode Exporter
- カスタムメトリクス付きサンプルPythonアプリ
- Slack通知付きAlertmanager
- DockerとDocker Composeがインストール済み
- YAML設定の基本的な理解
- Slack Webhook URL(オプション、アラート用)
前提条件
---
ステップ1:プロジェクト構造
プロジェクトディレクトリを作成します:
mkdir monitoring-stack && cd monitoring-stack
mkdir -p prometheus grafana/provisioning/datasources grafana/provisioning/dashboards alertmanager app
最終構造:
monitoring-stack/
├── docker-compose.yml
├── prometheus/
│ ├── prometheus.yml
│ └── alert.rules.yml
├── grafana/
│ └── provisioning/
│ ├── datasources/
│ │ └── prometheus.yml
│ └── dashboards/
│ ├── dashboard.yml
│ └── node-exporter.json
├── alertmanager/
│ └── alertmanager.yml
└── app/
├── app.py
├── requirements.txt
└── Dockerfile
---
ステップ2:Docker Compose設定
docker-compose.ymlを作成します:
version: '3.8'
services:
prometheus:
image: prom/prometheus:v2.51.0
container_name: prometheus
ports:
- "9090:9090"
volumes:
- ./prometheus/prometheus.yml:/etc/prometheus/prometheus.yml
- ./prometheus/alert.rules.yml:/etc/prometheus/alert.rules.yml
- prometheus_data:/prometheus
command:
- '--config.file=/etc/prometheus/prometheus.yml'
- '--storage.tsdb.path=/prometheus'
- '--storage.tsdb.retention.time=30d'
- '--web.enable-lifecycle'
restart: unless-stopped
networks:
- monitoring
grafana:
image: grafana/grafana:10.3.1
container_name: grafana
ports:
- "3000:3000"
environment:
- GF_SECURITY_ADMIN_USER=admin
- GF_SECURITY_ADMIN_PASSWORD=changeme
- GF_USERS_ALLOW_SIGN_UP=false
volumes:
- grafana_data:/var/lib/grafana
- ./grafana/provisioning:/etc/grafana/provisioning
restart: unless-stopped
networks:
- monitoring
node-exporter:
image: prom/node-exporter:v1.7.0
container_name: node-exporter
ports:
- "9100:9100"
volumes:
- /proc:/host/proc:ro
- /sys:/host/sys:ro
- /:/rootfs:ro
command:
- '--path.procfs=/host/proc'
- '--path.rootfs=/rootfs'
- '--path.sysfs=/host/sys'
- '--collector.filesystem.mount-points-exclude=^/(sys|proc|dev|host|etc)($$|/)'
restart: unless-stopped
networks:
- monitoring
alertmanager:
image: prom/alertmanager:v0.27.0
container_name: alertmanager
ports:
- "9093:9093"
volumes:
- ./alertmanager/alertmanager.yml:/etc/alertmanager/alertmanager.yml
restart: unless-stopped
networks:
- monitoring
sample-app:
build: ./app
container_name: sample-app
ports:
- "8000:8000"
restart: unless-stopped
networks:
- monitoring
volumes:
prometheus_data:
grafana_data:
networks:
monitoring:
driver: bridge
---
ステップ3:Prometheus設定
prometheus/prometheus.ymlを作成します:
global:
scrape_interval: 15s
evaluation_interval: 15s
alerting:
alertmanagers:
- static_configs:
- targets:
- alertmanager:9093
rule_files:
- "alert.rules.yml"
scrape_configs:
- job_name: 'prometheus'
static_configs:
- targets: ['localhost:9090']
- job_name: 'node-exporter'
static_configs:
- targets: ['node-exporter:9100']
- job_name: 'sample-app'
static_configs:
- targets: ['sample-app:8000']
アラートルール prometheus/alert.rules.ymlを作成:
groups:
- name: system_alerts
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: "{{ $labels.instance }}でCPU使用率が高い"
description: "CPU使用率が5分以上80%を超えています(現在: {{ $value }}%)"
- alert: TargetDown
expr: up == 0
for: 1m
labels:
severity: critical
annotations:
summary: "ターゲット{{ $labels.instance }}がダウンしています"
---
ステップ4:カスタムメトリクス付きPythonアプリ
app/app.pyを作成します:
import time
import random
from flask import Flask, Response
from prometheus_client import (
Counter, Histogram, Gauge,
generate_latest, CONTENT_TYPE_LATEST
)
app = Flask(__name__)
# カスタムメトリクスの定義
REQUEST_COUNT = Counter(
'http_requests_total',
'HTTPリクエスト総数',
['method', 'endpoint', 'status']
)
REQUEST_DURATION = Histogram(
'http_request_duration_seconds',
'HTTPリクエスト処理時間(秒)',
['method', 'endpoint'],
buckets=[0.01, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0]
)
ACTIVE_REQUESTS = Gauge(
'http_active_requests',
'アクティブなHTTPリクエスト数'
)
def track_request(method, endpoint):
"""リクエストメトリクスを追跡するデコレータ"""
def decorator(f):
def wrapper(args, *kwargs):
ACTIVE_REQUESTS.inc()
start_time = time.time()
try:
result = f(args, *kwargs)
status = 200
return result
except Exception:
status = 500
raise
finally:
duration = time.time() - start_time
REQUEST_COUNT.labels(method, endpoint, status).inc()
REQUEST_DURATION.labels(method, endpoint).observe(duration)
ACTIVE_REQUESTS.dec()
wrapper.__name__ = f.__name__
return wrapper
return decorator
@app.route('/')
@track_request('GET', '/')
def home():
time.sleep(random.uniform(0.01, 0.1))
return {'status': 'ok', 'message': '監視対象アプリからこんにちは!'}
@app.route('/metrics')
def metrics():
return Response(generate_latest(), mimetype=CONTENT_TYPE_LATEST)
if __name__ == '__main__':
app.run(host='0.0.0.0', port=8000)
---
ステップ5:起動とテスト
# スタック全体を起動
docker compose up -d
# サービス状態を確認
docker compose ps
# サンプルアプリにトラフィックを生成
for i in $(seq 1 50); do
curl -s http://localhost:8000/ > /dev/null
done
# メトリクスを確認
curl http://localhost:8000/metrics
アクセス先:
---
ステップ6:便利なPromQLクエリ
# 1秒あたりのリクエストレート
rate(http_requests_total[5m])
# 95パーセンタイルレイテンシ
histogram_quantile(0.95, rate(http_request_duration_seconds_bucket[5m]))
# 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. Grafanaのセキュリティ: デフォルトパスワードを変更し、HTTPSとOAuthを設定
2. 保持ポリシー: ストレージ容量に基づいてretention.timeを調整
3. リモートストレージ: 長期保存にはThanosまたはCortexを使用
4. サービスディスカバリ: 静的設定をConsulやKubernetes SDに置き換え
5. レコーディングルール: ダッシュボード性能向上のために高負荷クエリを事前計算
本番グレードの監視スタックが完成しました!独自のサービスをスクレイプターゲットとして追加し、ニーズに合わせたカスタムダッシュボードを構築しましょう。