こんにちは。株式会社FLINTERS エンジニアの瀬田です。
FLINTERSブログ祭りの企画に沿って今回の記事を執筆しました。
はじめに
Amazon ECS(Elastic Container Service)は、DockerコンテナをAmazon Web Service(AWS)上で実行・管理するためのサービスとして広く利用されています。しかし、AWS環境でのデプロイとローカル環境での開発・テストの間にはさまざまな問題が潜んでおり、コンテナをローカル環境で正確にテストするのは難しいことがあります。
特に、AWS Software Development Kit(SDK) を使って他のAWSサービスを操作する際には次のような処理を書くことがあると思います。
# Python版のSDK(boto3)でのコード url_path = os.environ.get("AWS_CONTAINER_CREDENTIALS_RELATIVE_URI") url = urljoin("http://169.254.170.2", url_path) res = requests.get(url, timeout=3).json() os.environ["AWS_ACCESS_KEY_ID"] = res["AccessKeyId"] os.environ["AWS_SECRET_ACCESS_KEY"] = res["SecretAccessKey"] os.environ["AWS_SESSION_TOKEN"] = res["Token"] self.session = boto3.Session( aws_access_key_id=os.environ["AWS_ACCESS_KEY_ID"], aws_secret_access_key=os.environ["AWS_SECRET_ACCESS_KEY"], aws_session_token=os.environ["AWS_SESSION_TOKEN"], )
上記は、ECS上では必要な処理でありますが、ローカル環境で動かそうとするとエラーが起きます。
またECSで用いるIAMロールも含めて検証しようとすると、都度ECSにデプロイして動作確認する必要がありました。
その解決策として、AWSからAmazon ECS Local Container Endpointsが提供されています。このツールはECSのモックエンドポイントをローカル環境で提供し、開発者がローカル環境でのテストをクラウド環境と同じようにシンプルかつ効率的に行えるようにします。
Amazon ECS Local Container Endpointsとは?
Amazon ECS Local Container Endpointsは、ローカル環境でのECSタスクの実行をシームレスにするためのツールです。これにより、開発者はクラウドのリソースをローカルに模擬し、デプロイ前に詳細なテストを行うことができます。
主要な機能は次のとおりです:
- モックエンドポイントの提供: ローカル環境でECS Task IAM RolesとECS Task Metadataのモックエンドポイントを立て、AWS上のような振る舞いをシミュレートします。
- IAMポリシーの検証: AWSコンテナランタイムに似た仕組みをローカルで再現し、IAMポリシーの検証を容易にします。
- ローカルデバッグ: AWS環境にデプロイする前に、細かなデバッグ作業をローカルで行うことができます。
なぜ使うべきか?
ECS Local Container Endpointsを使用する利点はいくつかあります。
1. 開発・デプロイのスピードアップ
AWS上にデプロイせずに、ローカル環境で即座にテスト・デバッグが可能です。これにより、開発サイクルが高速化します。
2. 一貫性のある環境の再現
モックエンドポイントを用いることで、AWS環境とローカル環境での挙動が一致し、不整合を減少させます。結果として、本番環境における予測外の動作を事前に察知しやすくなります。
3. コスト削減
テストをAWS環境上で実行する必要がないため、開発コストが下がります。必要に応じてモックエンドポイントを活用することで、有料リソースの利用を抑えられます。
セットアップ方法
前提
以下のコードを動かすことを前提とします。
S3からファイルを取得し、内容を出力するコードです。
sample.py
import os import boto3 import requests from urllib.parse import urljoin # AWS_CONTAINER_CREDENTIALS_RELATIVE_URI環境変数からURLパスを取得 url_path = os.environ.get("AWS_CONTAINER_CREDENTIALS_RELATIVE_URI") # ECSタスクロールエンドポイントのURLを構築 url = urljoin("http://169.254.170.2", url_path) # ECSタスクロールエンドポイントから認証情報を取得し、JSONとしてパース res = requests.get(url, timeout=3).json() # 取得した認証情報を環境変数に設定 os.environ["AWS_ACCESS_KEY_ID"] = res["AccessKeyId"] os.environ["AWS_SECRET_ACCESS_KEY"] = res["SecretAccessKey"] os.environ["AWS_SESSION_TOKEN"] = res["Token"] # 取得した認証情報を使用して、Boto3セッションを作成 session = boto3.Session( aws_access_key_id=os.environ["AWS_ACCESS_KEY_ID"], aws_secret_access_key=os.environ["AWS_SECRET_ACCESS_KEY"], aws_session_token=os.environ["AWS_SESSION_TOKEN"], ) # S3クライアントを作成 s3_client = session.client("s3") # S3バケットからオブジェクトを取得 response = s3_client.get_object(Bucket="ecs-local-endpoints-sample", Key="sample.txt") content = response['Body'].read().decode('utf-8') print(content)
1. ローカル環境での準備
ディレクトリ構成
構成は以下のようになります。
. ├── sample.py ├── Dockerfile ├── compose.yml └── compose.override.yml
Docker関連のファイル作成
ファイルはそれぞれ以下の内容で作成します。
Dockerfile
FROM python:3.10-slim-buster RUN pip install --upgrade pip RUN pip install boto3 requests WORKDIR /usr/app/sample ENTRYPOINT ["tail", "-f", "/dev/null"]
compose.yml
services: sample-app: build: context: . volumes: - .:/usr/app/sample ports: - 8000:80
compose.override.yml
networks: credentials_network: # ECSのメタデータをローカルで再現するためのネットワークを作成 # ローカルメタデータサービスが特定のIPアドレスにバインドできるように構成 driver: bridge ipam: config: - subnet: "169.254.170.0/24" gateway: 169.254.170.1 services: ecs-local-endpoints: image: amazon/amazon-ecs-local-container-endpoints volumes: # /var/runをマウントして、docker.sockにアクセスしてDockerと通信できるようにする - /var/run:/var/run # AWS CLIとAWS SDKで使用される共有構成ディレクトリをマウント - $HOME/.aws/:/home/.aws/:ro environment: # ホームフォルダを定義 # 資格情報は$HOME/.awsから読み取られる HOME: "/home" # 使用するAWS CLIプロファイルを指定 AWS_PROFILE: <profile name> networks: credentials_network: # ECSメタデータのエンドポイント ipv4_address: "169.254.170.2" sample-app: depends_on: - ecs-local-endpoints networks: credentials_network: ipv4_address: "169.254.170.3" environment: AWS_DEFAULT_REGION: "ap-northeast-1" # タスクロールを用いない場合 # AWS_CONTAINER_CREDENTIALS_RELATIVE_URI: "/creds" # タスクロールを用いる場合 AWS_CONTAINER_CREDENTIALS_RELATIVE_URI: "/role/<AWSで用いているロール名>"
2. AWS上での準備
S3バケットの構成
S3バケットecs-local-endpoints-sample
には、sample.txt
を以下のように配置してください。
ecs-local-endpoints-sample └── sample.txt
IAMロールの設定
ポリシーの設定
今回使用するIAMロールに対して、以下のポリシーを設定してください
- AmazonEC2ContainerServiceRole
- AmazonS3ReadOnlyAccess
信頼ポリシーの設定
ECSで用いるIAMロールに対し、以下の信頼ポリシーを設定してください
{ "Version": "2008-10-17", "Statement": [ { "Sid": "statement1", "Effect": "Allow", "Principal": { "Service": "ecs.amazonaws.com" }, "Action": "sts:AssumeRole" }, { "Sid": "Statement2", "Effect": "Allow", "Principal": { "AWS": "arn:aws:iam::<AWSアカウントID>:root" }, "Action": "sts:AssumeRole" } ] }
3. コンテナの起動
以下のコマンドを実行し、コンテナを起動します。
docker compose -f compose.yml -f compose.override.yml up -d
これで、開発中のコンテナに加えてモックエンドポイントが起動し、ローカル環境でもAWS環境さながらをテストが可能になります。
おわりに
Amazon ECS Local Container Endpointsは、ローカル環境でAWS ECSのテストを簡潔かつ効率的に行うための非常に強力なツールです。 これにより、開発者はローカルとAWS環境での不整合を避けつつ、高速なデバッグと開発を実現できます。
ぜひこのツールを活用し、検証を一層スムーズに進めてみてください。