継続は力なり

タイトル通り定期的な更新を心掛けるブログです。

ECS Fargate で動作する FastAPI のコードを X-Ray でトレースする

タダです.

前回 Amazon Linux2 の上で FastAPI のコードに X-Ray を仕込みました.今回は ECS Fargate 上で動作する FastAPI のコードから X-Ray にトレースした情報を送る時に設定する内容をさらったので整理してきます.

sadayoshi-tada.hatenablog.com

ECS Fargate から X-Ray にトレース情報を送る設定

FastAPI のコードで X-Ray のセグメントを指定する部分は前回と変わらないため,割愛して ECS Fargate から X-Ray にトレース情報を送る部分にフォーカスしていきます.なお,ECS Fargate はプライベートサブネットに展開され,X-Ray にデータを送るために NAT Gateway を経由するような構成で確認しています.

1, X-Ray のコンテナをサイドカーとしてタスク定義する

EC2 同様に ECS Fargate でも X-Ray にデータを送る,X-Ray デーモンが必要です.そのためのサイドカーをタスク定義にいれます.まず,ECR に登録するコンテナの Dockerfile はドキュメントに沿って作りました.このコンテナを ECR に登録します.

FROM amazonlinux
RUN yum install -y unzip
RUN curl -o daemon.zip https://s3.dualstack.us-east-2.amazonaws.com/aws-xray-assets.us-east-2/xray-daemon/aws-xray-daemon-linux-2.x.zip
RUN unzip daemon.zip && cp xray /usr/bin/xray
ENTRYPOINT ["/usr/bin/xray", "-b", "0.0.0.0:2000"]
EXPOSE 2000/udp

次にタスク定義ですが,次のようにしました.ドキュメントにはログ出力の定義がありませんでしたが,動作状況を確認できるようCloudWatch Logs に出力する定義を追加しています.この設定でタスク定義に登録します.

    {
      "logConfiguration": {
        "logDriver": "awslogs",
        "options": {
          "awslogs-group": "/ecs/XXXXXXXXXXXX",
          "awslogs-region": "ap-northeast-1",
          "awslogs-stream-prefix": "ecs"
        }
      },
      "portMappings": [
        {
          "protocol": "udp",
          "containerPort": 2000
        }
      ],
      "cpu": 32,
      "memoryReservation": 256,
      "image": "XXXXXXXXXXXX.dkr.ecr.ap-northeast-1.amazonaws.com/XXXXXXXXXXXX:latest",
      "name": "xray-daemon"
    }

参考情報

docs.aws.amazon.com

2, ECS のタスク実行ロールに権限を付与する

タスク定義が終わったら次はタスク実行ロールの設定が必要です.今回は AWS 管理ポリシーであるAWSXRayDaemonWriteAccessを使いました.ポリシーの中身は次のようになってます.

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "xray:PutTraceSegments",
                "xray:PutTelemetryRecords",
                "xray:GetSamplingRules",
                "xray:GetSamplingTargets",
                "xray:GetSamplingStatisticSummaries"
            ],
            "Resource": [
                "*"
            ]
        }
    ]
}

3, X-Ray でのトレース結果の確認

1,2の設定を終えた後タスクを起動して動作確認してみました.タスクを起動させてところ画像のようにサイドカーで起動してきます.ログをみてみると,コンテナの起動ログとは別に [Info] Successfully sent batch of 1 segments というメッセージが出力されました.

f:id:sadayoshi_tada:20210502235804p:plain f:id:sadayoshi_tada:20210502234903p:plain

X-Ray の画面で確認してみたところトレースした情報が表示されました.

f:id:sadayoshi_tada:20210502235031p:plain

まとめ

ECS Fargate 上で動作する FastAPI のコードに X-Ray を仕込んでトレース情報を収集するための設定を ECS Fargate 周りにフォーカスして整理しました.ここまでで単一のコードに対する X-Ray の設定はできましたが,他サービスとの統合や他のコードへの展開も考えていかなければならないため整理ができたら記事にしていきます.

AWS のリソースを Terraform ファイルに変換する『aws2tf』を使ってみる

タダです.

AWSリポジトリを見ていたら aws2tf というツールを見つけました. Terrafrom を使ってのリソース管理をし始めたのでどんな動きをするかを知りたくてこのツールを使ってみることにしました.この記事で aws2tf のツールをさらっていければと思います.

aws2tf って?

このツールは AWS のアカウントの設定を読み込んで tf ファイルを生成するものです.ツールの中では terraform impotterraform plan を実行して tf ファイルを作っているようです.記事を書いている時点では開発中のステータスです.

Work in progress - please report any issues you find

github.com

使用上の前提条件

aws2tf を使う条件として次のものがあります.AWS CLIjq もツール内部で使っているのかと想像できます.

macOS 10.15.7 以上

AWS CLI v2 バージョン 2.1.15 以上かつ読み取り権限のアクセスを持つこと

terraform バージョン v0.14.3 以上

jq バージョン 1.6 以上

サポートされているリソース

記事執筆時点のサポートされているリソースは以下のものです.

  • App Mesh
  • Athena
  • AutoScaling
  • CloudTrail
  • CloudWatch Logs
  • CodeBuild
  • CodePipeline
  • Config
  • Directory Services
  • EC2
  • ECS
  • EKS
  • ALB
  • NLB
  • Glue
  • IAM
  • KMS
  • Lambda
  • Resource Groups
  • RDS
  • Route53
  • S3
  • Sercice Discovery
  • VPC

aws2tf の実行

早速ツールを使ってみます.サポートされている全リソースの取り込みを行うのは下記コマンド1発で終わりです.scriptsディレクトリ下のgetから始まるスクリプトが実行されます.

$ ./aws2tf.sh 
~中略~

---------------------------------------------------------------------------
aws2tf output files are in generated/tf.[アカウント番号]
---------------------------------------------------------------------------

$ tree scripts
scripts
├── 030-get-iam-users.sh
├── 034-get-iam-groups.sh
├── 050-get-iam-roles.sh
├── 051-get-iam-role-policies.sh
├── 052-get-iam-attached-role-policies.sh
├── 055-get-iam-policies.sh
├── 056-get-instance-profile.sh
├── 060-get-s3.sh
├── 061-get-s3-policies.sh
├── 062-get-s3-aps.sh
├── 070-get-cw-log-grp.sh
├── 080-get-kms-key.sh
├── 081-get-kms-alias.sh
├── 090-get-cloudtrail.sh
├── 100-get-vpc.py
├── 100-get-vpc.sh
├── 101-get-vpc-cidr.sh
├── 105-get-subnet.sh
├── 110-get-security-group.sh
├── 111-get-dhcp-options.sh
├── 120-get-igw.sh
├── 130-get-natgw.sh
├── 135-get-transit-gateway-vpc-attachments.sh
├── 140-get-route-table.sh
├── 141-get-route-table-associations.sh
├── 161-get-vpce.sh
├── 201-get-transit-gateway.sh
├── 202-get-transit-gateway-route-tables.sh
├── 209-get-transit-gateway-route-table-associations.sh
├── 210-get-vpcpeer.sh
├── 220-get-custgw.sh
├── 225-get-cvpn-endpoints.sh
├── 227-get-vpn-connections.sh
├── 240-get-directories.sh
├── 250-get-instances.sh
├── 252-get-c9.sh
├── 255-get-launch-templates.sh
├── 260-get-autoscaling-groups.sh
├── 300-get-eks-cluster.sh
├── 350-get-ecs-cluster.sh
├── 351-get-ecs-task.sh
├── 360-get-appmesh-mesh.sh
├── 410-get-config-recorder.sh
├── 412-get-config-delivery_channel.sh
├── 414-get-config-recorder-status.sh
├── 420-get-config-rule.sh
├── 440-get-ssm-doc.sh
├── 442-get-ssm-association.sh
├── 601-get-rds-ins.sh
├── 611-get-dms-ins.sh
├── 612-get-dms-endp.sh
├── 613-get-dms-tasks.sh
├── 625-get-code-build-project.sh
├── 629-get-code-pipeline.sh
├── 650-get-glue.sh
├── 660-athena-queries.sh
├── 700-get-lambda-function.sh
├── 800-get-cloudfront-dist.sh
├── 810-get-wafv2.sh.tfbug

スクリプトが終わると generated/tf.[アカウント番号]ディレクトリ下に tf ファイルが作られます.また,スクリプトの実行結果はimport.logに残るようです.スクリプトの結果はすごい勢いで流れるのでどこで成功,失敗しているのかをみるのに良さそうです.

tree generated/tf.[アカウント番号] 
generated/tf.[アカウント番号]
├── aws.tf
├── aws_autoscaling_group__xxx.tf
~中略~
├── data
│   ├── aws_xxx.json
~中略~
├── import.log
├── import_.sh
├── terraform.tfstate
└── tf2.tmp

個別実行をしたい場合は次のようにサポートされているようなので,特定リソースの tf ファイルを生成されます.

  • Transit Gateway リソース : ./aws2tf.sh -t tgw -i transit-gateway ID
  • VPC リソース: ./aws2tf.sh -t vpc -i VPC ID
  • EKS リソース: ./aws2tf -t eks -i Cluster-Name
  • ECS リソース: ./aws2tf -t ecs -i Cluster-Name
  • IAM リソース: ./aws2tf -t iam
  • KMS リソース: ./aws2tf -t kms
  • Code 系リソース: ./aws2tf -t code
  • AppMesh リソース: ./aws2tf -t appmesh

また,アカウントが複数ある場合は AWS CLI のプロファイルを使ってツールを実行します.リージョンもパラメーターで指定できます.

./aws2tf.sh  -r [リージョン名] -p [プロファイル名]

所感

ざっと使ってみて感じたところをまとめてみます.

  • ツールの実態がシェルスクリプト になっており,読み解きやすいツールになっていると感じた
    • scriptsディレクトリ のスクリプトAWS CLI のコマンド群で書かれているため AWS CLI に慣れていればこのツールを使うだけでなくサポートされてないリソースの変換もできそう
  • これは好みの問題と思いますが tf ファイルの生成が1ファイルごとになっているため,例えば VPC のリソースを見ようとするときに各ファイルの中身を見ないとわからない
    • 似たようなツールで TerraformerTerraforming は1ファイルでサポートリソースの情報を入れてくれる

まとめ

aws2tf のツールの概要と実際に使ってみた所感をまとめてみました.冒頭に書いたように現在開発中のツールというところで興味があればフィードバックなどで参加してみるのも良いかもしれません.

ECS Fargate で Mackerel コンテナエージェントによる監視設定をする

タダです.

業務で ECS Fargate の監視をしていく時に Mackerel のコンテナエージェントをセットアップするやり方を確認しました.設定方法をこの記事でまとめていきます.

確認した環境

今回のセットアップを確認した環境はコンテナエージェントのバージョンが1.4.0 で確認しています.

コンテナエージェントのセットアップ

コンテナエージェントのセットアップについてはドキュメントの記載があり,サイドカーとして ECS クラスターの中で動作させます.コンテナエージェントを動作させるには,Fargate のプラットフォームバージョンが 1.3.0以降である必要があります.

AWS Fargate プラットフォームバージョン 1.3.0以降

mackerel.io mackerel.io

また,サイドカーとして動かすコンテナはタスク定義で以下の設定が必要です.

  • コンテナ名:mackerel-container-agent
  • コンテナイメージ: mackerel/mackerel-container-agent:latest
  • メモリ制限: ハード制限: 128
  • 環境変数: MACKEREL_CONTAINER_PLATFORM: "ecs",MACKEREL_APIKEY: Mackerel API キー

Systems Manager Parmeter Store に Mackerel API キーを保管

Mackerel API キーは直に環境変数に設定するのではなく Systems Manager Paramater Store に Secure String として Mackerel API キーの文字列を入れてコンテナ起動時に読み込むよう事前準備で設定しておきます.

f:id:sadayoshi_tada:20210420230701p:plain

ECS Fargate のタスク定義にコンテナエージェントの設定を追加

そして,アプリケーションのコンテナのタスク定義と一緒に次のような定義を追加していきます.また,タスクの実行ロールで Systems Manager Paramater Store の読み取り権限も付与して準備が完了です.

      {
        "name":"mackerel-container-agent",
        "image":"mackerel/mackerel-container-agent:latest",
        "memoryReservation": 128,
        "essential":true,
        "environment": [
          {
            "value": "ecs",
            "name": "MACKEREL_CONTAINER_PLATFORM"
          }
        ],
        "secrets": [
          {
            "valueFrom": "mackerel_agent_apikey",
            "name": "MACKEREL_APIKEY"
          }
        ]     
      }

コンテナエージェント起動後の Mackerel 管理画面での確認

コンテナエージェントが正常に起動すれば Mackerel に監視対象ホストとして登録されます.コンテナごとの CPU 使用量,コンテナごとのメモリ使用量,コンテナごとのインタフェースの送受信バイト数がメトリックとして確認できるようになりました.

f:id:sadayoshi_tada:20210420231120p:plain

まとめ

ECS Fargate 環境での Mackerel コンテナエージェントの導入方法をまとめていきました.この記事では触れられてないですがEC2 の監視同様にプラグイン監視も公開されたイメージを使うことで監視ができるようになるため適宜利用していきましょう.

hub.docker.com

FastAPI のコードを X-Ray を使ってトレーシングする

タダです.

FastAPI を業務のアプリケーションで扱う割合が増えつつあるのですが,FastAPI のパフォーマンスを見えるよう可視化していくために X-Ray を試す機会があったのでこの記事にまとめていきます.

X-Ray について

X-Ray はアプリケーションの処理するリクエストに関する処理時間を収集するサービスで,トレーシングすることでボトルネックの可視化やどこで問題が起こっているかなども見えます.ログ以外の観点でアプリケーションの状態を見る手段が欲しくて X-Ray を試してみることにしたので検証をしてみました.

docs.aws.amazon.com

サポートされている言語

サポートされている言語は Java/Node.js/Python/Go/Ruby/C# です.なお,今回使う Python ではフレームワークとして Django と Flask がサポートされており,ミドルウェアを使ってアプリケーションの受信リクエストを計測できますが,FastAPI はサポートされてないようなのでミドルウェアを使った受信リクエストの計測ではなく他の Python コードの部分でのトレーシングをしてみることにしました.

X-Ray の用語

X-Ray での用語も整理しておきます.

  • セグメント: アプリケーションを実行しているコンピューティングリソースを指し,動作に関するデータを送信する
  • サブセグメント: セグメントからダウンストリーム呼び出しのアプリケーションビューを表し,AWS サービス,外部 HTTP API,SQL データベースの呼び出しに関する情報を含める
  • サービスグラフ:アプリケーションが送信したデータを使って表現されるグラフ

FastAPI のコードに X-Ray を組み込む

それでは FastAPI のコードの中に X-Ray を仕込んでいきます.まず,Amazon Linux2 の EC2 上で FastAPI の開発環境を作ってライブラリと X-Ray にデータを送るデーモンを導入します.FastAPI の導入は公式ドキュメントに沿って行います.

# X-Ray のライブラリの導入
$ pip install aws-xray-sdk

# X-Ray デーモン導入
$ curl https://s3.dualstack.ap-northeast-1.amazonaws.com/aws-xray-assets.ap-northeast-1/xray-daemon/aws-xray-daemon-3.x.rpm -o /home/ec2-user/xray.rpm
$ sudo yum install -y /home/ec2-user/xray.rpm

# FastAPI と uvicorn の導入
$ pip install fastapi uvicorn

X-Ray SDK for Python を使ってライブラリにパッチを適用し,ダウンストリーム呼び出しを実装していくのですが,FastAPI で{"Hello":"World"}と返すだけのコード(main.py)で組み込んでみます.これでpython main.pyをしてアクセスしてみます.

from aws_xray_sdk.core import xray_recorder
from aws_xray_sdk.core import patch_all
from fastapi import FastAPI

xray_recorder.configure(service='FastAPI')
plugins = ('EC2Plugin')
xray_recorder.configure(plugins=plugins)
patch_all()


app = FastAPI()

xray_recorder.begin_segment('FastAPITest')
@app.get("/")
def read_root():
    return{"Hello":"World"}

xray_recorder.end_segment()

{"Hello":"World"}が返ってきたのと X-Ray のサービストレース画面でもFastAPITestのセグメントが記録されました.

FastAPI のアプリケーションにアクセスした画面 f:id:sadayoshi_tada:20210417175028p:plain

X-Ray のサービストレース画面 f:id:sadayoshi_tada:20210417174902p:plain

まとめ

まずはさくっと FastAPI のコードに X-Ray を組み込んで可視化してみました.業務の中でも取り込んでいくのでその時のハマりポイントやどういう風に取り込んでいったのかをまたブログにできたらと思います!

暗号化した Aurora スナップショットを別アカウントで復元する

タダです.

本番環境から別アカウントに暗号化した Aurora スナップショットを共有し,仕組み化して復元する時に少し手間取ったので対応をまとめていきます.

暗号化した Aurora スナップショットを共有する設定

Aurora スナップショットを共有する方法は AWS のドキュメントに記載があります.共有したいスナップショットの設定で共有するアカウント番号を指定すれば共有できます.

aws.amazon.com

AWS CLI でやるとスナップショット作成と共有するアカウント設定は以下のコマンドでできます.

aws rds create-db-cluster-snapshot \
    --db-cluster-identifier [クラスター名] \
    --db-cluster-snapshot-identifier [スナップショット名]

aws rds modify-db-cluster-snapshot-attribute \
    --db-cluster-snapshot-identifier [スナップショット名] \
    --attribute-name restore \
    --values-to-add [共有するアカウント番号]

今回は更に KMS(CMK)でスナップショットを暗号化しているため KMS でも別アカウントからアクセス許可を次のようなポリシーの形で与えてあげる必要があります.

{
  "Id": "key-policy-1",
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "Allow use of the key",
      "Effect": "Allow",
      "Principal": {"AWS": [
        "arn:aws:iam::111111111111:user/xxx",
        "arn:aws:iam::[共有するアカウント番号]:root"
      ]},
      "Action": [
        "kms:CreateGrant",
        "kms:Encrypt",
        "kms:Decrypt",
        "kms:ReEncrypt*",
        "kms:GenerateDataKey*",
        "kms:DescribeKey"
      ],
      "Resource": "*"
    },
    {
      "Sid": "Allow attachment of persistent resources",
      "Effect": "Allow",
      "Principal": {"AWS": [
        "arn:aws:iam::111111111111:user/xxx",
        "arn:aws:iam:::[共有するアカウント番号]:root"
      ]},
      "Action": [
        "kms:CreateGrant",
        "kms:ListGrants",
        "kms:RevokeGrant"
      ],
      "Resource": "*",
      "Condition": {"Bool": {"kms:GrantIsForAWSResource": true}}
    }
  ]
}               
            

docs.aws.amazon.com

共有されたアカウントでの設定

共有されたアカウント側の設定ですが,Lambda などのサービスをつかってスナップショットを復元に使いたい場合 IAM ポリシーの設定が必要です.下記の権限を当てた IAM ロールを作ってサービスで使っていますが,共有したスナップショットを復元してクラスター起動ができました.

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "AllowUseOfTheKey",
            "Effect": "Allow",
            "Action": [
                "kms:Encrypt",
                "kms:Decrypt",
                "kms:ReEncrypt*",
                "kms:GenerateDataKey*",
                "kms:DescribeKey",
                "kms:CreateGrant",
                "kms:RetireGrant",
                "kms:DescribeKey"
            ],
            "Resource": [
                "arn:aws:kms:[リージョン]:[CMK が存在するアカウント番号]:key/[CMK の ID]"
            ]
        }
}

まとめ

暗号化した Aurora スナップショットを別アカウントで復元するための設定と権限周りの定義をさらってきました.共有したアカウントの IAM ポリシーでうまく復元ができずにいたのですが,通る形を確認できてよかったです.同じような仕組み化する方の参考になれば嬉しいです!