0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

AIにインフラ構築からデバッグまで任せたら、分散トレースPoCが1日で終わった

0
Posted at

マイクロサービスの可視化において、分散トレースは強力な武器です。しかし、いざ共通プラットフォームに分散トレースを導入しようとすると、自動計装の裏に潜む「サンプリング仕様の不整合」や「通信経路上のセキュリティ制限」といった厄介なトイル(手作業の繰り返しや検証の壁)が立ちはだかります。

私たちのチームでは、金融系システムのモダン化に伴い、GKE + Istio + Spring Boot 3.5 + Datadog という構成で「W3C Trace Context」の伝搬フィジビリティを検証する必要がありました。

私たちはこの面倒な検証作業を、インフラ定義や図面作成の「SKILL(手順書や設計方針)」を搭載したAIエージェント(MCPツール群)に、検証計画書を1枚渡して「ガードレール付きで丸投げ」してみました。結果、AIはネットワーク起因のSSLエラーや、分散トレースのサンプリング仕様に起因する問題を自律的に切り分け、今回設定した検証項目を1日で完了しました。その一部始終を、具体的なコードと共にお届けします。


1. GKE × Datadogで分散トレースを検証する

私たちのチームが直面していたのは、レガシーなアプリケーションをコンテナ環境に移行し、かつシステム全体の可視性を担保する仕組みを整えることでした。

今回、モダン化プラットフォームの移行先としてGoogle CloudのGKE(Google Kubernetes Engine)を利用しています。

このGKE上のプラットフォーム層(Cloud Service Mesh)とアプリケーション層(Spring Boot 3.5)を跨いでリクエストを追跡するため、今回のPoCでは業界標準である「W3C Trace Context(traceparentヘッダー)」がサービス間で適切に伝搬されることを重要な検証項目としました。自動計装を使えば「簡単に繋がる」と記述されていますが、実際にはプラットフォームのデフォルト設定やエンタープライズ特有のセキュリティガードレールと干渉し、無音でトレースが消え去るリスクを孕んでいました。

私たちは、開発チームの手を煩わせることなく、こうした複雑な挙動を網羅的に検証するためのPoC(概念実証)を行うと決めました。ただし、トイルを極力減らすため、自律的に動くAIエージェントに環境構築からデバッグ、検証までを託すという新たなアプローチを試みました。


2. AIエージェントに渡したのは検証計画と2つのSKILL

今回、AIエージェントに渡したのは完成済みの検証環境ではありません。

人間が定義したのは、「W3C Trace Contextが同期・非同期のサービス間通信を跨いで伝搬できること」といった検証目的と成功条件、そして共通プラットフォームで守るべき設計ルールです。

そのうえで、AIエージェントには以下の2つの「ガードレール(SKILL)」を事前に与えました。

  • インフラ命名規則・設計SKILL: 共通プラットフォームで規定されている命名規則、ネットワークトポロジー、リソース配置方針などをマークダウン化したナレッジ。
  • Draw.io作図SKILL: 設計した検証環境の構成図をコードから自動生成・修正するためのプロトコル。

ここで重要なのは、検証用のインフラ構成そのものもAIエージェントが設計した点です。

検証計画に記載した確認観点から、AIは必要となる通信パターンを整理し、GKE上に複数のSpring Bootサービスを配置しました。

同期通信については、Ingress GatewayからサービスAへリクエストを送り、さらにサービスAからサービスBへHTTP通信を行う経路を構成しました。これにより、Ingress、サービスA、サービスBを跨いで traceparent がどのように伝搬するかを確認できるようにしました。

さらに、実際のシステムではHTTPによる同期通信だけでなく、メッセージングを利用した非同期処理も存在します。

そこでAIエージェントは、Google Cloud Pub/Subを経由する非同期通信の検証経路も追加しました。 サービスAがメッセージをPublishし、別のサービスがSubscriberとして受信・処理する構成を作成します。 HTTP通信では、W3C Trace Contextの traceparent / tracestate をHTTPヘッダーとしてサービス間に伝搬できます。一方、Pub/SubのようなメッセージングではHTTPのリクエストチェーンとは異なるため、メッセージ属性などをcarrierとしてトレースコンテキストを受け渡す必要があります。 今回のPoCでは、同期HTTP通信におけるトレースコンテキストの伝搬だけでなく、Pub/Subを介した非同期処理においても、PublisherとSubscriberの処理をトレースとして関連付けられるかを検証対象としました。

poc.ping.png

つまり今回AIに任せたのは、単なるアプリケーションコードの生成ではありません。

検証目的から必要なインフラと通信経路を逆算し、同期通信・非同期通信を含む検証アーキテクチャを設計し、Terraform等のインフラ定義、Spring Bootの検証アプリケーション、Dockerfile、動作確認スクリプト、構成図まで一式を作成したうえで、実際にデプロイして検証するところまでをAIエージェントに委譲しました。

人間が用意したのは「何を確認できれば成功なのか」と「どのルールを守らなければならないか」です。

その制約の内側で、「どういう環境を作ればその事実を証明できるか」はAI自身に考えさせました。


3. PoCで詰まった2つのポイント

しかし、検証環境(Colima + Docker)やクラウドの検証用環境へのデプロイにおいて、AIエージェントはすぐに「エンタープライズの洗礼」を受けることになりました。

Netskope配下でGradleのHTTPS通信が失敗する

AIエージェントはDockerビルド中にJavaのGradle Wrapperを使って外部へビルド資材をHTTPSで取得しようとしました。しかし、社内ネットワーク上のセキュリティ(NetskopeによるHTTPSインスペクション)に阻まれます。

コンテナ内のJava実行環境の truststore には、再署名を行う社内プロキシのCA証明書が含まれていません。結果、ビルドは以下の例外を吐いて呆気なく停止しました。

javax.net.ssl.SSLHandshakeException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target

AIエージェントはSSL検証を無効化するのではなく、社内セキュリティプロキシのCA証明書をビルドコンテキストに配置し、Dockerfile内でJVMの truststorecacerts)へ登録するステップを追加しました。 これにより、社内ネットワークのセキュリティポリシーを維持したまま、コンテナ内のGradleからHTTPS通信を成立させ、ビルドを継続できました。

※以下の例では、Dockerfileと同じビルドコンテキスト配下に ./certs/security-ca.crt として社内セキュリティプロキシのCA証明書を配置しています。

FROM eclipse-temurin:21-jdk AS builder 

WORKDIR /app 

# 社内セキュリティプロキシのCA証明書を先に配置 
COPY certs/security-ca.crt /tmp/security-ca.crt 

# JVMのtruststoreへCA証明書を登録 
RUN keytool -importcert \
    -trustcacerts \
    -file /tmp/security-ca.crt \
    -alias security-ca \
    -keystore "$JAVA_HOME/lib/security/cacerts" \
    -storepass changeit \
    -noprompt

# ビルドに必要なファイルをコピー 
COPY . . 

RUN ./gradlew build --no-daemon

Trace IDはあるのにDatadog APMに出てこない

第一の壁を突破し、GKE上にデプロイされた複数Pod間の通信(サービスA -> サービスB)に対して動作確認シナリオを実行したAIエージェントは、さらに不気味な現象に遭遇しました。

「ログにはトレースIDが出力されているのに、Datadog APMの画面にトレースが一切表示されない」

調査を進めたAIは、プラットフォーム側のインフラ(Cloud Service Mesh / Istio Ingress Gateway)とアプリケーション側のDatadog Java Agentにおける「サンプリング仕様の不整合」を突き止めました。

  1. インフラ側の仕様: Istio Ingress Gatewayではサンプリングレートがデフォルトで 1% に設定されており、99%のリクエストに traceparent に含まれる sampled bit が 0 の状態でアプリケーションまで伝搬する。
  2. Javaアプリ側の仕様: Javaアプリ側で DD_TRACE_SAMPLE_RATE=1.0(100%記録)を設定していても、Datadog Java Agentは上流(Istio)から引き継いだ traceparenttrace-flags: 00 を忠実に尊重し、トレースデータの送信を無効化(ロスト)してしまう。

4. IstioのサンプリングとMANUAL_KEEPを検証する

この自動計装の挙動自体は仕様に沿ったものですが、実運用では「特定の重要な通信」や「障害解析のために意図的に残したいトレース」について、アプリケーション側から保持判断を制御したいケースがあります。

この問題を解決し、実際にカスタム制御コードをコンパイルするためには、あらかじめ build.gradle でDatadog TracerのAPIライブラリへの依存関係を宣言しておく必要があります。

AIエージェントはこの不整合に対する検証として、Datadog Java Tracerが提供するManual Keep機能を利用しました。

アプリケーションコードから現在のアクティブSpanを取得し、DDTags.MANUAL_KEEP を設定することで、通常のサンプリング判断とは別に「このトレースを保持対象とする」という意思をTracerへ伝えます。

import datadog.trace.api.CorrelationIdentifier;
import datadog.trace.api.DDTags;
import io.opentracing.Span;
import io.opentracing.util.GlobalTracer;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class TraceController {

    @GetMapping("/api/execute")
    public String executeWithTrace() {
        Span span = GlobalTracer.get().activeSpan();

        if (span != null) {
            // このリクエストをDatadog Tracer側で明示的にKeep対象とする
            span.setTag(DDTags.MANUAL_KEEP, true);
        }

        String traceId = CorrelationIdentifier.getTraceId();
        System.out.println("Processing request under trace_id: " + traceId);

        return "Successfully processed";
    }
}

カスタム制御用APIをアプリケーションから参照する場合は、PoCで実際に使用したDatadog Java Agentと互換性のあるバージョンを明示します。

dependencies { 
    implementation 'org.springframework.boot:spring-boot-starter-web' 
    
    // Datadog Tracer API 
    implementation 'com.datadoghq:dd-trace-api:<PoCで検証したバージョン>' 
    
    // GlobalTracer / Spanの参照に利用 
    implementation 'io.opentracing:opentracing-api:0.33.0' 
    implementation 'io.opentracing:opentracing-util:0.33.0'
}

このワークアラウンドを適用することで、Istio Ingress Gatewayを通過する際に「非サンプリング」と判定されたリクエストについても、Javaアプリケーション側から明示的に保持対象として指定できることを確認しました。

今回のPoCでは、Datadog Java Agentをコンテナイメージへ組み込み、JVM起動時に -javaagent を指定する方式を採用しました。

# JVM起動引数にDatadog Agentをインジェクションする
ENTRYPOINT ["java", "-javaagent:/app/dd-java-agent.jar", "-jar", "app.jar"]

5. PoCをAIエージェントに任せて分かったこと

今回AIエージェントに任せた作業には、単なるコード生成だけでなく、Terraformによるインフラ定義、Spring Bootの検証アプリケーション作成、Dockerイメージのビルド、GKEへのデプロイ、疎通確認、ログ確認、Datadog APM上でのトレース確認、失敗時の原因調査、設定変更、再デプロイまでが含まれています。

私は個々のコマンド実行や設定変更を逐次指示するのではなく、検証目的、成功条件、プラットフォーム上の制約を与え、その範囲内での試行錯誤をAIエージェントへ委譲しただけです。

人間が同じPoCを行っていた場合、Netskopeのハンドシェイクエラーでの環境構築の挫折、サンプリングフラグが意図せず上書きされてロストする仕様解明などに追われていたはずです。

今回のPoCを通じて見えてきたのは、「AIに何も考えず丸投げできる」という未来ではありません。 AIエージェントが自律的に動けた背景には、人間があらかじめ検証目的、成功条件、命名規則、ネットワーク設計方針といったガードレールを定義していたことがあります。 そのうえで、環境構築、コード生成、デバッグ、再検証といった反復作業をAIへ委譲することで、人間のエンジニアは、アーキテクチャ上の意思決定や「何を検証すべきか」「どの制約を守るべきか」という設計に、より多くの時間を使えるようになります。

AIエージェントに「適切な計画」と「共通のルール」というガードレールを与え、その範囲内で実装・調査・検証のループを自律実行させる。人間が設計と意思決定を担い、AIが実装と反復検証を高速に回す。この役割分担が、これからのプラットフォーム開発におけるひとつの形になると考えています。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?