はじめに
AWS Lambda から ECS Fargate タスクを起動する方法について、自分の備忘録としてまとめました。
マイグレーションコンテナは、以下の記事で詳しく説明しているので気になる方は、参考にしてみてください。
個人の備忘録程度の走り書きとなっておりますが、温かい目で見守っていただければ幸いです。
書こうと思ったきっかけ
受講している IT スクールのハッカソンでチーム開発を進める中、Lambda から ECS タスクを起動する仕組みを実装しました。その際に IAM ポリシーや Lambda のエラーで詰まったため、今後の自分や他の人が同じことでつまづかないように記事にしておきます。
つまづいた内容
必要な IAM ロール
以下の IAM ポリシーを Lambda の実行ロールに付与する必要があります。
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"logs:CreateLogGroup",
"logs:CreateLogStream",
"logs:PutLogEvents"
],
"Resource": "arn:aws:logs:*:*:*"
},
{
"Effect": "Allow",
"Action": [
"ecs:RunTask",
"ecs:DescribeTasks",
"ecs:DescribeTaskDefinition"
],
"Resource": "*"
},
{
"Effect": "Allow",
"Action": "iam:PassRole",
"Resource": [
"arn:aws:iam::xxx:role/prod-ecs-task-role",
"arn:aws:iam::xxx:role/prod-ecs-task-execution-role"
]
}
]
}
作成後の画面
実装済み Lambda 関数
boto3
の run_task
メソッドは datetime
オブジェクトを含むため、json.dumps(..., default=str)
を使用してレスポンスを文字列化しています。
import os
import boto3
import json
def lambda_handler(event, context):
ecs = boto3.client('ecs')
response = ecs.run_task(
cluster=os.environ['ECS_CLUSTER_NAME'],
taskDefinition=os.environ['ECS_TASK_DEFINITION'],
launchType='FARGATE',
networkConfiguration={
'awsvpcConfiguration': {
'subnets': os.environ['SUBNETS'].split(','),
'securityGroups': os.environ['SECURITY_GROUPS'].split(','),
'assignPublicIp': 'ENABLED' if os.environ.get('ASSIGN_PUBLIC_IP', 'false').lower() == 'true' else 'DISABLED'
}
}
)
print("Task started successfully:", response)
return {
"statusCode": 200,
"headers": {
"Content-Type": "application/json"
},
"body": json.dumps({
"status": "invoked",
"detail": response
}, default=str)
}
環境変数の確認(必要なもの)
この Lambda 関数を正常に動作させるために、以下の環境変数を設定しておく必要があります:
ECS_CLUSTER_NAME
ECS_TASK_DEFINITION
-
SUBNETS
(カンマ区切り) -
SECURITY_GROUPS
(カンマ区切り) -
ASSIGN_PUBLIC_IP
(オプション、true/false)
実際の実行後結果
問題なく起動して、マイグレーションされていることが確認できました!
まとめ
Lambda から ECS タスクを起動する際には、IAM の iam:PassRole
の対象リソースが正しく設定されているか、また boto3
のレスポンスを JSON に変換できるかに注意する必要があります。
小さなミスで大きなハマりポイントになるので、この記事が誰かの助けになればうれしいです...!