AWS Fargateタスクは各AZにどのように分散されるのか?
はじめに
皆さんはAWS Fargateがお好きでしょうか?私は好きです。
突然ですが、以下AWS公式ドキュメントにFargateタスクは利用可能なAZに可能な限り分散してくれるとの記載があります。
AWS公式ドキュメント: How Amazon ECS places tasks on container instances Fargate launch type
Task placement strategies and constraints aren't supported for tasks using the Fargate launch type. Fargate will try its best to spread tasks across accessible Availability Zones. If the capacity provider includes both Fargate and Fargate Spot, the spread behavior is independent for each capacity provider.
利用可能なAZに可能な限り分散してくれるとはどのような意味なのでしょうか?
実際に東京リージョン, バージニア北部リージョンで300タスクを起動させ、どのように分散されるのかを試してみました。
TL;DR
東京リージョンにおいてはAZ毎に100タスクずつ綺麗に分散されました。しかし、バージニア北部リージョン(通称:バー北)においては綺麗に分散されませんでした。バー北においてはFargateのvCPU Quotaの関係で、0.25vCPU, 0.5GB MEMで300タスクを起動しました。
実行条件によっては均等に分散されない可能性もあるので、それぞれの環境で実際に試してみることを強くお勧めします(多くのリソースを割り当てたり、FARGATE_SPOTを利用したりした場合、均等に分散しないかもしれません)
以下コードを利用すればお好みのリージョンで検証することが可能です。
検証に利用したコード
Terraform
variable "desired_count" {
type = number
default = 3
}
variable "region" {
type = string
default = "ap-northeast-1"
}
provider "aws" {
region = var.region
default_tags {
tags = {
Terraform = "true"
}
}
}
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "5.67"
}
}
required_version = ">= 1.0.0"
}
data "aws_availability_zones" "available" {
state = "available"
}
resource "aws_vpc" "main" {
cidr_block = "10.0.0.0/16"
enable_dns_hostnames = true
enable_dns_support = true
tags = {
Name = "fargate-vpc"
}
}
resource "aws_subnet" "public" {
count = length(data.aws_availability_zones.available.names)
vpc_id = aws_vpc.main.id
cidr_block = "10.0.${count.index * 8}.0/21"
availability_zone = data.aws_availability_zones.available.names[count.index]
map_public_ip_on_launch = true
tags = {
Name = "Public Subnet AZ ${count.index + 1}"
}
}
resource "aws_internet_gateway" "main" {
vpc_id = aws_vpc.main.id
tags = {
Name = "fargate-igw"
}
}
resource "aws_route_table" "public" {
vpc_id = aws_vpc.main.id
route {
cidr_block = "0.0.0.0/0"
gateway_id = aws_internet_gateway.main.id
}
tags = {
Name = "Public Route Table"
}
}
resource "aws_route_table_association" "public" {
count = length(data.aws_availability_zones.available.names)
subnet_id = aws_subnet.public[count.index].id
route_table_id = aws_route_table.public.id
}
resource "aws_security_group" "ecs_tasks" {
name = "ecs-tasks-sg"
description = "Allow inbound/outbound traffic for ECS tasks"
vpc_id = aws_vpc.main.id
ingress {
from_port = 80
to_port = 80
protocol = "tcp"
cidr_blocks = ["10.0.0.0/16"]
}
# Allow Pull container from ECR.
egress {
from_port = 443
to_port = 443
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
}
resource "aws_ecs_cluster" "fargate_cluster" {
name = "fargate-cluster"
}
resource "aws_ecs_task_definition" "sample_task" {
family = "sample-task"
network_mode = "awsvpc"
requires_compatibilities = ["FARGATE"]
# cpu = "256"
# memory = "512"
cpu = "4096"
memory = "16384"
runtime_platform {
cpu_architecture = "ARM64"
}
container_definitions = jsonencode([
{
name = "sample-nginx-container"
image = "public.ecr.aws/nginx/nginx:latest"
portMappings = [
{
containerPort = 80
hostPort = 80
}
]
}
])
}
resource "aws_ecs_service" "sample_service" {
name = "sample-service"
cluster = aws_ecs_cluster.fargate_cluster.id
task_definition = aws_ecs_task_definition.sample_task.arn
desired_count = var.desired_count
launch_type = "FARGATE"
network_configuration {
subnets = aws_subnet.public[*].id
assign_public_ip = true
security_groups = [aws_security_group.ecs_tasks.id]
}
}
実行シェル
以下シェルをcheck-evenly-distributed-among-azs.sh
という名前で保存したのち、bash check-evenly-distributed-among-azs.sh ap-northeast-1 300
のように実行することで本記事と同一条件でテストが可能です。
※ いい感じのAWS権限, jq/aws cli/Terraformインストール, 同一ディレクトリにTerraform(.tf)ファイルの配置が必要
#!/bin/bash
# Check Args.
if [ $# -ne 2 ]; then
echo "Error : 2つの引数が必要です。" >&2
echo "Usage : $0 <AWS_REGION> <ASSUMPTION_TASK_COUNT>" >&2
echo "<AWS_REGION>はAWSのリージョン名を指定。"
echo "<ASSUMPTION_TASK_COUNT>は起動するタスクの総数を指定。"
echo "使用例: $0 ap-northeast-1 30"
exit 1
fi
export AWS_DEFAULT_REGION=$1
export ASSUMPTION_TASK_COUNT=$2
export TF_VAR_region=$1
export TF_VAR_desired_count=$2
ATTEMPT_COUNT=5
OUTPUT_FILE_NAME="$AWS_DEFAULT_REGION-result-$ASSUMPTION_TASK_COUNT.txt"
for NUM in $(seq 1 $ATTEMPT_COUNT); do
echo "-------------------------" | tee -a $OUTPUT_FILE_NAME
echo "Attempt: $NUM" | tee -a $OUTPUT_FILE_NAME
## Terraform Apply
terraform init && terraform apply -auto-approve
## Waiting Start ECS Tasks.
sleep 30
while true; do
TASK_COUNT=$(aws ecs list-tasks --cluster fargate-cluster --service-name sample-service | jq '.taskArns | length')
if [ "$TASK_COUNT" -eq "$ASSUMPTION_TASK_COUNT" ]; then
echo "Task count reached $ASSUMPTION_TASK_COUNT. Displaying distribution:"
aws ecs list-tasks --cluster fargate-cluster --service-name sample-service |
jq -r '.taskArns[]' |
xargs -I {} aws ecs describe-tasks --cluster fargate-cluster --tasks {} |
jq -r '.tasks[].availabilityZone' |
sort | uniq -c | tee -a $OUTPUT_FILE_NAME
break
else
echo "Task count: $TASK_COUNT. Waiting 10 seconds before checking again..."
sleep 10
fi
done
## Terraform destroy
terraform destroy -auto-approve
echo "Attempt $NUM completed."
echo "-------------------------" | tee -a $OUTPUT_FILE_NAME
## Wait
if [ "$NUM" -ne "$ATTEMPT_COUNT" ]; then
sleep 30
fi
done
実行条件(東京リージョン)
- 実行タスク数: 300
- 利用AZ:
- ap-northeast-1a(apne1-az4)
- ap-northeast-1c(apne1-az1)
- ap-northeast-1d(apne1-az2)
- CPUアーキテクチャ: ARM64
- スペック: 4vCPU, 16GB MEM
結果(東京リージョン)
Attempt | ap-northeast-1a | ap-northeast-1c | ap-northeast-1d |
---|---|---|---|
1 | 100 | 100 | 100 |
2 | 100 | 100 | 100 |
3 | 100 | 100 | 100 |
4 | 100 | 100 | 100 |
5 | 100 | 100 | 100 |
この結果から、東京リージョンにおいてはタスクが均等に分散されたことがわかりました。
(0.25vCPU, 0.5GB MEMの条件でも実施しましたが、綺麗に100タスクずつ分散しました)
実行条件(バージニア北部)
- 実行タスク数: 300
- 利用AZ:
- us-east-1a(use1-az2)
- us-east-1b(use1-az4)
- us-east-1c(use1-az6)
- us-east-1d(use1-az1)
- us-east-1e(use1-az3)
- us-east-1f(use1-az5)
- CPUアーキテクチャ: ARM64
- スペック: 0.25vCPU, 0.5GB MEM
結果(バージニア北部)
Attempt | us-east-1a | us-east-1b | us-east-1c | us-east-1d | us-east-1f |
---|---|---|---|---|---|
1 | 62 | 78 | 66 | 46 | 48 |
2 | 62 | 67 | 57 | 56 | 58 |
3 | 61 | 58 | 57 | 61 | 63 |
4 | 64 | 62 | 58 | 60 | 56 |
5 | 68 | 65 | 64 | 53 | 50 |
この結果から、バージニア北部においてはタスクが均等に分散されなかったことがわかりました。
ちなみに、バージニア北部のus-east-1e(use1-az3)においてはARMがサポートされていないため、Fargateのサービスで該当AZを指定してもタスクは起動しません。
AWS公式ドキュメント: Amazon ECS task definitions for 64-bit ARM workloads
For the Fargate launch type, the following AWS Regions do not support 64-bit ARM workloads:
US East (N. Virginia), the use1-az3 Availability Zone
終わりに
今回は「AWS Fargateタスクは各AZにどのように分散されるのか?」と題して、東京リージョン, バージニア北部リージョンでFargateタスクがAZにどのように分散されるのかについて、実際に検証してみました。
概ね均等レベルにタスクを分散すれば良い場合、特に作り込まずとも良いことがわかりました。
この記事を読んでくださった方が、AWSに興味を少しでも持っていただけると嬉しいです。
ここまで読んでくださってありがとうございました。
Discussion