EKS 上でメトリクス・ログ・トレースの三本柱を Prometheus / Grafana / OpenTelemetry / Jaeger で構築する
オブザーバビリティ(可観測性)は、システムの内部状態を外部から観察する能力です。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 |
| ツール | namespace | 役割 |
|---|---|---|
| kube-prometheus-stack | monitoring | Prometheus + Grafana + AlertManager 一括インストール |
| OpenTelemetry Collector | observability | OTLP データを受信し Jaeger・Prometheus に転送 |
| Jaeger All-In-One | observability | 分散トレースの収集・表示 |
| HotROD | hotrod | 分散トレースのデモアプリ(配車サービス模擬) |
kubectl・helm・AWS CLI がインストール済みであることPrometheus + Grafana スタックはメモリを多く消費します。ノードは t3.large(8 GB RAM)以上を推奨します。t3.medium でも動作しますが、Pod が Pending になる可能性があります。
t3.large ノード 2 台の EKS クラスターは 1 時間あたり約 $0.27 かかります。ハンズオン終了後は必ずクリーンアップしてください。
# Helm バージョン確認 helm version # 未インストールの場合 curl https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash
# 新規作成の場合 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
kubectl create namespace monitoring kubectl create namespace observability kubectl create namespace hotrod
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 でノードが Ready、helm repo list で 4 つのリポジトリが表示されれば準備完了です。
Jaeger チームが開発した配車サービスのデモアプリ「HotROD(Hot R.O.D. - Rides on Demand)」をデプロイします。複数のマイクロサービスで構成され、分散トレースを体験するのに最適です。
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
kubectl get pods -n hotrod -w
Pod が Running になるまで待ちます。この時点では OTel Collector がまだないため、アプリは起動しますが接続エラーのログが出ます(正常)。
kubectl get pods -n hotrod で hotrod Pod が Running になれば次のステップに進めます。
kube-prometheus-stack Helm チャートを使って Prometheus・Grafana・AlertManager を一括インストールします。
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 分かかります。
kubectl get pods -n monitoring -w
以下の Pod が Running になるのを確認します。
kube-prom-grafana-xxxkube-prom-kube-prometheus-stack-prometheus-xxxkube-prom-kube-state-metrics-xxxkube-prom-prometheus-node-exporter-xxx(各ノードに 1 つ)別のターミナルで以下を実行してポートフォワードします。
kubectl port-forward -n monitoring svc/kube-prom-grafana 3000:80
ブラウザで http://localhost:3000 を開きます。
Grafana にログインし、左メニューの「Dashboards」→「Browse」で 「Kubernetes / Compute Resources / Cluster」 ダッシュボードが確認できれば成功です(CPU・メモリの使用状況が表示されます)。
OpenTelemetry Operator を使ってコレクターをデプロイします。まず Operator の前提となる 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
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
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
kubectl get pods -n observability
otel-collector-collector-xxx Pod が Running になれば OK です。
kubectl get svc -n observability で otel-collector-collector Service がポート 4317/4318 でリッスンしていれば成功です。
学習・開発環境向けの 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
kubectl port-forward -n observability svc/jaeger 16686:16686
ブラウザで http://localhost:16686 を開きます。「Service」セレクターが空の状態で表示されれば正常です。
Jaeger UI(http://localhost:16686)にアクセスでき、トップページが表示されれば成功です。
HotROD アプリにアクセスしてトレースデータを生成します。
kubectl port-forward -n hotrod svc/hotrod 8080:8080
ブラウザで http://localhost:8080 を開きます。配車サービスの UI が表示されます。
HotROD の UI で 「Rachel's Floral Designs」 などのボタンを 5〜10 回クリックします。各クリックが 1 つのトレースを生成します。
# 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 でトレースが確認できるようになります。
Grafana(http://localhost:3000)で 「Dashboards」→「Browse」 を開き、以下のダッシュボードを確認します。
| ダッシュボード名 | 確認できる内容 |
|---|---|
| Kubernetes / Compute Resources / Cluster | クラスター全体の CPU・メモリ使用率 |
| Kubernetes / Compute Resources / Namespace (Pods) | 名前空間・Pod 別のリソース使用率 |
| Node Exporter / Nodes | ノード(EC2)のハードウェアメトリクス |
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"}
Grafana の「Alerting」→「Alert rules」を開くと、kube-prometheus-stack が事前に定義した Kubernetes 向けアラートルールが確認できます。
Grafana で HotROD の Pod リソース使用状況がグラフで表示されれば成功です。
Jaeger UI(http://localhost:16686)の左パネルで以下を設定します。
「Find Traces」 をクリックします。
表示されたトレースをクリックして詳細を開きます。ウォーターフォール図で以下を確認します。
Jaeger UI のメニューから 「System Architecture」→「DAG」 を開きます。サービス間の依存関係がグラフで表示されます。
Jaeger でトレースの一覧が表示され、スパンのウォーターフォール図で複数サービスにわたるリクエスト経路が確認できれば成功です。
意図的に負荷をかけたり、Pod を削除してメトリクスとトレースで障害の様子を観察します。
# 並列リクエストを送信 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
Grafana の「Kubernetes / Compute Resources / Namespace (Pods)」ダッシュボードで hotrod 名前空間を選択します。CPU・メモリの急増が確認できます。
Jaeger UI で「Min Duration」に 500ms を設定して検索します。遅いリクエストのトレースに絞り込み、どのスパン(サービス)がボトルネックかを特定します。
kubectl delete pod -n hotrod -l app=hotrod --force
Grafana のダッシュボードで Pod の再起動回数メトリクスが増加することを確認します。
Grafana でリソース急増が、Jaeger で遅いトレースが確認でき、2 つのデータを組み合わせて原因調査ができる状態になれば目標達成です。
マイクロサービスの健全性を測る 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])) |
ハンズオン完了後は以下の順序でリソースを削除してください。
t3.large × 2 ノードのクラスターは 1 時間あたり約 $0.37 かかります。必ず削除してください。
kubectl delete namespace hotrod
kubectl delete opentelemetrycollector otel-collector -n observability
kubectl delete deployment jaeger -n observability kubectl delete service jaeger -n observability
helm uninstall opentelemetry-operator -n observability
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
helm uninstall cert-manager -n cert-manager kubectl delete namespace cert-manager
kubectl delete namespace monitoring observability
eksctl delete cluster --name observability-handson --region ap-northeast-1