Claude Codeを活用し、プロダクト向けPlatformのKubernetes Ecosystem複雑系に立ち向かう話
これはGLOBIS アドベントカレンダーシリーズ1の6日目の記事です。
こんにちは!グロービス・デジタルプラットフォーム部門(GDP) SREチームの松井です。
Claude Code、活用していますか・・・?
振り返ってみると今年はAI Agent元年と評されることが多かったように思えます。
グロービスにおいても、AI Agentを活用した開発は開発組織に浸透しており、SREチームにおいても、Claude Codeを利用した開発・運用が標準となっています。
今回は、SREの定常業務における、複雑性に立ち向かうためのClaude Codeの活用についてお伝えできればと思います。
はじめに: プロダクト向けPlatform運用におけるKubernetes Ecosystemの運用
グロービスではAmazon EKS (Elastic Kubernetes Service) クラスタを中央のAWSアカウントで集権的に管理し、顧客向けデジタルサービスを展開する各プロダクトに、安定したコンテナ実行環境を提供しています。
これらの運用において、Kubernetesならではの運用の柔軟性を実現するため、様々なKubernetes Ecosystem OSSをPlatformの機能として提供しており、信頼性の維持のため、Renovate、Helm、ArgoCD等を活用して定常的なアップデートを実現しています。
原則として、これらのアップデートは入念な事前調査の元、破壊的変更が含まれているか、変更の影響範囲を確認の上対応することが常ですが、しばしばデプロイ後に不具合が発覚するケースもあります。こうした不具合に対するrevert自体は運用上は容易ですが、複数のコンポーネントが絡み合う複合的な障害の場合、各OSSのソースコードまでdeep diveしないと根本原因が特定できず、従来のエンジニアリングではかなりの工数を要していました。
Claude Codeを活用したKubernetes Ecosystemの不具合原因調査
しかしながら、最近では、Claude Codeを活用することで、様々な技術スタック・コンポーネントが絡み合うKubernetes Ecosystemの複雑な不具合の事象を解析し、根本原因を特定することが容易になりつつあります。
SREチームでは数あるAI Agentの中からClaude Codeを標準ツールとして運用しています。CUI型でどのエディタ/IDEとも統合可能であること、このカテゴリーにおけるパイオニアであること、そしてClaude Codeの固有機能(MCPやCLAUDE.md,Agents,Custom Commandsによるカスタマイズ等)を積極的に活用していく事の組織的なメリットを勘案して、本格導入に至っています。
以下に、直近遭遇した不具合と、これのClaude Codeを活用した調査事例を共有します。
KEDA v2.18.1アップデート時の不具合調査事例
弊社ではKubernetesを利用したEvent Drivenなコンテナのスケーリング手段としてKEDAを採用しています。プロダクトバックエンドコンテナに対するアクセス数連動のオートスケーリング等や、Datadogのカスタムメトリクスに連動したスケーリング手段としても活用しています。
今回、EKS 1.31環境において、KEDA v2.18.1(Helm chart同一バージョン)へのアップデートを環境毎に段階的に進めていましたが、開発環境デプロイ時に特定のプロダクトで不具合が発現しました。
不具合の詳細
このプロダクトではBackendにRuby on Railsを採用しており、非同期処理にSidekiqを活用しています。これらのSidekiqコンテナのスケーリングに、Sidekiq Prometheus Exporterから出力されるカスタムメトリクスを、Datadog Agent経由で収集し、KEDA ScaledObjectによるDatadog metricsトリガーベースでのスケーリングを実施しています。
今回不具合が発現したのはこのDatadogと連携したScaledObjectに関する部分でした。ScaledObjectが正常に動作せず、連動するHPAリソースまで不具合が発現している状況でした。
ScaledObjectの設定詳細
apiVersion: keda.sh/v1alpha1
kind: ScaledObject
metadata:
labels:
scaledobject.keda.sh/name: batch-scaledobject
name: batch-scaledobject
spec:
cooldownPeriod: 300
maxReplicaCount: 2
minReplicaCount: 1
pollingInterval: 30
scaleTargetRef:
apiVersion: apps/v1
envSourceContainerName: batch
kind: Deployment
name: batch
triggers:
- authenticationRef:
kind: ClusterTriggerAuthentication
name: keda-operator
metadata:
age: '60'
metricUnavailableValue: '0'
query: max:sidekiq.example.sidekiq_queue_latency_seconds{*}.rollup(60)
queryValue: '120'
metricType: Value
type: datadog
status:
authenticationsTypes: keda-operator
conditions:
- message: Triggers defined in ScaledObject are not working correctly
reason: TriggerError
status: 'False'
type: Ready
- message: Scaling is not performed because triggers are not active
reason: ScalerNotActive
status: 'False'
type: Active
- message: No fallbacks are active on this scaled object
reason: NoFallbackFound
status: 'False'
type: Fallback
- status: Unknown
type: Paused
externalMetricNames:
- s0-datadog-max-sidekiq-example-sidekiq_queue_latency_seconds
hpaName: keda-hpa-batch-scaledobject
originalReplicaCount: 1
scaleTargetGVKR:
group: apps
kind: Deployment
resource: deployments
version: v1
scaleTargetKind: apps/v1.Deployment
triggersTypes: datadog
Claude Codeと協働して原因を特定する
- 仮説駆動で、検証を高速に回す
原因の切り分けとして、KEDAのアップデートを行っていない環境ではエラーが発現していないことから、KEDA本体のアップデートに起因するものであるという切り分けを行いました。 Updateに起因する可能性があるということで、Claude CodeにCHANGELOGを再度精査させ、原因となりうる変更について提示させましたが、この時点では有効な仮説は提示されませんでした。後に判明しましたが、原因となる変更はv2.18.0で適用されたリファクタリングに起因しており、CHANGELOGの記述だけではソースコードレベルの分析なしに特定することは困難でした。 - 事実を元に仮説をブラッシュアップする
ScaledObjectのイベントログのみでは原因を特定するのに不足となるため、KEDA controllerのログを確認し、関連するエラーログが無いかを精査しました。
すると、以下のようなエラーログが出力されている事が確認できました。
# エラーログ抜粋
...
no Datadog metrics returned for the given time window
...
\
github.com/kedacore/keda/v2/pkg/scalers.(*datadogScaler).GetMetricsAndActivity
/workspace/pkg/scalers/datadog_scaler.go:496
github.com/kedacore/keda/v2/pkg/scaling/cache.(*ScalersCache).GetMetricsAndActivityForScaler
/workspace/pkg/scaling/cache/scalers_cache.go:154
github.com/kedacore/keda/v2/pkg/scaling.(*scaleHandler).GetScaledObjectMetrics.func1
/workspace/pkg/scaling/scale_handler.go:548
...
該当するエラーログ/スタックトレース情報を元に、Claude CodeにKEDAのソースコード分析を実施したところ、ようやく原因と思わしき仮説を構築することができました。以下はClaude Codeの分析の抜粋です。
### エラー発生箇所
datadog_scaler.go:496
if len(series) == 0 {
if !s.metadata.useFiller { // ← ここでエラー
return 0, fmt.Errorf("no Datadog metrics returned for the given time window")
}
return s.metadata.fillValue, nil
}
### 問題の核心
**KEDA 2.18.0で導入されたパラメータバリデーション(PR #6721)**が、`metricUnavailableValue` を正しく認識せず、`useFiller` フラグが設定されていない可能性があります。
複合的に絡み合った不具合の全容を読み解く
上記により、Datadog Scaler設定のmetricUnavailableValueの不具合らしいというところまでは特定できましたが、現在起きている不具合の全面的なプロセスの特定にまでは至っていません。不具合が発現しているのは開発環境クラスターに限定されていますが、殆ど同様の設定を実装済みである、別のk8s namespace上の開発環境では再現しない状況となっていました。そもそも、なぜmetricUnavailableValueのトリガー条件にマッチするようなイベントが頻発しているのかについても解明されていない状況でした。
- 環境間の差分を元に、複合要因の不具合を読み解く
The value of the metric to return to the HPA if Datadog doesn’t find a metric value for the specified time window. If not set, an error will be returned to the HPA, which will log a warning. (Optional, This value can be a float)
documentの詳細を紐解いても、Datadogクエリが何らかの過程で取得できないケースでこの設定は機能するとありますが、設定値上のスケールトリガーとなるDatadog metricsクエリを叩いても、直近までの値がUI上からは問題無く確認できます。
何度かこの事象に対するClaude Codeへの事実の再提示と、仮説の再検証を進めていくことで、ようやく全容がつかめてきました。
上記の図にある通り、KEDAのDatadog Scaler設定、Datadogのrollup関数の仕様、これらの連動に起因する複合的な不具合でした。不具合が発生した環境ではKEDAのtrigger metricsを取得するウィンドウ設定であるageが、rollupクエリの設定値と同一の60に設定されており、また、rollupをモニター等に設定するべき場合に推奨されるtimeWindowOffsetによる遅延が設定されていませんでした。
これにより、以下の事象が発生していました。
- Sidekiq Prometheus Exporter経由でカスタムメトリクスが出力される
- Datadog Agent経由で一定時間毎にDatadogへメトリクスが送信される
- rollup(60)はNm00s - Nm59sの間にDatadog Agentから送られたデータを集計する(series集計バケット)
- rollup(60)はseriesとして
Nm00s,N+1m00sにデータポイントを示す(unix timestamp準拠) - 結果として、KEDA Datadog Scalerが、既存設定(
age=60,timeWindowOffset=0)に基づき、rollup(60)をクエリした場合、集計遅延に基づきseriesが空のケースが発生しうる - fallbackとして機能すべき
metricUnavailableValueが不具合のため機能せず、結果としてScaledObjectのエラーが発現
これを回避するには、age=90, timeWindowOffset=60のような形でrollup関数の仕様に併せた修正を入れるのが望ましいです。
修正後のScaledObject設定例
apiVersion: keda.sh/v1alpha1
kind: ScaledObject
metadata:
labels:
scaledobject.keda.sh/name: batch-scaledobject
name: batch-scaledobject
spec:
cooldownPeriod: 300
maxReplicaCount: 2
minReplicaCount: 1
pollingInterval: 30
scaleTargetRef:
apiVersion: apps/v1
envSourceContainerName: batch
kind: Deployment
name: example-batch
triggers:
- authenticationRef:
kind: ClusterTriggerAuthentication
name: keda-operator
metadata:
age: '90'
metricUnavailableValue: '0'
query: max:sidekiq.example.sidekiq_queue_latency_seconds{*}.rollup(60)
queryValue: '120'
timeWindowOffset: '60'
metricType: Value
type: datadog
上記により、KEDAのスケーリングプロセスが、評価遅延を元に確定済みのseriesがトリガーメトリクスとして正しく取得されるよう改善されます。
以下は修正後のプロセス図です。
Claude Codeを活用し、Kubernetes Ecosystemの改善に貢献する
しかしながら、トリガーメトリクスを取得時、一定確率でネットワーク起因のエラー等が発現するため、根本的にはKEDA本体にて不具合が修正されることが望ましいです。今回のケースでは不具合が確認できた時点ではIssue報告が無かった為、Issueを起票しました。
起票にもClaude Codeを全面的に活用しています。
今回の不具合、Issue起票を通じてDatadog Scalerの実装に関して、コードリーディングをClaude Codeの解説を参考に進めました。
不具合の影響範囲が限定的で、修正が比較的容易だったこともあり、折角の機会なので、今回は修正PRの作成も対応しています。
筆者はGoでのプログラミングにそこまで精通しているわけではありませんが、メンテナーのレビューに大いに助けられながら、テスタビリティを担保しつつ、保守性も一定考慮した実装ができました。
Coding Agentの活用を通じて、普段触り慣れてない言語への越境が容易になっているという感触を得ました。一方で、設計に関する実装者による考慮は未だ必須であるため、ここは熟慮が必要になります。
まとめ
今回の不具合対応を通じて、Kubernetes Ecosystemに代表されるような、複雑にコンポーネント、技術スタックが絡み合うような不具合でも、Claude Codeとの協働で原因分析、修正対応可能であることが見えてきました。今回の調査は約3〜4時間で完了しましたが、従来のエンジニアリングでは完全な全容解明に1日以上を要する可能性が高い内容でした。
特に、普段触ってないコードの理解、分析、検証におけるテスト用のコマンドサンプルの作成等、特定領域においてかなりの力を発揮します。
また、今回の障害調査では、原因特定に即座に至ることはありませんでしたが、辛抱強く事実を元に検証プロセスを回して、事象の全体像を掴むのには大いに役に立ちました。
今回提示した調査対応については、以下を意識することでAI Agentから良質なアウトプットを得られると感じています。
- 仮説の妥当性についての検証に関し、キーファクターに関するソースの提示を求める
- source/log/metrics/trace等の事実ベースでの仮説検証を求める
- 検証に利用するコマンド、クエリ等を自然言語ベースで作成指示し、検証プロセスを効率化する
- 複雑な事象についての理解について、自身の理解を投げかけて、齟齬がないか認識合わせをする
- 具体例を使った説明を求めることで、事象に対する解像度を上げる
- 例:mermaid等を利用した図解の指示等
一方で、ユーザーに阿りすぎる傾向があり、使いこなすにはユーザー側の批判的思考が必須だなという感触をまだ覚えます。
この辺りはそのうち改善されるのかもしれませんが、当面は良いところ、要注意なところを意識しながらClaude CodeのようなAI Agentと付き合っていきたいと思います。
Discussion