AWSでサーバーレスバッチ処理のアーキテクチャを考えてみた

## 概要

AWSのフルマネージド型バッチ処理サービスのAWS Batchを使用して、サーバーレスバッチ処理をTerraform構築してみます。
ソースはこちら: [777nancy/batch-infra](https://github.com/777nancy/batch-infra)

## 前提

- 定期処理を想定
    - 日次
    - 月次
- バッチ処理のコンテナイメージは別途用意が必要
    - 本記事ではDocker Hubのbusyboxを使用
- コンピューティングリソースにFargate Spotを使用
    - 運用する場合はFargateの使用を想定

## 構成図

![architecture.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/639315/0be942c6-5b36-d46b-2346-af9c4f0c131d.png)

## AWSサービス

- AWS Batch
  - Fargate
- AWS Step Functions
- Amazon EventBridge

## Terraform

ジョブ、ステートマシーンを説明します。

### Job Definitions

本記事ではbusyboxのコンテナイメージを使用したジョブを定義しています。
運用する場合は、実行する処理(コンテナイメージ)の数に合わせてジョブを定義します。

```terraform:batch.tf
resource "aws_batch_job_definition" "busybox_job_definition" {
  name = "${var.system}-busy-box-job-definition"
  type = "container"
  platform_capabilities = [
    "FARGATE",
  ]
  container_properties = templatefile(
    "container_properties/busybox.tftpl",
    {
      execution_role_arn = aws_iam_role.aws_batch_execution_role.arn
      job_role_arn       = aws_iam_role.aws_batch_job_role.arn
  })
  tags = {
    "Name" = "${var.system}-busy-box-job-definition"
  }
  depends_on = [
    aws_iam_role.aws_batch_execution_role,
    aws_iam_role.aws_batch_job_role
  ]
}
```

```json:container_properties/busybox.tftpl
{
    "command": [
        "echo",
        "test"
    ],
    "image": "busybox",
    "fargatePlatformConfiguration": {
        "platformVersion": "1.4.0"
    },
    "networkConfiguration": {
        "assignPublicIp": "ENABLED"
    },
    "resourceRequirements": [
        {
            "type": "VCPU",
            "value": "0.25"
        },
        {
            "type": "MEMORY",
            "value": "512"
        }
    ],
    "executionRoleArn": "${execution_role_arn}",
    "jobRoleArn": "${job_role_arn}"
}
```

実行するコンテナイメージに合わせてレジストリを設定します。(AWSのサービスであればAmazon ECRのレジストリ)
また、AWSのブログで[Creating a Simple “Fetch & Run” AWS Batch Job](https://aws.amazon.com/jp/blogs/compute/creating-a-simple-fetch-and-run-aws-batch-job/)より、シンプルなジョブのコンテナイメージ作成方法が紹介されています。
```json
"image": "busybox"
```

また、Fargateは`4 vCPU-30GB`の上限あります。

```json
"resourceRequirements": [
        {
            "type": "VCPU",
            "value": "0.25"
        },
        {
            "type": "MEMORY",
            "value": "512"
        }
    ]
```

### State Machine

State Machineを使用して、ジョブの依存関係を定義します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/639315/564b2b72-0e8f-8dcd-a297-3b824afa0ad1.png)

```json
{
    "Comment": "batch-system-state-machine",
    "StartAt": "first_job",
    "States": {
        "first_job": {
            "Type": "Task",
            "Resource": "arn:aws:states:::batch:submitJob.sync",
            "Parameters": {
                "JobName": "first_job",
                "JobDefinition": "${job_definition_arn}",
                "JobQueue": "${job_queue_arn}",
                "ContainerOverrides": {
                    "Command": [
                        "echo",
                        "first",
                        "job"
                    ]
                }
            },
            "Next": "second_job"
        },
        "second_job": {
            "Type": "Task",
            "Resource": "arn:aws:states:::batch:submitJob.sync",
            "Parameters": {
                "JobName": "second_job",
                "JobDefinition": "${job_definition_arn}",
                "JobQueue": "${job_queue_arn}",
                "ContainerOverrides": {
                    "Command": [
                        "echo",
                        "second",
                        "job"
                    ]
                }
            },
            "End": true
        }
    }
}
```

各ステートごとに[Job Definitions](#JobDefinitions)で定義している実行コマンドを上書きできるため、同じジョブ定義でも異なる処理を実行できます。

```json
"ContainerOverrides": {
                    "Command": [
                        "echo",
                        "second",
                        "job"
                    ]
                }
```

## 課題

- Fargateのリソース制限
    - GPU使用不可
    - `4 vCPU-30GB`以上のリソースを指定不可
    - 上記のリソースを使用する場合処理はAWS BatchでコンピューティングリソースにEC2を使用
        - EC2を使用する場合はサーバーレスではない


## 最後に

Terraformを勉強し始めたばかりで、汎用的な記述になっていませんが、本記事が誰かのお役に立てれば幸いです。