- 公開日
- 最終更新日
AWS FargateでS3上のCSVを集計するシンプルなバッチ処理を構築してみた
この記事を共有する
目次
1. はじめに
パーソル&サーバーワークスの菅野 索です。
AWSを中心としたクラウドインフラの設計・構築・運用を担当しています。
今回はAWS Fargateを利用し、Amazon S3に保存したCSVファイルを集計するシンプルなバッチ処理を構築しました。
検証を目的とした構成のため、ネットワークはPublic Subnetを利用したシンプルな構成としています。本番環境ではPrivate SubnetやVPC Endpointの利用を検討してください。
2. AWS Fargateとは
AWS Fargateは、Amazon ECS向けのサーバーレスコンテナ実行サービスです。
従来のコンテナ実行環境ではEC2インスタンスの管理が必要でしたが、Fargateではコンテナ実行基盤をAWSが管理します。
そのため利用者は、コンテナイメージの作成やタスク定義の作成、アプリケーション開発に集中できます。
主な特徴は以下の通りです。
- コンテナ実行基盤の管理が不要
- ECSとの統合が容易
- コンテナ単位でCPU・メモリを指定可能
- 必要なタイミングでコンテナを起動可能
コンテナ実行基盤の運用負荷を軽減できる点がFargateの大きな特徴です。
3. 今回やること
今回はS3に保存したCSVファイルを読み込み、売上金額を集計するバッチ処理を作成します。
入力データは以下の通りです。
【csv】
date,amount
2025-01-01,1000
2025-01-02,1500
2025-01-03,2000
実行結果は以下になります。
Total Amount : 4500
4. LambdaではなくFargateを選んだ理由
今回の処理はAWS Lambdaでも実装できます。
一方で今回は以下の理由からFargateを選択しました。
- コンテナ実行環境を試したかった
- Pythonアプリケーションをそのままコンテナ化できる
- 将来的な処理拡張に対応しやすい
小規模な処理であればLambdaも有力な選択肢です。一方で、コンテナベースの実行環境やECSの基本的な仕組みを学習する用途では、Fargateは理解しやすい選択肢の一つだと感じました。
5. 構成図

今回利用したAWSサービスは以下です。
- Amazon ECS(AWS Fargate)
- Amazon ECR
- Amazon S3
- Amazon EventBridge Scheduler
- Amazon CloudWatch Logs
本構成では、EventBridge SchedulerからECSのRunTask APIを実行し、Fargateタスクを起動しています。
6. 集計プログラムについて
今回は以下のPythonコードを利用しました。
ここを押すと展開します
import os
import boto3
import csv
from io import StringIO
s3 = boto3.client("s3")
bucket_name = os.environ["BUCKET_NAME"]
response = s3.get_object(
Bucket=bucket_name,
Key="sales.csv"
)
csv_data = response["Body"].read().decode("utf-8")
reader = csv.DictReader(
StringIO(csv_data)
)
total = sum(
int(row["amount"])
for row in reader
)
print(f"Total Amount : {total}")
処理内容はシンプルで、S3からCSVファイルを取得し、amount列の値を集計してCloudWatch Logs上に出力します。
6-1 コンテナイメージについて
今回は検証用途だったため、CloudShellを利用してDockerイメージを作成し、Amazon ECRへプッシュしました。
ローカル環境を準備することなくAWS上だけで検証できるため、手軽に試せる点が便利でした。
※今回は最低限の構成のためrequirements.txtは作成しておりません。
6-2 Dockerfile
コンテナ化には以下のDockerfileを利用しました。
FROM python:3.11-slim
WORKDIR /app
COPY app.py .
RUN pip install --no-cache-dir boto3
CMD ["python", "app.py"]
6-3 インフラ構成
インフラはCloudFormationで作成しました。
今回作成した主なリソースは以下の通りです。
※以下作成リソースのCloudFormationコードは「12. 参考」に記載しております。
- VPC
- Public Subnet
- Internet Gateway
- Amazon ECR
- Amazon ECS Cluster
- ECS Task Definition
- Amazon S3
- Amazon CloudWatch Logs
- IAM Role
- Amazon EventBridge Scheduler
6-4 Fargateタスク定義
今回利用したタスク定義の主要部分は以下の通りです。
ここを押すと展開します
TaskDefinition:
Type: AWS::ECS::TaskDefinition
Properties:
Family: csv-batch
RequiresCompatibilities:
- FARGATE
Cpu: 256
Memory: 512
NetworkMode: awsvpc
ContainerDefinitions:
- Name: csv-batch
Environment:
- Name: BUCKET_NAME
Value:
6-5 検証用CSV
S3へ配置するCSVファイルです。
今回は環境変数 BUCKET_NAME で指定したS3バケットへ sales.csv という名前で配置しています。
date,amount
2025-01-01,1000
2025-01-02,1500
2025-01-03,2000
7. 実際の構築手順
7-1 CloudFormationテンプレートを作成
以下URLを参照し、CloudFormationにてリソースを作成します。 コンソールを使用して CloudFormation スタックを作成する
7-2 格納用CSVファイル作成
CloudShellを起動して以下コマンドでエディタを起動し、格納用CSV(### 検証用CSVの内容を参照)を作成し保存(:wq)します。
vi sales.csv
7-3 CloudFormationで作成されたS3バケットへアップロード
以下コマンドで、S3上にCSVをコピーします。
aws s3 cp sales.csv s3://<作成したバケット名>/
7-4 プログラムファイル作成
以下コマンドでエディタを起動し、集計用プログラム(### 集計プログラムについて)を作成し保存(:wq)します。
vi app.py
7-5 Dockerfile作成
以下コマンドでエディタを起動し、Dockerfile(### Dockerfile)を作成し保存(:wq)します。
vi dockerfile
7-6 Dockerイメージを作成
docker build -t csv-batch-app .
7-7 Amazon ECRへイメージをプッシュ
以下のコマンドにてローカルにビルドしたDockerイメージが存在することを確認します。
docker images | grep csv-batch-app
上記でECRリポジトリが確認できたら以下のコマンドを実行します。
ここを押すと展開します
ACCOUNT_ID=$(aws sts get-caller-identity --query Account --output text)
REGION=${AWS_REGION}
aws ecr get-login-password \
| docker login \
--username AWS \
--password-stdin \
${ACCOUNT_ID}.dkr.ecr.${REGION}.amazonaws.com && \
docker tag csv-batch-app:latest \
${ACCOUNT_ID}.dkr.ecr.${REGION}.amazonaws.com/csv-batch-app:latest && \
docker push \
${ACCOUNT_ID}.dkr.ecr.${REGION}.amazonaws.com/csv-batch-app:latest
7-8 EventBridge Schedulerにてスケジュール作成
以下URLを参照し、スケジュールを作成します。
EventBridge Schedulerにてスケジュールを作成し、ターゲットとしてECSのRunTaskを指定します。
また今回の検証では、パブリックサブネットを利用しているため、同じ構成にする場合は「自動割り当てパブリック IP」を有効化にするのを忘れないで下さい。

例えば以下のcron式を設定すると、毎時0分にFargateタスクを実行できます。
cron(0 * * * ? *)
これにより指定したスケジュールでFargateタスクを自動実行できます。
8. 実際の動作
EventBridge Scheduler にてタスク実行後、CloudWatch Logsを確認すると以下の通り出力されました。


期待通りにCSV内の金額を集計できていることを確認できました。
9. 構築時の気づき
CloudWatch Logsは早めに設定しておく
当初ログ出力設定を用意しておらず、タスク実行の問題調査に時間がかかりました。
Fargateを利用する場合は、まず最初にCloudWatch Logsを設定し、ログを確認できる状態にしておくことをおすすめします。
Fargateではawsvpcが必須
Fargateでは以下の設定が必須です。
NetworkMode: awsvpc
当初は「FargateはサーバーレスサービスであるためVPCは不要ではないか」と考えていました。
しかし実際にはFargateで実行されるタスクはVPC内のサブネット上で起動するため、VPCやサブネット、セキュリティグループなどのネットワーク設定が必要です。
また、ECSはコンテナ実行を管理するコントロールプレーンとして動作し、Fargateはコンテナ実行環境を提供する役割(データプレーン)を担っています。
Fargateを利用する際は、コンテナだけでなくネットワーク構成についても理解しておくことが重要だと感じました。
EventBridge Scheduler スケジュール作成時は「自動割り当てパブリック IP」を有効化が必要
スケジュール作成時に自動割り当てパブリック IPを有効化していなかったため、手動ではECSからFargateを起動できるが、スケジュール実行だと起動できない事象に陥り、原因を突き止めるのに時間がかかってしまいました。
パブリックサブネット上でFargateをスケジュール実行する場合は自動パブリックIP割り当て有効化が必要なのだと勉強になりました。
10. やってみた感想
今回Fargateを利用したバッチ処理を構築しましたが、コンテナ実行基盤を意識せずにアプリケーション開発へ集中できる点が印象的でした。
Lambdaと比較すると設定項目は増えますが、一度コンテナ化してしまえば実行環境の差異を意識せずに運用できる点は大きなメリットだと感じています。
またECSの基本要素であるCluster、Task Definition、Taskの関係についても理解を深めることができました。
11. まとめ
今回はAWS Fargateを利用して、S3上のCSVファイルを集計するシンプルなバッチ処理を構築しました。
Lambdaでも実現可能な処理ではありますが、コンテナベースのアプリケーション実行やECRとの連携、EventBridge Schedulerによる定期実行など、ECS/Fargateを利用したバッチ処理の基本構成を一通り確認できました。
FargateはWebアプリケーションだけでなく、定期実行バッチやデータ処理ジョブとの相性も良くコンテナ運用を学習する入り口としても有用なサービスだと感じています。
なお、今回は検証用途としてPublic Subnet構成を採用しましたが、本番環境ではPrivate SubnetやVPC Endpointを利用した閉域構成を検討することをおすすめします。
同様の構成を検討している方や、これからECS/Fargateを学習する方の参考になれば幸いです。
12. 参考
リソース作成用CloudFormationコード
ここを押すと展開します
AWSTemplateFormatVersion: '2010-09-09'
Description: CSV Aggregation Batch using AWS Fargate
Resources:
VPC:
Type: AWS::EC2::VPC
Properties:
CidrBlock: 10.100.0.0/16
EnableDnsSupport: true
EnableDnsHostnames: true
InternetGateway:
Type: AWS::EC2::InternetGateway
VPCGatewayAttachment:
Type: AWS::EC2::VPCGatewayAttachment
Properties:
VpcId: !Ref VPC
InternetGatewayId: !Ref InternetGateway
PublicSubnet:
Type: AWS::EC2::Subnet
Properties:
VpcId: !Ref VPC
AvailabilityZone: !Select [0, !GetAZs '']
CidrBlock: 10.100.1.0/24
MapPublicIpOnLaunch: true
PublicRouteTable:
Type: AWS::EC2::RouteTable
Properties:
VpcId: !Ref VPC
DefaultRoute:
Type: AWS::EC2::Route
DependsOn: VPCGatewayAttachment
Properties:
RouteTableId: !Ref PublicRouteTable
DestinationCidrBlock: 0.0.0.0/0
GatewayId: !Ref InternetGateway
PublicSubnetAssociation:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
RouteTableId: !Ref PublicRouteTable
SubnetId: !Ref PublicSubnet
FargateSecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: Fargate Batch Security Group
VpcId: !Ref VPC
SecurityGroupEgress:
- IpProtocol: "-1"
CidrIp: 0.0.0.0/0
SalesBucket:
Type: AWS::S3::Bucket
Properties:
BucketName: !Sub sales-batch-${AWS::AccountId}-${AWS::Region}
ECRRepository:
Type: AWS::ECR::Repository
Properties:
RepositoryName: csv-batch-app
LogGroup:
Type: AWS::Logs::LogGroup
Properties:
LogGroupName: /ecs/csv-batch
RetentionInDays: 30
ECSCluster:
Type: AWS::ECS::Cluster
Properties:
ClusterName: csv-batch-cluster
TaskExecutionRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Principal:
Service:
- ecs-tasks.amazonaws.com
Action:
- sts:AssumeRole
ManagedPolicyArns:
- arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy
TaskRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Principal:
Service:
- ecs-tasks.amazonaws.com
Action:
- sts:AssumeRole
Policies:
- PolicyName: ReadCsvFromS3
PolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Action:
- s3:GetObject
Resource:
- !Sub '${SalesBucket.Arn}/*'
TaskDefinition:
Type: AWS::ECS::TaskDefinition
Properties:
Family: csv-batch
RequiresCompatibilities:
- FARGATE
Cpu: 256
Memory: 512
NetworkMode: awsvpc
ExecutionRoleArn: !GetAtt TaskExecutionRole.Arn
TaskRoleArn: !GetAtt TaskRole.Arn
ContainerDefinitions:
- Name: csv-batch
Image: !Sub "${ECRRepository.RepositoryUri}:latest"
Essential: true
Environment:
- Name: BUCKET_NAME
Value: !Ref SalesBucket
LogConfiguration:
LogDriver: awslogs
Options:
awslogs-group: !Ref LogGroup
awslogs-region: !Ref AWS::Region
awslogs-stream-prefix: ecs
Outputs:
BucketName:
Description: S3 Bucket Name
Value: !Ref SalesBucket
RepositoryUri:
Description: ECR Repository URI
Value: !GetAtt ECRRepository.RepositoryUri
ClusterName:
Description: ECS Cluster Name
Value: !Ref ECSCluster
TaskDefinitionArn:
Description: ECS Task Definition ARN
Value: !Ref TaskDefinition
PublicSubnetId:
Description: Public Subnet ID
Value: !Ref PublicSubnet
SecurityGroupId:
Description: Fargate Security Group ID
Value: !Ref FargateSecurityGroup
この記事は私が書きました
菅野 索
記事一覧趣味:ジョギング、散歩
最近体重の増加が気になるので、ダイエット頑張ってます。