mcpField
O
observability-sre

observability-sre

github.com/majiayu000クラウド・DevOps288162 回インストール今日更新
リポジトリ

observability-sre について

Observability & Site Reliability Engineering は、サービスの設計・運用に携わるエンジニア向けの可観測性と信頼性のリファレンススキルです。メトリクス、ログ、トレース、SLO、アラート、インシデント対応の指針と実装例をまとめています。

主な機能

  1. 01メトリクス、ログ、トレースの指針
  2. 02ユーザー症状に基づくアラート原則
  3. 03SLOとエラーバジェットの実践
  4. 04トレースコンテキストと構造化ログ
  5. 05PrometheusとOpenTelemetryの例

活用シーン

  1. 01サービスのSLOとエラーバジェットの定義
  2. 02症状に基づく本番アラートの設計
  3. 03ログと分散トレースの関連付け

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/majiayu000/spellbook --skill observability-sre

インストール後、Claude Code で/observability-sreを入力して読み込まれたか確認します。

同梱ファイル

SKILL.md と一緒にインストールされる参考資料やスクリプト。

reference/
extended.md
incident-response.md
logging.md
monitoring.md
tracing.md
templates/
slo-template.md

詳細

可観測性とサイト信頼性エンジニアリング

基本原則

  • 3つの柱 — メトリクス、ログ、トレースによって全体を把握できます
  • 可観測性を最優先 — システムが自身の動作を説明できるように構築します
  • SLO 主導 — ユーザーにとって重要な信頼性目標を定義します
  • 事前検知 — 顧客が気付く前に問題を発見します
  • 非難しない文化 — 誰かを責めずに障害から学びます
  • 運用負荷を自動化 — 繰り返し発生する運用作業を減らします
  • 継続的な改善 — インシデントのたびにシステムの耐障害性を高めます
  • フルスタックの可視性 — インフラストラクチャからビジネスメトリクスまで監視します

厳守事項

これらのルールは必須です。違反すると、このスキルが正しく機能しません。

症状に基づくアラートのみ

内部インフラストラクチャのメトリクスではなく、ユーザーに影響する症状に対してアラートを設定します。

# ❌ FORBIDDEN: Alerting on internal metrics
- alert: CPUHigh
  expr: cpu_usage > 70%
  # Users don't care about CPU, they care about latency

- alert: MemoryHigh
  expr: memory_usage > 80%
  # Internal metric, may not affect users

# ✅ REQUIRED: Alert on user experience
- alert: APILatencyHigh
  expr: slo:api_latency:p95 > 0.200
  annotations:
    summary: "Users experiencing slow response times"

- alert: ErrorRateHigh
  expr: slo:api_errors:rate5m > 0.001
  annotations:
    summary: "Users encountering errors"
低カーディナリティのラベル

Loki/Prometheus のラベルは低カーディナリティ(固有のラベルは 10 個未満)にする必要があります。

# ❌ FORBIDDEN: High cardinality labels
labels:
  user_id: "usr_123"      # Millions of values!
  order_id: "ord_456"     # Millions of values!
  request_id: "req_789"   # Every request is unique!

# ✅ REQUIRED: Low cardinality only
labels:
  namespace: "production"  # Few values
  app: "api-server"        # Few values
  level: "error"           # 5-6 values
  method: "GET"            # ~10 values

# High cardinality data goes in log body:
logger.info({
  user_id: "usr_123",      # In JSON body, not label
  order_id: "ord_456",
}, "Order processed");
SLO に基づくエラーバジェット

すべてのサービスで SLO を定義し、エラーバジェットを追跡する必要があります。

# ❌ FORBIDDEN: No SLO definition
# Just monitoring without targets

# ✅ REQUIRED: Explicit SLO with budget
# SLO: 99.9% availability
# Error Budget: 0.1% = 43.2 minutes/month downtime

groups:
  - name: slo_tracking
    rules:
      - record: slo:api_availability:ratio
        expr: sum(rate(http_requests_total{status!~"5.."}[5m])) / sum(rate(http_requests_total[5m]))

      - alert: ErrorBudgetBurnRate
        expr: slo:api_availability:ratio < 0.999
        for: 5m
        annotations:
          summary: "Burning error budget too fast"
ログ内のトレースコンテキスト

分散トレースとの関連付けのため、すべてのログに trace_id を含める必要があります。

// ❌ FORBIDDEN: Logs without trace context
logger.info("Payment processed");

// ✅ REQUIRED: Include trace_id in every log
const span = trace.getActiveSpan();
logger.info({
  trace_id: span?.spanContext().traceId,
  span_id: span?.spanContext().spanId,
  order_id: "ord_123",
}, "Payment processed");

// Output includes correlation:
// {"trace_id":"abc123","span_id":"def456","order_id":"ord_123","msg":"Payment processed"}

クイックリファレンス

用途に応じた選択
シナリオツール/パターン理由
メトリクス収集Prometheus + Grafana業界標準で、強力なクエリ言語を備えています
分散トレーシングOpenTelemetry + Tempo/Jaegerベンダーに依存せず、CNCF 標準に準拠しています
ログ集約(コスト重視)Grafana Lokiラベルのみをインデックス化し、コストを 10 分の 1 に抑えます
ログ集約(検索重視)ELK Stack全文検索と高度な分析が可能です
統合オブザーバビリティElastic/Datadog/Dynatraceすべてのテレメトリを一元的に把握できます
インシデント管理PagerDuty/Opsgenieアラートのルーティングとオンコールのスケジュール管理に対応します
カオスエンジニアリングGremlin/Chaos Mesh制御された障害注入が可能です
AIOps/異常検知Dynatrace/DatadogAI 主導の根本原因分析に対応します
3つの柱
柱内容用途ツール
メトリクス数値の時系列データリアルタイム監視、アラートPrometheus、StatsD、CloudWatch
ログコンテキストを含むイベント記録デバッグ、監査証跡Loki、ELK、Splunk
トレースサービス間のリクエスト経路パフォーマンス分析、依存関係の把握OpenTelemetry、Jaeger、Zipkin

第 4 の柱(新興): 継続的プロファイリング — コードレベルのパフォーマンスデータ(関数単位の CPU 使用率、メモリ使用量)


オブザーバビリティアーキテクチャ

階層化された Prometheus のセットアップ
# 2025 Best Practice: Federated architecture
# Prevents metric chaos while enabling drill-down

# Layer 1: Application Prometheus
# - Detailed business logic metrics
# - High cardinality acceptable
# - Short retention (7 days)

# Layer 2: Cluster Prometheus
# - Per-environment/cluster metrics
# - Medium retention (30 days)
# - Aggregates from application level

# Layer 3: Global Prometheus
# - Cross-cluster critical metrics
# - Long retention (1 year)
# - Federation from cluster level

# Global Prometheus config
scrape_configs:
  - job_name: 'federate'
    scrape_interval: 15s
    honor_labels: true
    metrics_path: '/federate'
    params:
      'match[]':
        - '{job="kubernetes-nodes"}'
        - '{__name__=~"job:.*"}'  # Recording rules only
    static_configs:
      - targets:
        - 'cluster-prom-us-east.internal:9090'
        - 'cluster-prom-eu-west.internal:9090'
パフォーマンス向上のための記録ルール
# Precompute expensive queries
groups:
  - name: api_performance
    interval: 30s
    rules:
      # Request rate (requests per second)
      - record: job:api_requests:rate5m
        expr: sum(rate(http_requests_total[5m])) by (job, method, status)

      # Error rate
      - record: job:api_errors:rate5m
        expr: |
          sum(rate(http_requests_total{status=~"5.."}[5m])) by (job)
          /
          sum(rate(http_requests_total[5m])) by (job)

      # P95 latency
      - record: job:api_latency:p95
        expr: histogram_quantile(0.95, sum(rate(http_request_duration_seconds_bucket[5m])) by (job, le))
リソースの最適化
# Increase scrape interval for high-target deployments
scrape_interval: 30s  # Default: 15s reduces load by 50%

# Use relabeling to drop unnecessary metrics
metric_relabel_configs:
  - source_labels: [__name__]
    regex: 'go_.*|process_.*'  # Drop Go runtime metrics
    action: drop

# Limit sample retention
storage:
  tsdb:
    retention.time: 15d  # Keep only 15 days locally
    retention.size: 50GB # Or max 50GB

OpenTelemetry による分散トレーシング

自動計装のセットアップ
// Node.js auto-instrumentation
import { NodeSDK } from '@opentelemetry/sdk-node';
import { getNodeAutoInstrumentations } from '@opentelemetry/auto-instrumentations-node';
import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-http';

const sdk = new NodeSDK({
  traceExporter: new OTLPTraceExporter({
    url: 'http://otel-collector:4318/v1/traces',
  }),
  instrumentations: [
    getNodeAutoInstrumentations({
      // Auto-instruments HTTP, Express, PostgreSQL, Redis, etc.
      '@opentelemetry/instrumentation-fs': { enabled: false }, // Too noisy
    }),
  ],
});

sdk.start();
ビジネスロジックへの手動計装
import { trace, SpanStatusCode } from '@opentelemetry/api';

const tracer = trace.getTracer('payment-service', '1.0.0');

async function processPayment(orderId: string, amount: number) {
  // Create custom span for business operation
  return tracer.startActiveSpan('processPayment', async (span) => {
    try {
      // Add business context
      span.setAttributes({
        'order.id': orderId,
        'payment.amount': amount,
        'payment.currency': 'USD',
      });

      // Child span for external API call
      const paymentResult = await tracer.startActiveSpan('stripe.charge', async (childSpan) => {
        const result = await stripe.charges.create({ amount, currency: 'usd' });
        childSpan.setAttribute('stripe.charge_id', result.id);
        childSpan.setStatus({ code: SpanStatusCode.OK });
        childSpan.end();
        return result;
      });

      span.setStatus({ code: SpanStatusCode.OK });
      return paymentResult;
    } catch (error) {
      span.recordException(error);
      span.setStatus({ code: SpanStatusCode.ERROR, message: error.message });
      throw error;
    } finally {
      span.end();
    }
  });
}
サンプリング戦略
# OpenTelemetry Collector config
processors:
  # Probabilistic sampling: Keep 10% of traces
  probabilistic_sampler:
    sampling_percentage: 10

  # Tail sampling: Make decisions after seeing full trace
  tail_sampling:
    policies:
      # Always sample errors
      - name: error-traces
        type: status_code
        status_code: {status_codes: [ERROR]}

      # Always sample slow requests
      - name: slow-traces
        type: latency
        latency: {threshold_ms: 1000}

      # Sample 5% of normal traffic
      - name: normal-traces
        type: probabilistic
        probabilistic: {sampling_percentage: 5}
コンテキスト伝播
// Ensure trace context flows across services
import { propagation, context } from '@opentelemetry/api';

// Outgoing HTTP request (automatic with auto-instrumentation)
fetch('https://api.example.com/data', {
  headers: {
    // W3C Trace Context headers injected automatically:
    // traceparent: 00-<trace-id>-<span-id>-01
    // tracestate: vendor=value
  },
});

// Manual propagation for non-HTTP (e.g., message queues)
const carrier = {};
propagation.inject(context.active(), carrier);
await publishMessage(queue, { data: payload, headers: carrier });

構造化ロギングのベストプラクティス

JSON ロギング形式
// Use structured logging library
import pino from 'pino';

const logger = pino({
  level: process.env.LOG_LEVEL || 'info',
  formatters: {
    level: (label) => ({ level: label }),
  },
  timestamp: pino.stdTimeFunctions.isoTime,
  // Include trace context in logs
  mixin() {
    const span = trace.getActiveSpan();
    if (!span) return {};

    const { traceId, spanId } = span.spanContext();
    return {
      trace_id: traceId,
      span_id: spanId,
    };
  },
});

// Structured logging with context
logger.info(
  {
    user_id: '123',
    order_id: 'ord_456',
    amount: 99.99,
    payment_method: 'card',
  },
  'Payment processed successfully'
);

// Output:
// {"level":"info","time":"2025-01-15T10:30:00.000Z","trace_id":"abc123","span_id":"def456","user_id":"123","order_id":"ord_456","amount":99.99,"payment_method":"card","msg":"Payment processed successfully"}
ログレベル
// Follow standard severity levels
logger.trace({ details }, 'Low-level debugging');     // Very verbose
logger.debug({ state }, 'Debug information');          // Development
logger.info({ event }, 'Normal operation');            // Production default
logger.warn({ issue }, 'Warning condition');           // Potential issues
logger.error({ error, context }, 'Error occurred');    // Errors
logger.fatal({ critical }, 'Fatal error');             // Process crash
Grafana Loki の設定
# Promtail config - ships logs to Loki
server:
  http_listen_port: 9080

positions:
  filename: /tmp/positions.yaml

clients:
  - url: http://loki:3100/loki/api/v1/push

scrape_configs:
  - job_name: kubernetes
    kubernetes_sd_configs:
      - role: pod
    relabel_configs:
      # Add pod labels as Loki labels (LOW cardinality only!)
      - source_labels: [__meta_kubernetes_namespace]
        target_label: namespace
      - source_labels: [__meta_kubernetes_pod_name]
        target_label: pod
      - source_labels: [__meta_kubernetes_pod_label_app]
        target_label: app
    pipeline_stages:
      # Parse JSON logs
      - json:
          expressions:
            level: level
            trace_id: trace_id
      # Extract fields as labels
      - labels:
          level:
          trace_id:
Loki のベストプラクティス
  • 低カーディナリティのラベル — 使用するラベルは 5~10 個(namespace、app、level)のみにします
  • ログ本文には高カーディナリティの値を含める — user_id や order_id はラベルではなく JSON に含めます
  • フィルタリングには LogQL を使用 — {app="api"} | json | user_id="123" を使用します
  • 保持ポリシー — 最近のログは長く保持し、古いログは圧縮します
# LogQL query examples
{namespace="production", app="api"} |= "error"  # Text search

{app="api"} | json | level="error" | line_format "{{.msg}}"  # JSON parsing

rate({app="api"}[5m])  # Log rate per second

sum by (level) (count_over_time({namespace="production"}[1h]))  # Count by level

詳細リファレンス

このスキルを簡潔に保つため、## SLO/SLI/SLA Management 以降の詳細な資料は reference/extended.md に移動しました。移動された使用例、コマンド一覧、チェックリスト、プラットフォームの詳細、実装テンプレートが必要なタスクでは、このリファレンスを読み込んでください。

コメント