Kubernetes Observability Stack ハンズオン

EKS 上でメトリクス・ログ・トレースの三本柱を Prometheus / Grafana / OpenTelemetry / Jaeger で構築する

Amazon EKS Prometheus Grafana OpenTelemetry Jaeger CLI 操作 中級 所要時間 100〜130 分 v1.0

📋 概要

オブザーバビリティ(可観測性)は、システムの内部状態を外部から観察する能力です。CNCF の Observability エコシステムを代表するツール群を EKS 上に構築し、マイクロサービスの健全性をリアルタイムで把握する方法を学びます。

項目内容
対象サービスAmazon EKS、Prometheus、Grafana、OpenTelemetry Collector、Jaeger
主な学習内容三本柱の理解・kube-prometheus-stack 導入・OTel Collector 設定・分散トレース確認・障害調査
所要時間100〜130 分
難易度★★★☆☆(中級者向け)
前提知識Kubernetes / Helm の基本操作
費用目安約 3〜6 USD(EKS クラスター、t3.large ノード 2 台)
ℹ️ オブザーバビリティ三本柱
内容ツール(本ハンズオン)
メトリクス数値の時系列データ(CPU・レイテンシ・エラー率)Prometheus + Grafana
ログイベントのテキスト記録CloudWatch Logs(EKS 標準)
トレース1 リクエストのサービス間経路OpenTelemetry + Jaeger
ℹ️ CNCF プロジェクトの位置づけ
  • Prometheus — CNCF Graduated。デファクトの Kubernetes メトリクス収集ツール
  • OpenTelemetry — CNCF Incubating。ベンダー中立のテレメトリ標準
  • Jaeger — CNCF Graduated。分散トレーシングシステム
  • Grafana — CNCF エコシステム外だが事実上の標準ダッシュボード

🏗️ アーキテクチャ

🚗 HotROD デモアプリ(マイクロサービス)
frontend / customer / driver / route / config の 5 サービス
↓ OTLP(gRPC 4317)
📡 OpenTelemetry Collector(DaemonSet / Deployment)
受信: OTLP → 変換 → エクスポート
↓ トレース → Jaeger  ↓ メトリクス → Prometheus
🔭 Jaeger(All-In-One)
UI: http://localhost:16686
📊 Prometheus → Grafana
kube-prometheus-stack(UI: http://localhost:3000)

使用ツールと役割

ツールnamespace役割
kube-prometheus-stackmonitoringPrometheus + Grafana + AlertManager 一括インストール
OpenTelemetry CollectorobservabilityOTLP データを受信し Jaeger・Prometheus に転送
Jaeger All-In-Oneobservability分散トレースの収集・表示
HotRODhotrod分散トレースのデモアプリ(配車サービス模擬)

✅ 前提条件

⚠️ ノードスペックに注意

Prometheus + Grafana スタックはメモリを多く消費します。ノードは t3.large(8 GB RAM)以上を推奨します。t3.medium でも動作しますが、Pod が Pending になる可能性があります。

⚠️ 費用について

t3.large ノード 2 台の EKS クラスターは 1 時間あたり約 $0.27 かかります。ハンズオン終了後は必ずクリーンアップしてください。

Helm のインストール確認

# Helm バージョン確認
helm version

# 未インストールの場合
curl https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash

☸️ ステップ 1 ― EKS クラスターの準備

1-1. EKS クラスターの作成(または既存クラスターへの接続)
# 新規作成の場合
eksctl create cluster \
  --name observability-handson \
  --version 1.33 \
  --region ap-northeast-1 \
  --nodegroup-name workers \
  --node-type t3.large \
  --nodes 2 \
  --managed

# 既存クラスターへの接続
aws eks update-kubeconfig --name <クラスター名> --region ap-northeast-1
1-2. 名前空間の作成
kubectl create namespace monitoring
kubectl create namespace observability
kubectl create namespace hotrod
1-3. Helm リポジトリの追加
helm repo add prometheus-community https://prometheus-community.github.io/helm-charts
helm repo add open-telemetry https://open-telemetry.github.io/opentelemetry-helm-charts
helm repo add jaegertracing https://jaegertracing.github.io/helm-charts
helm repo add cert-manager https://charts.jetstack.io
helm repo update
✅ 確認ポイント

kubectl get nodes でノードが Readyhelm repo list で 4 つのリポジトリが表示されれば準備完了です。

🚗 ステップ 2 ― サンプルマイクロサービスのデプロイ(HotROD)

Jaeger チームが開発した配車サービスのデモアプリ「HotROD(Hot R.O.D. - Rides on Demand)」をデプロイします。複数のマイクロサービスで構成され、分散トレースを体験するのに最適です。

2-1. HotROD の Deployment と Service を作成
kubectl apply -n hotrod -f - <<'EOF'
apiVersion: apps/v1
kind: Deployment
metadata:
  name: hotrod
  namespace: hotrod
spec:
  replicas: 1
  selector:
    matchLabels:
      app: hotrod
  template:
    metadata:
      labels:
        app: hotrod
    spec:
      containers:
      - name: hotrod
        image: jaegertracing/example-hotrod:latest
        args: ["all"]
        env:
        - name: OTEL_EXPORTER_OTLP_ENDPOINT
          value: "http://otel-collector.observability.svc.cluster.local:4317"
        ports:
        - containerPort: 8080
          name: frontend
        - containerPort: 8081
          name: customer
        - containerPort: 8082
          name: route
        - containerPort: 8083
          name: driver
---
apiVersion: v1
kind: Service
metadata:
  name: hotrod
  namespace: hotrod
spec:
  selector:
    app: hotrod
  ports:
  - name: frontend
    port: 8080
    targetPort: 8080
EOF
2-2. Pod の起動確認
kubectl get pods -n hotrod -w

Pod が Running になるまで待ちます。この時点では OTel Collector がまだないため、アプリは起動しますが接続エラーのログが出ます(正常)。

✅ 確認ポイント

kubectl get pods -n hotrodhotrod Pod が Running になれば次のステップに進めます。

📊 ステップ 3 ― Prometheus / Grafana の導入

kube-prometheus-stack Helm チャートを使って Prometheus・Grafana・AlertManager を一括インストールします。

3-1. kube-prometheus-stack のインストール
helm install kube-prom prometheus-community/kube-prometheus-stack \
  --namespace monitoring \
  --set grafana.adminPassword="HandsOn2024!" \
  --set grafana.service.type=ClusterIP \
  --set prometheus.prometheusSpec.retention=1d \
  --set alertmanager.enabled=false

インストールに 2〜3 分かかります。

3-2. Pod の起動確認
kubectl get pods -n monitoring -w

以下の Pod が Running になるのを確認します。

  • kube-prom-grafana-xxx
  • kube-prom-kube-prometheus-stack-prometheus-xxx
  • kube-prom-kube-state-metrics-xxx
  • kube-prom-prometheus-node-exporter-xxx(各ノードに 1 つ)
3-3. Grafana にアクセス

別のターミナルで以下を実行してポートフォワードします。

kubectl port-forward -n monitoring svc/kube-prom-grafana 3000:80

ブラウザで http://localhost:3000 を開きます。

ユーザー名admin
パスワードHandsOn2024!
✅ 確認ポイント

Grafana にログインし、左メニューの「Dashboards」→「Browse」で 「Kubernetes / Compute Resources / Cluster」 ダッシュボードが確認できれば成功です(CPU・メモリの使用状況が表示されます)。

📡 ステップ 4 ― OpenTelemetry Collector の導入

OpenTelemetry Operator を使ってコレクターをデプロイします。まず Operator の前提となる cert-manager をインストールします。

4-1. cert-manager のインストール
helm install cert-manager cert-manager/cert-manager \
  --namespace cert-manager \
  --create-namespace \
  --set installCRDs=true

# 起動確認(1〜2 分待つ)
kubectl get pods -n cert-manager
4-2. OpenTelemetry Operator のインストール
helm install opentelemetry-operator open-telemetry/opentelemetry-operator \
  --namespace observability \
  --set manager.collectorImage.repository=otel/opentelemetry-collector-contrib

kubectl rollout status deployment/opentelemetry-operator-controller-manager \
  -n observability
4-3. OpenTelemetry Collector CR を作成

OTLP でトレースを受信し、Jaeger に転送するコレクターを作成します(Jaeger は次のステップで作成)。

kubectl apply -n observability -f - <<'EOF'
apiVersion: opentelemetry.io/v1beta1
kind: OpenTelemetryCollector
metadata:
  name: otel-collector
  namespace: observability
spec:
  mode: Deployment
  config:
    receivers:
      otlp:
        protocols:
          grpc:
            endpoint: 0.0.0.0:4317
          http:
            endpoint: 0.0.0.0:4318
    processors:
      batch:
        timeout: 1s
    exporters:
      otlp/jaeger:
        endpoint: jaeger.observability.svc.cluster.local:4317
        tls:
          insecure: true
      debug:
        verbosity: basic
    service:
      pipelines:
        traces:
          receivers: [otlp]
          processors: [batch]
          exporters: [otlp/jaeger, debug]
EOF
4-4. Collector Pod の確認
kubectl get pods -n observability

otel-collector-collector-xxx Pod が Running になれば OK です。

✅ 確認ポイント

kubectl get svc -n observabilityotel-collector-collector Service がポート 4317/4318 でリッスンしていれば成功です。

🔭 ステップ 5 ― Jaeger の導入

学習・開発環境向けの Jaeger All-In-One をデプロイします(データはメモリに保持されます)。

5-1. Jaeger All-In-One のデプロイ
kubectl apply -n observability -f - <<'EOF'
apiVersion: apps/v1
kind: Deployment
metadata:
  name: jaeger
  namespace: observability
spec:
  replicas: 1
  selector:
    matchLabels:
      app: jaeger
  template:
    metadata:
      labels:
        app: jaeger
    spec:
      containers:
      - name: jaeger
        image: jaegertracing/all-in-one:latest
        env:
        - name: COLLECTOR_OTLP_ENABLED
          value: "true"
        ports:
        - containerPort: 16686
          name: ui
        - containerPort: 4317
          name: otlp-grpc
        - containerPort: 4318
          name: otlp-http
        - containerPort: 14250
          name: grpc
---
apiVersion: v1
kind: Service
metadata:
  name: jaeger
  namespace: observability
spec:
  selector:
    app: jaeger
  ports:
  - name: ui
    port: 16686
    targetPort: 16686
  - name: otlp-grpc
    port: 4317
    targetPort: 4317
  - name: otlp-http
    port: 4318
    targetPort: 4318
  - name: grpc
    port: 14250
    targetPort: 14250
EOF
5-2. Jaeger UI へのアクセス
kubectl port-forward -n observability svc/jaeger 16686:16686

ブラウザで http://localhost:16686 を開きます。「Service」セレクターが空の状態で表示されれば正常です。

✅ 確認ポイント

Jaeger UI(http://localhost:16686)にアクセスでき、トップページが表示されれば成功です。

🚦 ステップ 6 ― 正常トラフィックの生成

HotROD アプリにアクセスしてトレースデータを生成します。

6-1. HotROD フロントエンドへのアクセス
kubectl port-forward -n hotrod svc/hotrod 8080:8080

ブラウザで http://localhost:8080 を開きます。配車サービスの UI が表示されます。

6-2. リクエストを複数回生成

HotROD の UI で 「Rachel's Floral Designs」 などのボタンを 5〜10 回クリックします。各クリックが 1 つのトレースを生成します。

6-3. 継続的なトラフィック生成(オプション)
# curl でリクエストをループ送信
for i in $(seq 1 20); do
  curl -s "http://localhost:8080/dispatch?customer=123&nonse=0.6308022493951762" > /dev/null
  sleep 1
done
✅ 確認ポイント

HotROD UI でリクエストに成功すると、ドライバー情報が表示されます。1〜2 分後に Jaeger UI でトレースが確認できるようになります。

📊 ステップ 7 ― Grafana でメトリクスを確認

7-1. Kubernetes クラスターダッシュボードを確認

Grafana(http://localhost:3000)で 「Dashboards」→「Browse」 を開き、以下のダッシュボードを確認します。

ダッシュボード名確認できる内容
Kubernetes / Compute Resources / Clusterクラスター全体の CPU・メモリ使用率
Kubernetes / Compute Resources / Namespace (Pods)名前空間・Pod 別のリソース使用率
Node Exporter / Nodesノード(EC2)のハードウェアメトリクス
7-2. PromQL でカスタムクエリを実行

Grafana の「Explore」画面で PromQL クエリを試します。

# HotROD の CPU 使用率
rate(container_cpu_usage_seconds_total{namespace="hotrod"}[5m])

# メモリ使用量(バイト)
container_memory_working_set_bytes{namespace="hotrod"}

# Pod の再起動回数
kube_pod_container_status_restarts_total{namespace="hotrod"}
7-3. アラートルールの確認

Grafana の「Alerting」→「Alert rules」を開くと、kube-prometheus-stack が事前に定義した Kubernetes 向けアラートルールが確認できます。

✅ 確認ポイント

Grafana で HotROD の Pod リソース使用状況がグラフで表示されれば成功です。

🔭 ステップ 8 ― Jaeger でトレースを確認

8-1. Jaeger UI でサービスを選択

Jaeger UI(http://localhost:16686)の左パネルで以下を設定します。

Servicefrontend(または hotrod)
OperationHTTP GET /dispatch
LookbackLast 1 Hour

「Find Traces」 をクリックします。

8-2. トレース詳細を確認

表示されたトレースをクリックして詳細を開きます。ウォーターフォール図で以下を確認します。

  • 各サービス(frontend → customer → driver → route)の呼び出し順序
  • 各スパンの所要時間(遅いサービスを特定)
  • スパンのタグ(HTTP メソッド、ステータスコード、DB クエリ等)
8-3. サービス依存グラフの確認

Jaeger UI のメニューから 「System Architecture」→「DAG」 を開きます。サービス間の依存関係がグラフで表示されます。

✅ 確認ポイント

Jaeger でトレースの一覧が表示され、スパンのウォーターフォール図で複数サービスにわたるリクエスト経路が確認できれば成功です。

🔥 ステップ 9 ― 障害シナリオの確認

意図的に負荷をかけたり、Pod を削除してメトリクスとトレースで障害の様子を観察します。

9-1. HotROD に高負荷をかける
# 並列リクエストを送信
for i in $(seq 1 50); do
  curl -s "http://localhost:8080/dispatch?customer=392&nonse=$(python3 -c 'import random; print(random.random())')" > /dev/null &
done
wait
9-2. Grafana でリソース変化を観察

Grafana の「Kubernetes / Compute Resources / Namespace (Pods)」ダッシュボードで hotrod 名前空間を選択します。CPU・メモリの急増が確認できます。

9-3. Jaeger で遅いトレースをフィルタリング

Jaeger UI で「Min Duration」に 500ms を設定して検索します。遅いリクエストのトレースに絞り込み、どのスパン(サービス)がボトルネックかを特定します。

9-4. Pod を強制削除して再起動を観察
kubectl delete pod -n hotrod -l app=hotrod --force

Grafana のダッシュボードで Pod の再起動回数メトリクスが増加することを確認します。

✅ 確認ポイント

Grafana でリソース急増が、Jaeger で遅いトレースが確認でき、2 つのデータを組み合わせて原因調査ができる状態になれば目標達成です。

💡 学習ポイント

三本柱を使った障害調査フロー

  1. メトリクス(Grafana) でいつ・どのサービスで異常が発生したかを特定
  2. トレース(Jaeger) で問題のあったリクエストの経路・ボトルネックを特定
  3. ログ(CloudWatch Logs) で詳細なエラーメッセージを確認

RED メソッド

マイクロサービスの健全性を測る 3 つの黄金指標です。

指標説明Prometheus クエリ例
Rate(スループット)1 秒あたりのリクエスト数rate(http_requests_total[5m])
Errors(エラー率)失敗したリクエストの割合rate(http_requests_total{status=~"5.."}[5m])
Duration(レイテンシ)リクエストの処理時間histogram_quantile(0.99, rate(http_request_duration_seconds_bucket[5m]))

次のステップ

🧹 クリーンアップ

ハンズオン完了後は以下の順序でリソースを削除してください。

⚠️ EKS クラスターは放置すると費用が継続発生します

t3.large × 2 ノードのクラスターは 1 時間あたり約 $0.37 かかります。必ず削除してください。

1. HotROD の削除
kubectl delete namespace hotrod
2. OpenTelemetry Collector の削除
kubectl delete opentelemetrycollector otel-collector -n observability
3. Jaeger の削除
kubectl delete deployment jaeger -n observability
kubectl delete service jaeger -n observability
4. OpenTelemetry Operator の削除
helm uninstall opentelemetry-operator -n observability
5. kube-prometheus-stack の削除
helm uninstall kube-prom -n monitoring

CRD も削除する場合(監視スタックを完全削除):

kubectl delete crd \
  alertmanagerconfigs.monitoring.coreos.com \
  alertmanagers.monitoring.coreos.com \
  podmonitors.monitoring.coreos.com \
  probes.monitoring.coreos.com \
  prometheuses.monitoring.coreos.com \
  prometheusrules.monitoring.coreos.com \
  servicemonitors.monitoring.coreos.com \
  thanosrulers.monitoring.coreos.com
6. cert-manager の削除
helm uninstall cert-manager -n cert-manager
kubectl delete namespace cert-manager
7. 名前空間の削除
kubectl delete namespace monitoring observability
8. EKS クラスターの削除(このハンズオンで作成した場合)
eksctl delete cluster --name observability-handson --region ap-northeast-1
✅ クリーンアップ完了チェックリスト
  • ☐ hotrod namespace が削除された
  • ☐ monitoring namespace が削除された
  • ☐ observability namespace が削除された
  • ☐ cert-manager namespace が削除された
  • ☐ EKS クラスターが削除された
  • ☐ CloudFormation スタックが消えていること(AWS コンソールで確認)