[アップデート] Amazon ECS が一時領域として Amazon EBS のアタッチをサポートしました

Amazon ECS が コンテナの一時領域として Amazon EBS をサポートしました。機械学習等でパフォーマンスを出したい一時領域の選択肢の1つに名を挙げそうです。
2024.01.28

こんにちは! AWS 事業本部コンサルティング部のたかくに(@takakuni_)です。

Amazon ECS がコンテナの一時領域として Amazon EBS のアタッチをサポートしました。

これにより、サーバレスなコンテナ環境で ETL 処理や機械学習の推論等のデータ集約型のワークロードを実装したい場合の選択肢が増えました!

今まではどうだったか

今まで、データ集約型のワークロードを ECS で実装する場合、データの置き場は以下のようなパターンが考えられました。

  • Amazon S3 にデータを置いておき、コンテナ起動時に持ってくる
  • Amazon EFS に置いてマウントする
  • 巨大なコンテナイメージを作る

今回のアップデートで上記の選択肢に加え、 Amazon EBS をコンテナにアタッチすることができるようになりました。

何が嬉しいのか

先ほど想定したケースだと、以下を懸念する必要がありました。

  • Amazon S3 にデータを置いておき、コンテナ起動時に持ってくる
    • VPC 越しからデータを取得するため、 VPC 内で通信するより、レイテンシは劣る
  • Amazon EFS に置いてマウントする
    • 高い IOPS, スループットで読み書きしたい場合、コストが気になる
    • ストレージ容量に関しても、他のストレージサービスに比べ、コストが気になる
  • 巨大なコンテナイメージを作る
    • コンテナ起動までの時間が気になる
    • 膨大なデータを含めたイメージのビルド(時間)、プッシュが運用面で現実的ではない

Amazon EBS はブロックストレージです。今回のアップデートで以下のメリットを受けることができるようになりました。

  • 料金
    • Amazon EFS に比べて安くパフォーマンスやストレージサイズを提供
  • レイテンシの向上
    • Amazon S3 に比べて早くワークロードを起動できる

注意したい点

あくまで一時ストレージ領域

今回発表された機能はあくまで、一時ストレージ領域として提供されるものとなります。

そのため、サービスで管理しているタスクの場合、タスクの終了時にアタッチされるボリュームは削除される仕様となっています。 1

Volumes that are attached to tasks that are managed by a service are not preserved and are always deleted upon task termination.

Amazon EBS volume termination policy

前提条件

上記に加えて、いくつか前提条件があったため記載します。ざっくりまとめると、以下の通りです。

  • Linux のみサポート
    • Windows コンテナは未サポート
    • Fargate, on EC2 だと Nitro ベースの ECS 最適化 AMI をサポート
  • Fargate Platform 1.4.0 以上のバージョン
  • ECS 最適化 AMI 20231219 以上のバージョン
  • standard タイプ(旧世代)の EBS は未サポート
  • 新しく インフラストラクチャロール が爆誕
    • マネージドポリシー AmazonECSInfrastructureRolePolicyForVolumes が提供されている
  • 各タスクにアタッチできるAmazon EBSボリュームは 1つ まで
    • アタッチされるボリュームは新しいボリュームでなければならない
    • 既存の Amazon EBS ボリュームをタスクにアタッチは不可
    • 既存のボリュームのスナップショットを使用して、デプロイ時に新しい Amazon EBS ボリュームをアタッチするのは可能
  • ローリングアップデートデプロイタイプをサポート
    • B/G はサポートしていない
  • レプリカスケジューリング戦略をサポート
    • デーモンはサポートしていない
  • ボリュームに AmazonECSCreatedAmazonECSManaged タグを付与
    • タグを消すと ECS 側で管理できなくなる
    • パーティション化されたボリュームのアタッチは不可
  • Nitro システムのインスタンスタイプのみサポート
  • AWS Outpost 上で実行されている Amazon ECS タスクは未サポート

最新状況は Amazon EBS volume considerations をご覧ください。

やってみる

今回は簡単に Nginx タスクに EBS ボリュームを当ててみようと思います。まずは、いくつか IAM ロールを作成していきます。

インフラストラクチャロール

今回新たに インフラストラクチャロール と言う名前の IAM ロールが新登場しました。文字通り、 Amazon ECS がインフラストラクチャ(EBS)を管理するためのロールです。

自身でカスタムポリシーを作成するか、マネージドポリシーの AmazonECSInfrastructureRolePolicyForVolumes を設定すれば良さそうです。

信頼ポリシー

assume_infrastructure_iam_role.json

{
  "Version": "2012-10-17", 
  "Statement": [ 
    {
      "Sid": "AllowAccessToECSForInfrastructureManagement", 
      "Effect": "Allow", 
      "Principal": {
        "Service": "ecs.amazonaws.com" 
      }, 
      "Action": "sts:AssumeRole" 
    } 
  ] 
}

IAM ポリシー

AmazonECSInfrastructureRolePolicyForVolumes

{
	"Version": "2012-10-17",
	"Statement": [
		{
			"Sid": "CreateEBSManagedVolume",
			"Effect": "Allow",
			"Action": "ec2:CreateVolume",
			"Resource": "arn:aws:ec2:*:*:volume/*",
			"Condition": {
				"ArnLike": {
					"aws:RequestTag/AmazonECSCreated": "arn:aws:ecs:*:*:task/*"
				},
				"StringEquals": {
					"aws:RequestTag/AmazonECSManaged": "true"
				}
			}
		},
		{
			"Sid": "TagOnCreateVolume",
			"Effect": "Allow",
			"Action": "ec2:CreateTags",
			"Resource": "arn:aws:ec2:*:*:volume/*",
			"Condition": {
				"ArnLike": {
					"aws:RequestTag/AmazonECSCreated": "arn:aws:ecs:*:*:task/*"
				},
				"StringEquals": {
					"ec2:CreateAction": "CreateVolume",
					"aws:RequestTag/AmazonECSManaged": "true"
				}
			}
		},
		{
			"Sid": "DescribeVolumesForLifecycle",
			"Effect": "Allow",
			"Action": [
				"ec2:DescribeVolumes",
				"ec2:DescribeAvailabilityZones"
			],
			"Resource": "*"
		},
		{
			"Sid": "ManageEBSVolumeLifecycle",
			"Effect": "Allow",
			"Action": [
				"ec2:AttachVolume",
				"ec2:DetachVolume"
			],
			"Resource": "arn:aws:ec2:*:*:volume/*",
			"Condition": {
				"StringEquals": {
					"aws:ResourceTag/AmazonECSManaged": "true"
				}
			}
		},
		{
			"Sid": "ManageVolumeAttachmentsForEC2",
			"Effect": "Allow",
			"Action": [
				"ec2:AttachVolume",
				"ec2:DetachVolume"
			],
			"Resource": "arn:aws:ec2:*:*:instance/*"
		},
		{
			"Sid": "DeleteEBSManagedVolume",
			"Effect": "Allow",
			"Action": "ec2:DeleteVolume",
			"Resource": "arn:aws:ec2:*:*:volume/*",
			"Condition": {
				"ArnLike": {
					"aws:ResourceTag/AmazonECSCreated": "arn:aws:ecs:*:*:task/*"
				},
				"StringEquals": {
					"aws:ResourceTag/AmazonECSManaged": "true"
				}
			}
		}
	]
}

今回は、マネージドポリシーをアタッチする形にしました。

タスク実行ロール

ECS サービスで使うタスク実行ロールも今回は 1 から作ります。

信頼ポリシー

assume_task_exec_iam_role.json

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "",
      "Effect": "Allow",
      "Principal": {
        "Service": "ecs-tasks.amazonaws.com"
      },
      "Action": "sts:AssumeRole"
    }
  ]
}

IAM ポリシー

AmazonECSTaskExecutionRolePolicy

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "ecr:GetAuthorizationToken",
                "ecr:BatchCheckLayerAvailability",
                "ecr:GetDownloadUrlForLayer",
                "ecr:BatchGetImage",
                "logs:CreateLogStream",
                "logs:PutLogEvents"
            ],
            "Resource": "*"
        }
    ]
}

タスクロール

ECS Exec をしてタスクからボリュームを見てみたいので、 タスクロールに ECS Exec ができるよう設定していきます。

信頼ポリシー

assume_task_iam_role.json

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "",
      "Effect": "Allow",
      "Principal": {
        "Service": "ecs-tasks.amazonaws.com"
      },
      "Action": "sts:AssumeRole"
    }
  ]
}

IAM ポリシー

ecs-ebs-support-task-policy

{
   "Version": "2012-10-17",
   "Statement": [
       {
       "Effect": "Allow",
       "Action": [
            "ssmmessages:CreateControlChannel",
            "ssmmessages:CreateDataChannel",
            "ssmmessages:OpenControlChannel",
            "ssmmessages:OpenDataChannel"
       ],
      "Resource": "*"
      }
   ]
}

タスク定義の作成

EBS をアタッチするため、 タスク定義を作成します。コンソールを覗くと新しく設定タイプに 「デプロイ時に設定」 が生えてました。ストレージサイズや IOPS はタスク起動時に設定するようです。

コンテナマウントポイントで、ソースボリュームとコンテナパスを設定します。

タスク定義の名前は以下にしました。

  • ecs-ebs-support-taskdef

また、先ほど作成したタスクロール(ecs-ebs-support-task-role)、タスク実行ロール(ecs-ebs-support-task-exec-role)を指定します。

JSON で表現すると以下のようなイメージです。(IAM ロールの部分を置き換えてください)

ecs-ebs-support.json

{
  "family": "ecs-ebs-support-taskdef",
  "containerDefinitions": [
    {
      "name": "nginx",
      "image": "nginx",
      "cpu": 0,
      "portMappings": [
        {
          "name": "nginx-80-tcp",
          "containerPort": 80,
          "hostPort": 80,
          "protocol": "tcp",
          "appProtocol": "http"
        }
      ],
      "essential": true,
      "environment": [],
      "environmentFiles": [],
      "mountPoints": [
        {
          "sourceVolume": "nginx-volume",
          "containerPath": "/ebs",
          "readOnly": false
        }
      ],
      "logConfiguration": {
        "logDriver": "awslogs",
        "options": {
          "awslogs-create-group": "true",
          "awslogs-group": "/ecs/ecs-ebs-support",
          "awslogs-region": "ap-northeast-1",
          "awslogs-stream-prefix": "ecs"
        }
      }
    }
  ],
  "taskRoleArn": "タスクロールの IAM ロール ARN",
  "executionRoleArn": "タスク実行ロールの IAM ロール ARN",
  "networkMode": "awsvpc",
  "volumes": [
    {
      "name": "nginx-volume",
      "configuredAtLaunch": true
    }
  ],
  "requiresCompatibilities": ["FARGATE"],
  "cpu": "512",
  "memory": "1024",
  "runtimePlatform": {
    "cpuArchitecture": "X86_64",
    "operatingSystemFamily": "LINUX"
  }
}

クラスター

ECS サービスを起動するため、クラスターを作成します。

今回は以下のクラスター名、キャパシティープロバイダを選択します。

  • クラスター名:ecs-ebs-support-cluster
  • キャパシティプロバイダ:Fargate 2

サービス

諸々準備が整ったので、サービスからタスクを起動してみます。

  • サービス名:ecs-ebs-support-service

先ほど作成したタスク定義(ecs-ebs-support-taskdef)を指定すると、下にスクロールした時に ボリューム が指定されていました。ボリュームタイプやサイズが指定できそうです。

今回は以下のスペックを指定してみました。

  • Amazon EBS ボリュームタイプ: gp3
  • サイズ:300 GiB
  • IOPS:3000
  • スループット:125
  • スナップショット ID:指定しない
  • ファイルシステムの種類:EXT3
  • インフラストラクチャロール:ecs-ebs-support-infra-role
  • 暗号化:デフォルト

暗号化について

本機能では EBS の暗号化オプションが選択可能でした。ただし、利用するには KMS のキーポリシーに以下のような権限付与が必要です。

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "ReadOnlyPermissions",
      "Effect": "Allow",
      "Principal": {
        "AWS": "arn:aws:iam::111122223333:role/ecsInfrastructureRole"
      },
      "Action": "kms:DescribeKey",
      "Resource": "*"
    },
    {
      "Sid": "DataKeyGenerationForAmazonEBS",
      "Effect": "Allow",
      "Principal": {
        "AWS": "arn:aws:iam::111122223333:role/ecsInfrastructureRole"
      },
      "Action": [
        "kms:GenerateDataKey*",
        "kms:ReEncryptTo",
        "kms:ReEncryptFrom"
      ],
      "Resource": "*",
      "Condition": {
        "StringEquals": {
          "kms:CallerAccount": "aws_account_id",
          "kms:ViaService": "ec2.region.amazonaws.com"
        },
        "ForAnyValue:StringEquals": {
          "kms:EncryptionContextKeys": "aws:ebs:id"
        }
      }
    },
    {
      "Sid": "GrantCreationForAmazonEBS",
      "Effect": "Allow",
      "Principal": {
        "AWS": "arn:aws:iam::111122223333:role/ecsInfrastructureRole"
      },
      "Action": "kms:CreateGrant",
      "Resource": "*",
      "Condition": {
        "StringEquals": {
          "kms:CallerAccount": "aws_account_id",
          "kms:ViaService": "ec2.region.amazonaws.com"
        },
        "ForAnyValue:StringEquals": {
          "kms:EncryptionContextKeys": "aws:ebs:id"
        },
        "Bool": {
          "kms:GrantIsForAWSResource": true
        }
      }
    }
  ]
}

Condition 周りがガッツリ組まれているので、セキュリティレベル落としてシンプルにしたい場合は、以下のようなことができるかと思います。

緩めなキーポリシー.json

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "Allow Amazon ECS to use the key",
      "Effect": "Allow",
      "Principal": {
        "AWS": "インフラストラクチャロールの IAM ロール ARN"
      },
      "Action": [
        "kms:GenerateDataKey*",
        "kms:ReEncryptTo",
        "kms:ReEncryptFrom",
        "kms:DescribeKey",
        "kms:CreateGrant"
      ],
      "Resource": "*",
      "Condition": {
        "StringEquals": {
          "kms:CallerAccount": "アカウントID",
          "kms:ViaService": "ec2.リーション名.amazonaws.com"
        }
      }
    }
  ]
}

サービスの起動が完了するとタスクのボリューム欄に EBS が現れていました。インフラストラクチャロールは、別名「ボリュームロール」と表されるようです。

ECS Exec

それでは、 ESC Exec してコンテナの中からボリュームを覗いてみます。まずは、 ECS サービスの enableExecuteCommand を有効にします。

aws ecs update-service \
    --cluster ecs-ebs-support-cluster \
    --service ecs-ebs-support-service \
    --enable-execute-command

実行結果

[cloudshell-user@ip-10-130-52-192 ~]$ aws ecs update-service \
>     --cluster ecs-ebs-support-cluster \
>     --service ecs-ebs-support-service \
>     --enable-execute-command
{
    "service": {
        "serviceArn": "arn:aws:ecs:ap-northeast-1:XXXXXXXXXXXX:service/ecs-ebs-support-cluster/ecs-ebs-support-service",
        "serviceName": "ecs-ebs-support-service",
        "clusterArn": "arn:aws:ecs:ap-northeast-1:XXXXXXXXXXXX:cluster/ecs-ebs-support-cluster",
        "loadBalancers": [],
        "serviceRegistries": [],
        "status": "ACTIVE",
        "desiredCount": 1,
        "runningCount": 1,
        "pendingCount": 0,
        "capacityProviderStrategy": [
            {
                "capacityProvider": "FARGATE",
                "weight": 1,
                "base": 0
            }
        ],
        "platformVersion": "LATEST",
        "platformFamily": "Linux",
        "taskDefinition": "arn:aws:ecs:ap-northeast-1:XXXXXXXXXXXX:task-definition/ecs-ebs-support-taskdef:1",
        "deploymentConfiguration": {
            "deploymentCircuitBreaker": {
                "enable": true,
                "rollback": true
            },
            "maximumPercent": 200,
            "minimumHealthyPercent": 100
        },
        "deployments": [
            {
                "id": "ecs-svc/9782616216133603217",
                "status": "PRIMARY",
                "taskDefinition": "arn:aws:ecs:ap-northeast-1:XXXXXXXXXXXX:task-definition/ecs-ebs-support-taskdef:1",
                "desiredCount": 1,
                "pendingCount": 0,
                "runningCount": 1,
                "failedTasks": 0,
                "createdAt": "2024-01-28T12:14:48.907000+00:00",
                "updatedAt": "2024-01-28T12:19:25.014000+00:00",
                "capacityProviderStrategy": [
                    {
                        "capacityProvider": "FARGATE",
                        "weight": 1,
                        "base": 0
                    }
                ],
                "platformVersion": "1.4.0",
                "platformFamily": "Linux",
                "networkConfiguration": {
                    "awsvpcConfiguration": {
                        "subnets": [
                            "subnet-05a65d661b1a74795",
                            "subnet-0deef2f54bbb1a19b",
                            "subnet-0f5238f9112b400e1"
                        ],
                                {
                                    "resourceType": "volume",
                                    "tags": []
                                }
                            ],
                            "roleArn": "arn:aws:iam::XXXXXXXXXXXX:role/ecs-ebs-support-infra-role",
                            "filesystemType": "ext3"
                        }
                    }
                ]
            }
        ],
        "roleArn": "arn:aws:iam::XXXXXXXXXXXX:role/aws-service-role/ecs.amazonaws.com/AWSServiceRoleForECS",
        "events": [
            {
                "id": "f06ef6ec-81f6-46d4-9e3d-12ec098ca3a9",
                "createdAt": "2024-01-28T12:19:25.023000+00:00",
                "message": "(service ecs-ebs-support-service) has reached a steady state."
            },
            {
                "id": "022dd505-fa90-4f9f-a003-5d002fc9ce69",
                "createdAt": "2024-01-28T12:19:25.022000+00:00",
                "message": "(service ecs-ebs-support-service) (deployment ecs-svc/9782616216133603217) deployment completed."
            },
            {
                "id": "1405dde3-2fda-489c-a1c0-01f75c633c03",
                "createdAt": "2024-01-28T12:15:00.857000+00:00",
                "message": "(service ecs-ebs-support-service) has started 1 tasks: (task aa48a73955e8484aa2c24a5e96fcba85)."
            }
        ],
        "createdAt": "2024-01-28T12:10:23.926000+00:00",
        "placementConstraints": [],
        "placementStrategy": [],
        "networkConfiguration": {
            "awsvpcConfiguration": {
                "subnets": [
                    "subnet-05a65d661b1a74795",
                    "subnet-0deef2f54bbb1a19b",
                    "subnet-0f5238f9112b400e1"
                ],
                "securityGroups": [
                    "sg-0e919f1eaaab40ae9"
                ],
                "assignPublicIp": "ENABLED"
            }
        },
        "schedulingStrategy": "REPLICA",
        "deploymentController": {
            "type": "ECS"
        },
        "createdBy": "arn:aws:iam::XXXXXXXXXXXX:role/takakuni",
        "enableECSManagedTags": true,
        "propagateTags": "NONE",
        "enableExecuteCommand": true
    }
}
[cloudshell-user@ip-10-130-52-192 ~]$

enableExecuteCommand も有効になったところで、タスクの置き換えを行います。

aws ecs update-service \
    --cluster ecs-ebs-support-cluster \
    --service ecs-ebs-support-service \
    --force-new-deployment

実行結果

[cloudshell-user@ip-10-130-52-192 ~]$ aws ecs update-service \
>     --cluster ecs-ebs-support-cluster \
>     --service ecs-ebs-support-service \
>     --force-new-deployment
{
    "service": {
        "serviceArn": "arn:aws:ecs:ap-northeast-1:XXXXXXXXXXXX:service/ecs-ebs-support-cluster/ecs-ebs-support-service",
        "serviceName": "ecs-ebs-support-service",
        "clusterArn": "arn:aws:ecs:ap-northeast-1:XXXXXXXXXXXX:cluster/ecs-ebs-support-cluster",
        "loadBalancers": [],
        "serviceRegistries": [],
        "status": "ACTIVE",
        "desiredCount": 1,
        "runningCount": 1,
        "pendingCount": 0,
        "capacityProviderStrategy": [
            {
                "capacityProvider": "FARGATE",
                "weight": 1,
                "base": 0
            }
        ],
        "platformVersion": "LATEST",
        "platformFamily": "Linux",
        "taskDefinition": "arn:aws:ecs:ap-northeast-1:XXXXXXXXXXXX:task-definition/ecs-ebs-support-taskdef:1",
        "deploymentConfiguration": {
            "deploymentCircuitBreaker": {
                "enable": true,
                "rollback": true
            },
            "maximumPercent": 200,
            "minimumHealthyPercent": 100
        },
        "deployments": [
            {
                "id": "ecs-svc/1931092835025257968",
                "status": "PRIMARY",
                "taskDefinition": "arn:aws:ecs:ap-northeast-1:XXXXXXXXXXXX:task-definition/ecs-ebs-support-taskdef:1",
                "desiredCount": 0,
                "pendingCount": 0,
                "runningCount": 0,
                "failedTasks": 0,
                "createdAt": "2024-01-28T12:34:47.215000+00:00",
                "updatedAt": "2024-01-28T12:34:47.215000+00:00",
                "capacityProviderStrategy": [
                    {
                        "capacityProvider": "FARGATE",
                        "weight": 1,
                        "base": 0
                    }
                ],
                "platformVersion": "1.4.0",
                "platformFamily": "Linux",
                "networkConfiguration": {
                    "awsvpcConfiguration": {
                        "subnets": [
                            "subnet-05a65d661b1a74795",
                            "subnet-0deef2f54bbb1a19b",
                            "subnet-0f5238f9112b400e1"
                        ],
                        "securityGroups": [
                            "sg-0e919f1eaaab40ae9"
                        ],
                        "assignPublicIp": "ENABLED"
                    }
                },
                "rolloutState": "IN_PROGRESS",
                "rolloutStateReason": "ECS deployment ecs-svc/1931092835025257968 in progress.",
                "volumeConfigurations": [
                    {
                        "name": "nginx-volume",
                        "managedEBSVolume": {
                            "encrypted": true,
                            "kmsKeyId": "arn:aws:kms:ap-northeast-1:XXXXXXXXXXXX:key/d1e340b1-663e-40b8-8790-13651b0b986b",
                            "volumeType": "gp3",
                            "sizeInGiB": 300,
                            "iops": 3000,
                            "throughput": 125,
                            "tagSpecifications": [
                                {
                                    "resourceType": "volume",
                                    "tags": []
                                }
                            ],
                            "roleArn": "arn:aws:iam::XXXXXXXXXXXX:role/ecs-ebs-support-infra-role",
                            "filesystemType": "ext3"
                        }
                    }
                ]
            },
            {
                "id": "ecs-svc/9782616216133603217",
                "status": "ACTIVE",
                "taskDefinition": "arn:aws:ecs:ap-northeast-1:XXXXXXXXXXXX:task-definition/ecs-ebs-support-taskdef:1",
                "desiredCount": 1,
                "pendingCount": 0,
                "runningCount": 1,
                "failedTasks": 0,
                "createdAt": "2024-01-28T12:14:48.907000+00:00",
                "updatedAt": "2024-01-28T12:25:54.795000+00:00",
                "capacityProviderStrategy": [
                    {
                        "capacityProvider": "FARGATE",
                        "weight": 1,
                        "base": 0
                    }
                ],
                "platformVersion": "1.4.0",
                "platformFamily": "Linux",
                "networkConfiguration": {
                    "awsvpcConfiguration": {
                        "subnets": [
                            "subnet-05a65d661b1a74795",
                            "subnet-0deef2f54bbb1a19b",
                            "subnet-0f5238f9112b400e1"
                        ],
                        "securityGroups": [
                            "sg-0e919f1eaaab40ae9"
                        ],
                        "assignPublicIp": "ENABLED"
                    }
                },
                "rolloutState": "COMPLETED",
                "rolloutStateReason": "ECS deployment ecs-svc/9782616216133603217 completed.",
                "volumeConfigurations": [
                    {
                        "name": "nginx-volume",
                        "managedEBSVolume": {
                            "encrypted": true,
                            "kmsKeyId": "arn:aws:kms:ap-northeast-1:XXXXXXXXXXXX:key/d1e340b1-663e-40b8-8790-13651b0b986b",
                            "volumeType": "gp3",
                            "sizeInGiB": 300,
                            "iops": 3000,
                            "throughput": 125,
                            "tagSpecifications": [
                                {
                                    "resourceType": "volume",
                                    "tags": []
                                }
                            ],
                            "roleArn": "arn:aws:iam::XXXXXXXXXXXX:role/ecs-ebs-support-infra-role",
                            "filesystemType": "ext3"
                        }
                    }
                ]
            }
        ],
        "roleArn": "arn:aws:iam::XXXXXXXXXXXX:role/aws-service-role/ecs.amazonaws.com/AWSServiceRoleForECS",
        "events": [
            {
                "id": "f06ef6ec-81f6-46d4-9e3d-12ec098ca3a9",
                "createdAt": "2024-01-28T12:19:25.023000+00:00",
                "message": "(service ecs-ebs-support-service) has reached a steady state."
            },
            {
                "id": "022dd505-fa90-4f9f-a003-5d002fc9ce69",
                "createdAt": "2024-01-28T12:19:25.022000+00:00",
                "message": "(service ecs-ebs-support-service) (deployment ecs-svc/9782616216133603217) deployment completed."
            },
            {
                "id": "236b071f-4541-4eba-9ad3-9714ba8b0bbf",
                "createdAt": "2024-01-28T12:17:25.121000+00:00",
                "message": "(service ecs-ebs-support-service) has stopped 1 running tasks: (task b00c73d53c1548f29bb5533c6ebaafdc)."
            },
            {
                "id": "1405dde3-2fda-489c-a1c0-01f75c633c03",
                "createdAt": "2024-01-28T12:15:00.857000+00:00",
                "message": "(service ecs-ebs-support-service) has started 1 tasks: (task aa48a73955e8484aa2c24a5e96fcba85)."
            }
        ],
        "createdAt": "2024-01-28T12:10:23.926000+00:00",
        "placementConstraints": [],
        "placementStrategy": [],
        "networkConfiguration": {
            "awsvpcConfiguration": {
                "subnets": [
                    "subnet-05a65d661b1a74795",
                    "subnet-0deef2f54bbb1a19b",
                    "subnet-0f5238f9112b400e1"
                ],
                "securityGroups": [
                    "sg-0e919f1eaaab40ae9"
                ],
                "assignPublicIp": "ENABLED"
            }
        },
        "schedulingStrategy": "REPLICA",
        "deploymentController": {
            "type": "ECS"
        },
        "createdBy": "arn:aws:iam::XXXXXXXXXXXX:role/takakuni",
        "enableECSManagedTags": true,
        "propagateTags": "NONE",
        "enableExecuteCommand": true
    }
}
[cloudshell-user@ip-10-130-52-192 ~]$

タスクの置き換えが完了したら、 ECS Exec でコンテナにコマンドを実行してみます。

aws ecs execute-command \
    --cluster ecs-ebs-support-cluster \
    --task 6d2427ccfe384b3c9f17f677c7ff24dc \
    --container nginx \
    --interactive \
    --command "df -h"

ボリュームを確認すると /ebs で 296G 利用可能なストレージ領域が確認できます。

[cloudshell-user@ip-10-130-52-192 ~]$ aws ecs execute-command \
>     --cluster ecs-ebs-support-cluster \
>     --task 6d2427ccfe384b3c9f17f677c7ff24dc \
>     --container nginx \
>     --interactive \
>     --command "df -h"

The Session Manager plugin was installed successfully. Use the AWS CLI to start a session.


Starting session with SessionId: ecs-execute-command-0bb2a9b1a3faa2805
Filesystem      Size  Used Avail Use% Mounted on
overlay          30G  9.6G   19G  35% /
tmpfs            64M     0   64M   0% /dev
shm             963M     0  963M   0% /dev/shm
tmpfs           963M     0  963M   0% /sys/fs/cgroup
/dev/nvme2n1    296G  156K  296G   1% /ebs
/dev/nvme1n1     30G  9.6G   19G  35% /etc/hosts
/dev/nvme0n1p1  4.9G  2.0G  2.9G  42% /managed-agents/execute-command
tmpfs           963M     0  963M   0% /proc/acpi
tmpfs           963M     0  963M   0% /sys/firmware


Exiting session with sessionId: ecs-execute-command-0bb2a9b1a3faa2805.

[cloudshell-user@ip-10-130-52-192 ~]$

パフォーマンス

AWS Fargate 環境下で EBS アタッチをする場合、タスクに割り当てる vCPU によって、パフォーマンスリミットがかかるようです。

また、サイズが 0.25, 0.5, 1 vCPU タスクの場合は、 汎用 SSD (gp2, gp3) または HDD (st1, sc1) ボリュームを設定することが推奨されていました。

The baseline Amazon EBS volume IOPS and throughput available for a Fargate on-demand task depends on the total CPU units you request for the task. If you request 0.25, 0.5, or 1 virtual CPU unit (vCPU) for your Fargate task, we recommend that you configure a General Purpose SSD volume (gp2 or gp3) or a Hard Disk Drive (HDD) volume (st1 or sc1).

1 vCPU より大きい CPU を割り当てるタスクのパフォーマンスリミットは以下をご覧ください。

Amazon EBS volume performance limits for Fargate on-demand tasks

まとめ

以上、「Amazon ECS が一時領域として Amazon EBS のアタッチをサポートしました」でした。

今回は 一時領域 でのサポートですが、今後永続ボリュームとしてのサポートも期待したいですね。このブログがどなたかの参考になれば幸いです。

AWS 事業本部コンサルティング部のたかくに(@takakuni_)でした!


  1. スタンドアロンタスクの場合はボリュームを残すことができます。(デフォルトはサービスと同じで削除されます) 
  2. on EC2 の環境でも EBS をサポートしています。サクッと試したかったので今回は Fargate のみ選択しています。