Help us understand the problem. What is going on with this article?

AWS X-RayをJavaで色々動かして試してみる

前提条件

X-Ray初心者向け。なんとなくは知ってるけど、具体的に何がどこまでできて、どうやって実装するかを色々試してみながら確認した記事。

環境としては、Spring Boot+MavenでWebアプリを実装している。依存関係の解決方法以外はGradleも同じはず。

X-RayのDockerコンテナイメージを作る。

まずは、適当なEC2とかでコンテナイメージを作る。
今回は、AWSのサンプルをベースに作ってみよう。

$ git clone https://github.com/aws-samples/aws-xray-fargate

buildspec.yml に書いてあるコマンドを、実行していってみる。

$ aws ecr get-login --no-include-email --region ap-northeast-1

でログイン情報を取得後、実行。ap-northeast-1は利用しているリージョンを指定する。

$ docker build -t xray:latest .

作ったコンテナイメージは正常性確認をしてみよう。以下を参考にする。
それぞれのdocker runのオプションの意味も記載されているので読んでみると良い。

【公式】ローカルで X-Ray デーモンを実行する

$ docker run \
  --attach STDOUT \
  -v ~/.aws/:/root/.aws/:ro \
  --net=host \
  -e AWS_REGION=ap-northeast-1 \
  --name xray \
  -p 2000:2000/udp \
  xray -o

あと、EC2のロールにAWSXRayDaemonWriteAccessのIAMポリシをつけておく。

アプリケーションのX-Ray対応

受信リクエスト対応

以下の開発者ガイドを参考にしながら、アプリケーション側でX-Rayのログをデーモンに送るようにする。

【公式】AWS X-Ray SDK for Java

受信リクエストの対応をするだけなら簡単なようだ。WebConfig.javaなクラスを以下の様に実装する。ApigwTestは、サンプルで作ったWebアプリの名前。

WebConfig.java
package com.example;

import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Bean;
import javax.servlet.Filter;
import com.amazonaws.xray.javax.servlet.AWSXRayServletFilter;

@Configuration
public class WebConfig {

  @Bean
  public Filter TracingFilter() {
    return new AWSXRayServletFilter("ApigwTest");
  }
}

X-RayはAWSのSDKを使う必要があるため、pom.xmlに以下を記述して依存関係を解決する。

pom.xml
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>com.amazonaws</groupId>
                <artifactId>aws-xray-recorder-sdk-bom</artifactId>
                <version>2.4.0</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <dependencies>
        <dependency>
            <groupId>com.amazonaws</groupId>
            <artifactId>aws-xray-recorder-sdk-core</artifactId>
        </dependency>
    </dependencies>

さて、このアプリを起動してアクセスすると、↓こんな感じでトレースができるようになる。

キャプチャ6.PNG

詳細情報の取得

さらに、受信リクエストを受けたノードの情報を取得できるように、↑で作ったWebConfigクラスに以下のコードを入れてみる。

import com.amazonaws.xray.AWSXRay;
import com.amazonaws.xray.AWSXRayRecorderBuilder;
import com.amazonaws.xray.plugins.EC2Plugin;
import com.amazonaws.xray.plugins.ECSPlugin;

  static {
      AWSXRayRecorderBuilder builder = AWSXRayRecorderBuilder.standard().withPlugin(new EC2Plugin()).withPlugin(new ECSPlugin());

      AWSXRay.setGlobalRecorder(builder.build());
  }

これをEC2上で実行した場合は、以下のように、サービスマップにEC2インスタンスであることが表示されるようになる。

キャプチャ7.PNG

ダウンストリームのトレース対応

さらに、HTTPクライアントとして、ダウンストリームのWebサービスの情報も取得する場合は、コントローラの中に↓こんなのを入れてみる。

import com.amazonaws.xray.proxies.apache.http.HttpClientBuilder;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.impl.client.CloseableHttpClient;
import java.io.IOException;
(中略)
    public int HttpClient(String URL) throws IOException {
        int statusCode = 500;

        CloseableHttpClient httpclient = HttpClientBuilder.create().build();
        HttpGet httpGet = new HttpGet(URL);
        CloseableHttpResponse clientResponse = httpclient.execute(httpGet);

        try {
            statusCode = clientResponse.getStatusLine().getStatusCode();
        } finally {
            clientResponse.close();
        }

        return statusCode;
    }

また、com.amazonaws.xray.proxies.apache.http.HttpClientBuilderをインポートするために、pom.xmlにも以下の依存関係を追記する。

pom.xml
    <dependencies>
        <dependency>
            <groupId>com.amazonaws</groupId>
            <artifactId>aws-xray-recorder-sdk-apache-http</artifactId>
        </dependency>
    </dependencies>

すると、以下のようにダウンストリームの情報も取得できるようになる。

キャプチャ8.PNG

ちなみに、このダウンストリームのサービスはLambda関数で実装していたので、ふと気になってLambda関数側でX-Rayの設定を有効化すると、↓こんな感じで、重複した要素は取得しなくなった。賢い。

キャプチャ9.PNG

ECS on Fargateで動かす

まずは、ここまでで動作確認したX-RayのコンテナをECRにPUSHする。
事前にxrayのリポジトリを作っておくのを忘れないように。

$ docker tag xray:latest [AWSのアカウントID].dkr.ecr.[リージョン].amazonaws.com/xray:latest
$ docker push [AWSのアカウントID].dkr.ecr.[リージョン].amazonaws.com/xray:latest

また、ここでもECSのタスクロールとタスク実行ロールにAWSXRayDaemonWriteAccessを付与しておく。

コンテナのタスク定義に、↑でPUSHしたxrayのイメージを入れる。
CloudFormationテンプレートで言えば、ContainerDefinitions内で、既存のコンテナ定義に並べて以下の定義を書く。awsvpcを使わないECS on EC2の場合は他にも設定が必要だが、Fargateの場合は、awsvpcで動くので、簡単に加えられるようだ。

    - Name: X-Ray-Daemon
      Image: !Sub ${AWS::AccountId}.dkr.ecr.${AWS::Region}.amazonaws.com/xray:latest
      Cpu: 32
      MemoryReservation: 256
      PortMappings:
        - ContainerPort: 2000
          Protocol: udp

Lambda側のアクティブトレースを有効化すると、EC2と同様に取得することができた。

キャプチャ10.PNG

ただし、Lambda側のアクティブトレースを無効にすると、リクエストに対するトレースは取得できたが、ダウンストリームのトレースが取得できなかった。何かまだ足りていない設定があるのかもしれない。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした