🦤

S3からのイベントをトリガにECS Fargateのタスクを起動するEventBridgeを構築した話

2023/04/29に公開

タイトルの通り、S3にファイルが置かれたことをトリガに、ECS Fargateのタスクを起動するEventBridgeをCloudFormationで作成しました。

簡単な構成図はこちら。

今回のポイントは以下2点です。

  1. 特定のディレクトリ(正確にはキー)に配置された時だけイベントを発火したい
  2. 置かれたファイルの情報(ディレクトリ、ファイル名)をFargateのタスクに渡したい

作成したものをベースに、上記2つのポイントに絞って簡単に説明します。

前提

VPC、サブネット、セキュリティグループ、Fargate、S3は作成済みであることを前提としています。
ご自分の環境と照らし合わせて適宜読み替えてくださいm()m。
※ymlファイルの中で個別に修正が必要な箇所には「適宜修正ください」というコメントをつけています。

作ったもの

AWSTemplateFormatVersion: "2010-09-09"
Description: CloudFormation template for EventBridge.

Parameters:
  ProjectName:
    Description: Project name
    Type: String
  ProjectEnv:
    Description: Envirment of project
    Type: String
    AllowedValues:
      - dev
      - stg
      - prd

Resources:
  EventBridgeRole:
    Type: "AWS::IAM::Role"
    Properties:
      RoleName: !Sub ${ProjectName}-${ProjectEnv}-event-bridge-role
      AssumeRolePolicyDocument:
        Version: "2012-10-17"
        Statement:
          - Effect: "Allow"
            Principal:
              Service:
                - "events.amazonaws.com"
            Action:
              - "sts:AssumeRole"
      Policies:
        - PolicyName: !Sub ${ProjectName}-${ProjectEnv}-event-bridge-policy
          PolicyDocument:
            Version: "2012-10-17"
            Statement:
              - Effect: "Allow"
                Action:
                  - "ecs:RunTask"
                Resource:
                  - !Sub arn:aws:ecs:${AWS::Region}:${AWS::AccountId}:task-definition/${ProjectName}-${ProjectEnv}-task-def # 適宜修正ください
              - Effect: "Allow"
                Action:
                  - "iam:PassRole"
                Resource:
                  - "*"
                Condition:
                  StringLike:
                    iam:PassedToService: "ecs-tasks.amazonaws.com"
  EventBridgeRule:
    Type: "AWS::Events::Rule"
    Properties:
      Name: !Sub ${ProjectName}-${ProjectEnv}-event-bridge-rule
      EventPattern:
        source:
          - aws.s3
        detail-type:
          - Object Created
        detail:
          bucket:
            name:
              - !Sub ${ProjectName}-${ProjectEnv}-input-bucket # 適宜修正ください
          object:
            key:
              - prefix: key-name # 適宜修正ください
      Targets:
        - Arn: !Sub arn:aws:ecs:${AWS::Region}:${AWS::AccountId}:cluster/${ProjectName}-${ProjectEnv}-cluster # 適宜修正ください
          Id: !Sub ${ProjectName}-${ProjectEnv}-event-bridge-target # 適宜修正ください
          RoleArn: !GetAtt EventBridgeRole.Arn
          EcsParameters:
            EnableExecuteCommand: false
            LaunchType: FARGATE
            NetworkConfiguration:
              AwsVpcConfiguration:
                AssignPublicIp: ENABLED
                SecurityGroups:
                  - ${セキュリティグループのID} # 適宜修正ください
                Subnets:
                  - ${サブネットのID} # 適宜修正ください
            TaskDefinitionArn: !Sub arn:aws:ecs:${AWS::Region}:${AWS::AccountId}:task-definition/${ProjectName}-${ProjectEnv}-task-def # 適宜修正ください
          InputTransformer:
            InputPathsMap:
              key: "$.detail.object.key"
            InputTemplate: !Sub '{"containerOverrides":[{"name":"${ProjectName}-${ProjectEnv}-container-def","environment":[{"name":"OBJECT_KEY","value":"<key>"}]}]}' # 適宜修正ください

ポイント①:特定のディレクトリ(正確にはキー)に配置された時だけイベントを発火したい

yamlの中の以下の部分です。

      EventPattern:
        source:
          - aws.s3
        detail-type:
          - Object Created
        detail:
          bucket:
            name:
              - !Sub ${ProjectName}-${ProjectEnv}-input-bucket # 適宜修正ください
          object:
            key:
              - prefix: key-name # 適宜修正ください

object.key.prefixの箇所で、イベントを発火させるディレクトリを指定することができます。

ポイント②:置かれたファイルの情報(ディレクトリ、ファイル名)をFargateのタスクに渡したい

yamlの中の以下の部分です。

          InputTransformer:
            InputPathsMap:
              key: "$.detail.object.key"
            InputTemplate: !Sub '{"containerOverrides":[{"name":"${ProjectName}-${ProjectEnv}-container-def","environment":[{"name":"OBJECT_KEY","value":"<key>"}]}]}' # 適宜修正ください

ECSの「コンテナの上書き」の機能を使って、置かれたファイルの情報を環境変数でFargateに渡すようにします。
これをやるには、TargetsのInputTransformerという項目で指定するようです。わかりにくいです。
この中のInputPathsMapで、keyという項目に取得したパス($.detail.object.key)をマッピングします。
そして、マッピングされた項目はInputTemplateの中で<key>のように記載することで使用できます。
今回はkeyという名前を使用しましたが、名前はなんでも良いですし、keyに加えてobject-nameも加えるなど、複数の項目をマッピングすることも可能です。

あとは、Fargateの中で、渡された環境変数OBJECT_KEYを参照すればOKです。

Discussion