掲題の件、閉じたVPCからECS FargateをXRayでトレース取る手順です。
VPC Endpoint作成
ネットワーク繋がらない環境なので、XRayへのVPC Endpoint作成しておきます。こちらは省略します。
aws-xray-daemonの準備
ECSのXRay連携ではサイドカーとしてaws-xray-daemonを起動することになります。
自分でビルドしたりも可能ですが、今回はPublicのECRから取得してきます。以下のURLになります。
ドキュメントに記載されていることが多い、Docker Hubにあるamazon/aws-xray-daemon
と名前が変わっていて xray/aws-xray-daemon
となっていることに注意です。
Pull Through Cache
当然、閉じたVPCからPublicのECRにアクセスできないので、ECRのPull Through Cacheを利用します。設定としてはTerraformで言えば以下の標準的なものを利用してみます。
resource "aws_ecr_pull_through_cache_rule" "example" {
ecr_repository_prefix = "ecr-public"
upstream_registry_url = "public.ecr.aws"
}
後はECRへのVPC Endpointを作成すれば、以下の名前でxray/aws-xray-daemon
をPullできるようになります。
123456789012.dkr.ecr.ap-northeast-1.amazonaws.com/ecr-public/xray/aws-xray-daemon:latest
IAM権限
タスク実行ロールにECR Pull Through Cache用権限付与
ECR Pull Through Cacheから xray/aws-xray-daemon
をPullするため、こちらのドキュメントを参照して以下のような権限から必要なものを与えます。
- ecr:CreatePullThroughCacheRule
- ecr:BatchImportUpstreamImage
- ecr:CreateRepository
こちらはECSの タスク実行ロール
に設定します。
タスクロールにXRay Daemon用権限付与
こちらは以下のマネージドポリシーの利用することが可能です。 タスクロール
にアタッチしておきます。
- arn:aws:iam::aws:policy/AWSXRayDaemonWriteAccess
ECSタスク定義
ECSタスク定義の例は以下の通りです。
{
"networkMode": "awsvpc",
"cpu": "2048", # xray-daemonのCPUも合計値に含まれるので注意
"memory": "4096", # xray-daemonのMemoryも合計値に含まれるので注意
"containerDefinitions": [
# mainコンテナ等
{
"name": "xray-daemon",
"image": "123456789012.dkr.ecr.ap-northeast-1.amazonaws.com/ecr-public/xray/aws-xray-daemon:latest", # ECR Pull Through Cacheを指定
"cpu": 32,
"memoryReservation": 256,
"portMappings": [
{
"containerPort": 2000,
"hostPort": 2000, # hostPortとcontainerPortの値は合わせる
"protocol": "udp"
}
]
}
],
"logConfiguration": {
"logDriver": "awslogs",
"options": {
"awslogs-group": "/ecs/xxxx",
"awslogs-region": "ap-northeast-1",
"awslogs-stream-prefix": "logs",
"max-buffer-size": "25m",
"mode": "non-blocking"
}
}
}
Pythonに組み込み
後はPythonに組み込みます。
poetry add aws-xray-sdk
# or
pip install aws-xray-sdk
from aws_xray_sdk.core import patch_all, xray_recorder
xray_recorder.configure(service="myapp")
plugins: tuple[str] = ("ECSPlugin",) # Tupleである必要があるので注意
xray_recorder.configure(plugins=plugins)
patch_all()
if __name__ == "__main__":
xray_recorder.begin_segment(name="Main")
main(env=EnvironmentToFargateTask.parse_obj(env))
xray_recorder.end_segment()