mcpField
L
loki

loki

github.com/julianobarbosaクラウド・DevOps15147 回インストール4 日前に更新
リポジトリ

loki について

Grafana Lokiによるログ集約のデプロイ、設定、クエリ、トラブルシューティングを案内するスキルです。運用担当者やプラットフォームエンジニア向けに、ラベルベースのインデックス、LogQL、マルチテナント、オブジェクトストレージを扱います。

主な機能

  1. 01Lokiのアーキテクチャとデプロイ方式の解説
  2. 02オブジェクトストレージと保持期間の設定
  3. 03LogQLによるログクエリ
  4. 04OpenTelemetryログ取り込みの解説
  5. 05Kubernetesデプロイとトラブル対応の案内

活用シーン

  1. 01Lokiのデプロイ方式の検討
  2. 02ログストレージと保持期間の設定
  3. 03ログストリームの検索と分析
  4. 04Lokiクラスターのトラブル対応

インストール

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

$npx skills add https://github.com/julianobarbosa/claude-code-skills --skill loki

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

同梱ファイル

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

references/
logql.md
opentelemetry.md
storage.md

詳細

Grafana Loki スキル

Prometheus に着想を得た、コスト効率に優れ、水平方向にスケーラブルなログ集約システムである Grafana Loki の包括的なガイドです。

Loki とは?

Loki は、次の特徴を持つ水平方向にスケーラブルで、高可用性かつマルチテナント対応のログ集約システムです。

  • メタデータ(ラベル)のみをインデックス化します。従来のシステムのようにログ全体をインデックス化しません。
  • 手頃な価格のオブジェクトストレージ(S3、GCS、Azure Blob)に圧縮したチャンクを保存します。
  • ログストリームの整理にPrometheus 形式のラベルを使用します。
  • テナント分離機能を標準搭載し、デフォルトでマルチテナントに対応しています。
  • コスト効率に優れています。インデックスのサイズを大幅に縮小し、運用コストを抑えます。

アーキテクチャの概要

コアコンポーネント
コンポーネント目的
Distributorリクエストを検証し、ラベルを前処理して、ingester にルーティングします
Ingesterログをメモリにバッファリングし、チャンクに圧縮してストレージに書き込みます
Querieringester とストレージに対する LogQL クエリを実行します
Query Frontendクエリを分割、キャッシュ、スケジューリングして高速化します
Query Scheduler公平性を保つため、テナントごとのクエリキューを管理します
Index GatewayTSDB ストアのインデックスクエリを処理します
Compactorインデックスファイルをマージし、保持期間を管理して、削除を処理します
Rulerアラートルールと記録ルールを評価します
データフロー

書き込みパス:

Log Source → Distributor → Ingester → Object Storage
                                    ↓
                              Chunks + Indexes

読み取りパス:

Query → Query Frontend → Query Scheduler → Querier
                                             ↓
                                    Ingesters + Storage

デプロイモード

1. モノリシックモード(-target=all)
  • すべてのコンポーネントが単一プロセスで動作します
  • 最適な用途:初期の試験、小規模環境(ログ約20GB/日)
  • 最もシンプルな方法です
2. シンプルなスケーラブルデプロイメント(SSD)— 推奨されるデフォルト
deploymentMode: SimpleScalable

write:
  replicas: 3   # Distributor + Ingester

read:
  replicas: 2   # Query Frontend + Querier

backend:
  replicas: 2   # Compactor + Index Gateway + Query Scheduler + Ruler
3. マイクロサービスモード(分散型)
deploymentMode: Distributed

ingester:
  replicas: 3
  zoneAwareReplication:
    enabled: true

distributor:
  replicas: 3

querier:
  replicas: 3

queryFrontend:
  replicas: 2

queryScheduler:
  replicas: 2

compactor:
  replicas: 1

indexGateway:
  replicas: 2

スキーマ設定

推奨:スキーマ v13 を使用する TSDB

loki:
  schemaConfig:
    configs:
      - from: "2024-04-01"
        store: tsdb
        object_store: azure  # or s3, gcs
        schema: v13
        index:
          prefix: loki_index_
          period: 24h

ストレージ設定

Azure Blob Storage(Azure で推奨)
loki:
  storage:
    type: azure
    bucketNames:
      chunks: loki-chunks
      ruler: loki-ruler
      admin: loki-admin
    azure:
      accountName: <storage-account-name>
      # Option 1: User-Assigned Managed Identity (Recommended)
      useManagedIdentity: true
      useFederatedToken: false
      userAssignedId: <identity-client-id>
      # Option 2: Account Key (Dev only)
      # accountKey: <account-key>
      requestTimeout: 30s
AWS S3
loki:
  storage:
    type: s3
    bucketNames:
      chunks: my-loki-chunks-2024
      ruler: my-loki-ruler-2024
      admin: my-loki-admin-2024
    s3:
      endpoint: s3.us-east-1.amazonaws.com
      region: us-east-1
      # Use IAM roles or access keys
      accessKeyId: <access-key>
      secretAccessKey: <secret-key>
      s3ForcePathStyle: false
Google Cloud Storage
loki:
  storage:
    type: gcs
    bucketNames:
      chunks: my-loki-gcs-bucket
    gcs:
      bucketName: my-loki-gcs-bucket
      # Uses Workload Identity or service account

チャンク設定のベストプラクティス

loki:
  ingester:
    chunk_encoding: snappy        # Recommended (fast + efficient)
    chunk_target_size: 1572864    # ~1.5MB compressed
    max_chunk_age: 2h             # Max time before flush
    chunk_idle_period: 30m        # Flush idle chunks
    flush_check_period: 30s
    flush_op_timeout: 10m
設定推奨値目的
chunk_encodingsnappy圧縮率と速度のバランスに優れています
chunk_target_size1.5MB圧縮後のチャンクサイズの目標値
max_chunk_age2hメモリ使用量とデータ損失のリスクを抑えます
chunk_idle_period30m非アクティブなストリームをフラッシュします

制限の設定

loki:
  limits_config:
    # Retention
    retention_period: 744h              # 31 days

    # Ingestion limits
    ingestion_rate_mb: 50
    ingestion_burst_size_mb: 100
    per_stream_rate_limit: 3MB
    per_stream_rate_limit_burst: 15MB

    # Query limits
    max_query_series: 10000
    max_query_lookback: 720h
    max_entries_limit_per_query: 10000

    # Required for OTLP
    allow_structured_metadata: true
    volume_enabled: true

    # Sample rejection
    reject_old_samples: true
    reject_old_samples_max_age: 168h    # 7 days
    max_label_names_per_series: 25

Compactor の設定

loki:
  compactor:
    retention_enabled: true
    retention_delete_delay: 2h
    retention_delete_worker_count: 50
    compaction_interval: 10m
    delete_request_store: azure         # Match your storage type

キャッシュ設定

推奨:Memcached インスタンスを分けて使用

# Helm values for Loki caching
memcached:
  # Results cache
  frontend:
    replicas: 3
    memcached:
      maxItemMemory: 1024               # 1GB
      maxItemSize: 5m
      connectionLimit: 1024

  # Chunks cache
  chunks:
    replicas: 3
    memcached:
      maxItemMemory: 4096               # 4GB
      maxItemSize: 2m
      connectionLimit: 1024

# Enable caching in Loki config
loki:
  chunk_store_config:
    chunk_cache_config:
      memcached_client:
        host: loki-memcached-chunks.monitoring.svc
        service: memcached-client

LogQL クエリ言語

基本的なクエリ
# Stream selector
{job="api-server"}

# Multiple labels
{job="api-server", env="prod"}

# Label matchers
{namespace=~".*-prod"}           # Regex match
{level!="debug"}                  # Not equal

# Filter expressions
{job="api-server"} |= "error"     # Contains
{job="api-server"} != "debug"     # Not contains
{job="api-server"} |~ "err.*"     # Regex match
{job="api-server"} !~ "debug.*"   # Regex not match
パイプラインステージ
# JSON parsing
{job="api-server"} | json

# Extract specific fields
{job="api-server"} | json | line_format "{{.message}}"

# Label extraction
{job="api-server"} | logfmt | level="error"

# Pattern matching
{job="api-server"} | pattern "<ip> - - [<_>] \"<method> <path>\"" | method="POST"
メトリクスクエリ
# Count logs per minute
count_over_time({job="api-server"}[1m])

# Rate of errors
rate({job="api-server"} |= "error" [5m])

# Bytes rate
bytes_rate({job="api-server"}[5m])

# Sum by label
sum by (namespace) (rate({job="api-server"}[5m]))

# Top 10 by volume
topk(10, sum by (namespace) (bytes_rate({}[5m])))

OpenTelemetry との統合

ネイティブ OTLP(推奨 — Loki 3.0+)

OpenTelemetry Collector の設定:

exporters:
  otlphttp:
    endpoint: http://loki-gateway:3100/otlp
    headers:
      X-Scope-OrgID: "my-tenant"

service:
  pipelines:
    logs:
      receivers: [otlp]
      exporters: [otlphttp]

Loki の設定:

loki:
  limits_config:
    allow_structured_metadata: true    # Required for OTLP

主なメリット:

  • ログ本文をプレーンテキストとして保存します(JSON エンコードしません)。
  • 17 個のデフォルトのリソース属性を自動的にインデックス化します。
  • JSON の解析が不要になり、クエリがシンプルになります。
  • ストレージ効率が向上します。
リソース属性のマッピング
OTLP 属性Loki ラベル
service.nameservice_name
service.namespaceservice_namespace
k8s.pod.namek8s_pod_name
k8s.namespace.namek8s_namespace_name
cloud.regioncloud_region

Kubernetes Helm デプロイ

リポジトリを追加
helm repo add grafana https://grafana.github.io/helm-charts
helm repo update
Values を指定してインストール
helm install loki grafana/loki \
  --namespace monitoring \
  --values values.yaml
本番環境向け Values の例
deploymentMode: Distributed

loki:
  auth_enabled: true

  schemaConfig:
    configs:
      - from: "2024-04-01"
        store: tsdb
        object_store: azure
        schema: v13
        index:
          prefix: loki_index_
          period: 24h

  storage:
    type: azure
    azure:
      accountName: mystorageaccount
      useManagedIdentity: true
      userAssignedId: <client-id>
    bucketNames:
      chunks: loki-chunks
      ruler: loki-ruler
      admin: loki-admin

  limits_config:
    retention_period: 2160h             # 90 days
    allow_structured_metadata: true

ingester:
  replicas: 3
  zoneAwareReplication:
    enabled: true
  resources:
    requests:
      cpu: 2
      memory: 8Gi
    limits:
      cpu: 4
      memory: 16Gi

querier:
  replicas: 3
  maxUnavailable: 2

queryFrontend:
  replicas: 2

distributor:
  replicas: 3

compactor:
  replicas: 1

indexGateway:
  replicas: 2
  maxUnavailable: 1

# Gateway for external access
gateway:
  service:
    type: LoadBalancer

# Monitoring
monitoring:
  serviceMonitor:
    enabled: true

Azure ID の設定

ユーザー割り当てマネージド ID(推奨)

1. ID を作成:

az identity create \
  --name loki-identity \
  --resource-group <rg>

IDENTITY_CLIENT_ID=$(az identity show --name loki-identity --resource-group <rg> --query clientId -o tsv)
IDENTITY_PRINCIPAL_ID=$(az identity show --name loki-identity --resource-group <rg> --query principalId -o tsv)

2. ノードプールに割り当て:

az vmss identity assign \
  --resource-group <aks-node-rg> \
  --name <vmss-name> \
  --identities /subscriptions/<sub>/resourceGroups/<rg>/providers/Microsoft.ManagedIdentity/userAssignedIdentities/loki-identity

3. ストレージ権限を付与:

az role assignment create \
  --role "Storage Blob Data Contributor" \
  --assignee-object-id $IDENTITY_PRINCIPAL_ID \
  --scope /subscriptions/<sub>/resourceGroups/<rg>/providers/Microsoft.Storage/storageAccounts/<storage>

4. Loki を設定:

loki:
  storage:
    azure:
      useManagedIdentity: true
      userAssignedId: <IDENTITY_CLIENT_ID>

マルチテナント

loki:
  auth_enabled: true

# Query with tenant header
curl -H "X-Scope-OrgID: tenant-a" \
  "http://loki:3100/loki/api/v1/query?query={job=\"app\"}"

# Multi-tenant queries (if enabled)
# X-Scope-OrgID: tenant-a|tenant-b

トラブルシューティング

よくある問題

1. コンテナーが見つからない(Azure)

# Create required containers
az storage container create --name loki-chunks --account-name <storage>
az storage container create --name loki-ruler --account-name <storage>
az storage container create --name loki-admin --account-name <storage>

2. 認証エラー(Azure)

# Verify RBAC assignment
az role assignment list --scope /subscriptions/<sub>/resourceGroups/<rg>/providers/Microsoft.Storage/storageAccounts/<storage>

# Assign if missing
az role assignment create \
  --role "Storage Blob Data Contributor" \
  --assignee-object-id <principal-id> \
  --scope <storage-scope>

# Restart pod to refresh token
kubectl delete pod -n monitoring <ingester-pod>

3. Ingester の OOM

# Increase memory limits
ingester:
  resources:
    limits:
      memory: 16Gi

4. クエリのタイムアウト

loki:
  querier:
    query_timeout: 5m
    max_concurrent: 8
  query_scheduler:
    max_outstanding_requests_per_tenant: 2048
診断コマンド
# Check pod status
kubectl get pods -n monitoring -l app.kubernetes.io/name=loki

# Check ingester logs
kubectl logs -n monitoring -l app.kubernetes.io/component=ingester --tail=100

# Check compactor logs
kubectl logs -n monitoring -l app.kubernetes.io/component=compactor --tail=100

# Verify readiness
kubectl exec -it <loki-pod> -n monitoring -- wget -qO- http://localhost:3100/ready

# Check configuration
kubectl exec -it <loki-pod> -n monitoring -- cat /etc/loki/config/config.yaml

API リファレンス

取り込み
# Push logs
POST /loki/api/v1/push

# OTLP logs
POST /otlp/v1/logs
クエリ
# Instant query
GET /loki/api/v1/query?query={job="app"}&time=<timestamp>

# Range query
GET /loki/api/v1/query_range?query={job="app"}&start=<start>&end=<end>

# Labels
GET /loki/api/v1/labels
GET /loki/api/v1/label/<name>/values

# Series
GET /loki/api/v1/series

# Tail (WebSocket)
GET /loki/api/v1/tail?query={job="app"}
ヘルスチェック
GET /ready
GET /metrics

リファレンスドキュメント

トピック別の詳細な設定については、以下を参照してください。

外部リソース


注意点

  • Ingester はストリーム途中でカーディナリティが変化するラベルを拒否します — 低カーディナリティから高カーディナリティに切り替わったラベルは、通知なしにストリームを分割し、ゴーストギャップを発生させます。
  • LogQL の |=(行フィルター)はラベルフィルターより高速です — クエリープランは行フィルターのみを最適化します。ラベルフィルターは解析後に実行されます。
  • X-Scope-OrgID によるテナント分離:ヘッダーがない場合、通知なしにテナント「fake」へ書き込まれます。ログは失われたのではなく、別のテナントに保存されています。
  • 保持期間はテナントごとに設定されます。グローバルの保持期間環境変数はフォールバックとしてのみ使われるため、テナントの設定を誤るとグローバル設定が通知なしに上書きされます。
  • Compactor が実行されていないと、孤立したチャンクが蓄積します — ストレージは際限なく増大します。Compactor の障害は別コンポーネントのログに記録されます。
  • Promtail から Alloy への移行:ラベルの正規化には微妙な違いがあります(例:__path__ のセマンティクス)。トラフィックが多いときに移行すると、ログが失われます。

コメント