AWSのサーバーレスサービスでX-Rayを設定する

こんにちは、香田です。

今回はAWSのサーバーレスサービスでX-Rayを設定する方法について紹介していきます。

サーバーレスアプリケーションを構築し、X-Rayを設定するとどういったことができるか簡単に紹介していきます。

AWS X-Rayとは

AWS X-Rayを使用するとアプリケーションやその基盤となるサービスの実行状況を把握することができ、パフォーマンスの問題やエラーの根本原因を特定し、トラブルシューティングに活用できます。

利用するAWS サーバーレスサービス

今回利用するAWS サーバーレスサービスは、API Gateway、Lambda、SQSとなります。

以降で下記構成を構築していきます。

ローカル開発環境の構築

API Gateway、Lambdaの構築はServerless Frameworkを利用していきます。

ローカル開発環境として、docker-composeを利用しServerless Frameworkを利用できるようにしていきます。

作業ディレクトリを作成します。

mkdir serverless-x-ray
cd serverless-x-ray

Dockerfileを作成します。

FROM node:latest

RUN apt-get update && \
    apt-get install -y python3-pip less jq
RUN npm install -g serverless
RUN curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip" && \
    unzip awscliv2.zip && \
    ./aws/install

docker-compose.ymlを作成します。

version: "3"
services:
  serverless:
    build: .
    image: serverless
    container_name: serverless
    env_file:
      - .env
    tty: true
    volumes:
      - "./:/app"
    working_dir: /app

AWS認証情報を定義した.envファイルを作成します。

AWS_ACCESS_KEY_ID=xxxxx
AWS_SECRET_ACCESS_KEY=xxxxx
AWS_DEFAULT_REGION=ap-northeast-1

各ファイル作成後、下記のような構成になっているはずです。

tree -a
.
├── .env
├── Dockerfile
└── docker-compose.yml

コンテナを起動しログインします。

docker-compose up -d
docker-compose exec serverless bash

serverlessコマンドの実行確認。

serverless --version

AWSサーバーレス環境の構築

SQSを作成します。

aws sqs create-queue --queue-name serverless-app-queue

aws-xray-sdkをインストールし、requirements.txtを作成します。

pip install aws-xray-sdk
pip freeze > requirements.txt

Lambda 関数コードとしてapp.pyという名前でファイルを作成します。

import os
import logging
import json
import boto3
from aws_xray_sdk.core import patch_all
from aws_xray_sdk.core import xray_recorder

xray_recorder.configure(service='serverless-app')
patch_all()

logger = logging.getLogger()
logger.setLevel(logging.INFO)

QUEUE_URL = os.getenv('QUEUE_URL')
SQS = boto3.client('sqs')


def hello(event, context):
    body = {
        "message": "Hello World",
        "input": event
    }

    return {
        "statusCode": 200,
        "body": json.dumps(body)
    }


def producer(event, context):
    status_code = 200
    message = ''

    if not event.get('body'):
        return {'statusCode': 400, 'body': json.dumps({'message': 'No body was found'})}

    try:
        SQS.send_message(
            QueueUrl=QUEUE_URL,
            MessageBody=event['body']
        )
        message = 'Message accepted!'
    except Exception as e:
        logger.exception('Sending message to SQS queue failed!')
        message = str(e)
        status_code = 500

    return {
        'statusCode': status_code,
        'body': json.dumps({'message': message})
    }


def consumer(event, context):
    for record in event['Records']:
        logger.info(f'Message body: {record["body"]}')

X-Rayに関する設定は下記になります。

xray_recorder.configureでサービス名を定義し、patch_all()を設定することで、boto3、requests、psycopg2など下記でサポートされているライブラリのトレースデータを取得できます。

ダウンストリーム呼び出しを計測するためのライブラリへのパッチ適用

xray_recorder.configure(service='serverless-app')
patch_all()

次にServerless Frameworkの設定ファイルであるserverless.ymlを作成します。

service: serverless-app
frameworkVersion: '2'

provider:
  name: aws
  runtime: python3.9
  lambdaHashingVersion: 20201221
  stage: dev
  region: ap-northeast-1
  tracing:
    apiGateway: true
    lambda: true
  iamRoleStatements:
    - Effect: Allow
      Action:
        - sqs:SendMessage
        - xray:PutTraceSegments
        - xray:PutTelemetryRecords
      Resource:
        - "*"

functions:
  hello:
    handler: app.hello
    events:
      - http:
          path: /hello
          method: get
  producer:
    handler: app.producer
    events:
      - http:
          path: /producer
          method: post
    environment:
      QUEUE_URL: https://sqs.${aws:region}.amazonaws.com/${aws:accountId}/serverless-app-queue

  consumer:
    handler: app.consumer
    events:
      - sqs: arn:aws:sqs:${aws:region}:${aws:accountId}:serverless-app-queue

plugins:
  - serverless-python-requirements

Serverless Frameworkでは下記の箇所をtrueに設定することで、API Gateway、Lambdaのトレース設定が有効化されます。

tracing:
  apiGateway: true
  lambda: true

serverless-python-requirementsプラグインをインストールし、requirements.txtの外部パッケージも同梱されるようにします。

serverless plugin install -n serverless-python-requirements

準備ができたので、AWS環境へデプロイします。

serverless deploy -v

X-Rayの確認

デプロイが完了したら、API Gatewayへリクエストをしばらく送信しX-Rayでトレースデータが表示されるか確認します。

API GatewayのIDを確認し環境変数へ設定します。

export API_ID=xxxx

GET リクエストの送信確認。

curl -s -X GET https://$API_ID.execute-api.ap-northeast-1.amazonaws.com/dev/hello | jq .message

POST リクエストの送信確認。

curl -s -X POST https://$API_ID.execute-api.ap-northeast-1.amazonaws.com/dev/producer \
--header 'Content-Type: application/json' \
--data-raw '{"name": "hello world"}' | jq .message

しばらくリクエストを送信後、X-Rayのコンソールより[Service Map]を確認すると下記のように表示されているはずです。

サービスマップを使用するとアプリケーションが処理するリクエストの流れを可視化することが可能です。

エラーが発生しているサービス、高レイテンシーの接続、失敗したリクエストのトレース等を識別できます。

X-Ray コンソールの[トレース]よりトレースリストを使用し、トレースの要約からURL、レスポンス、またはその他のデータによるトレースを検索できます。

下記のようにトレースIDを選択してトレースのタイムラインが表示可能です。

クリーンアップ

作成したAWSリソースを削除していきます。

Serverless Frameworkで作成したリソースを削除します。

serverless remove -v

SQSを削除します。

export AWS_ACCOUT_ID=$(aws sts get-caller-identity --query Account --output text)
aws sqs delete-queue \
--queue-url https://sqs.ap-northeast-1.amazonaws.com/$AWS_ACCOUNT_ID/serverless-app-queue

さいごに

AWSのサーバーレスサービスでX-Rayを設定する方法いかかでしたでしょうか?

数行の設定追加でX-Rayが使用可能なので、アプリケーションや利用しているAWSサービスなどの実行状況やパフォーマンスを把握したい場合有用ではないでしょうか。

最後までご覧いただきありがとうございます。

SNSでもご購読できます。