はじめに
昨年、AWSはSeekable OCI(SOCI)の導入により、アプリケーションの起動と同時にコンテナからデータを非同期にダウンロードするコンテナイメージの遅延読み込みを実現しました。
これにより、コンテナイメージを変更せずにアプリケーションをより速く起動できるようになりました。
今回、SOCIがAWS Fargateにもサポートされました!
SOCIは、ECRに保存されているコンテナイメージと同じECRにインデックスを作成しておくことで、イメージ全体をダウンロードせずに個々のファイルを抽出してコンテナを迅速に起動できます。
Amazon ECR リポジトリからイメージをダウンロードする際には、自動的にSOCI インデックスの有無を検出し、イメージ全体のプルを待たずにコンテナを起動します。
もちろん、ECR リポジトリにSOCI インデックスがないコンテナイメージも引き続き実行できます。
追記:2023/7/27(日本語のAWSブログも公開されました)
SOCI インデックスの概要
SOCI インデックスは、イメージの遅延読み込み(非同期読み込み)を可能にするアーティファクトです。
SOCI インデックスは、下図の右側のSOCI インデックスマニフェストと zTOC (圧縮データのインデックス)で構成されます。
SOCI インデックスマニフェストには、zTOC のリストと、マニフェストが生成されたイメージが含まれています。
引用:https://aws.amazon.com/jp/blogs/aws/aws-fargate-enables-faster-container-startup-using-seekable-oci/
以下のリンクで用語の詳細が解説されております
SOCI インデックスの考慮点
Fargate で SOCI インデックスを使用してコンテナイメージを遅延読み込みする場合は、次の点を考慮してください。
- SOCI インデックスを使用できるのは、Linux プラットフォーム バージョン
1.4.0
で実行されるタスクのみです - X86_64 CPU アーキテクチャで実行されるタスクのみがサポートされます
- イメージサイズが 250 MiB を超えるコンテナイメージで遅延読み込みを試すことをお勧めします。サイズが小さい場合、コンテナ起動の改善時間が低くなります。
- 追加コストなしでSOCIを利用できますが、SOCI インデックスのイメージをECRに保存する場合に料金が発生します。
SOCI インデックスの作成方法
SOCI インデックスの作成方法は2つあります。
- AWS SOCI Index Builder を使用する
- AWS SOCI Index Builder は、 コンテナイメージのSOCI インデックスを作成するためのサーバーレスソリューションです。
- 以下のCloudFormationのスタックが用意されております
- Amazon EventBridgeルールが ECRアクションイベントを識別し、定義されたフィルターに一致するAWS Lambdaを呼び出します。別のAWS Lambda関数が SOCI インデックスを生成し、ECR リポジトリにプッシュします。
- 引用:https://aws-ia.github.io/cfn-ecr-aws-soci-index-builder/
- Amazon EventBridgeルールが ECRアクションイベントを識別し、定義されたフィルターに一致するAWS Lambdaを呼び出します。別のAWS Lambda関数が SOCI インデックスを生成し、ECR リポジトリにプッシュします。
- SOCI インデックスを手動で作成する
- SOCI Snapshoter というプラグインを利用して作成します。
ECRにイメージをプッシュすると、自動でSOCI インデックスが作成されるAWS SOCI Index Builderの使用がおすすめです。
今回は、AWS SOCI Index Builderを利用します。
環境
- PC:M2 MacBook Pro
- 利用するイメージ:Nginx
イメージを作成するディレクトリ構成
/ $ tree
.
├── 1GB.zip
├── Dockerfile
├── index.html
├── task-query-nginx.sh
└── task-query-nginx-soci.sh
1GB.zip
は、1GB程度のファイルです。
Dockerfile
FROM nginx:1.20.0
COPY ./index.html /usr/share/nginx/html
COPY ./1GB.zip /usr/share/nginx/html
EXPOSE 80
index.html
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>SOCI Test1</h1>
</body>
</html>
task-query-nginx.sh
とtask-query-nginx-soci.sh
は、タスクの起動時間を確認するため、「開始時刻(startedAt
) 」と「作成時刻(createdAt
)」を出力するコマンドです。
後で解説しますが、以下の設定です。
- クラスター名
nginx
- タスク定義
nginx-soci
nginx
task-query-nginx-soci.sh
CLUSTER=nginx
TASKDEF=nginx-soci
REGION=ap-northeast-1
TASKS=$(aws ecs list-tasks \
--cluster $CLUSTER \
--family $TASKDEF \
--region $REGION \
--query 'taskArns[*]' \
--output text)
aws ecs describe-tasks \
--tasks $TASKS \
--region $REGION \
--cluster $CLUSTER \
--query "tasks[] | reverse(sort_by(@, &createdAt)) | [].[{startedAt: startedAt, createdAt: createdAt, taskArn: taskArn}]" \
--output table
task-query-nginx.sh
CLUSTER=nginx
TASKDEF=nginx
REGION=ap-northeast-1
TASKS=$(aws ecs list-tasks \
--cluster $CLUSTER \
--family $TASKDEF \
--region $REGION \
--query 'taskArns[*]' \
--output text)
aws ecs describe-tasks \
--tasks $TASKS \
--region $REGION \
--cluster $CLUSTER \
--query "tasks[] | reverse(sort_by(@, &createdAt)) | [].[{startedAt: startedAt, createdAt: createdAt, taskArn: taskArn}]" \
--output table
ECRを作成
SOCI インデックスの有無を比較するため、同じコンテナイメージ(今回は、Nginx)を使用します。
また、SOCI インデックスが存在するECR リポジトリ(nginx-soci1
)とSOCI インデックスを存在しないECR リポジトリ(nginx
)を下記コマンドで作成します。
Macのターミナルを利用しています。
$ aws ecr create-repository --region ap-northeast-1 --repository-name nginx-soci
$ aws ecr create-repository --region ap-northeast-1 --repository-name nginx
AWS SOCI Index Builder をデプロイ
こちらからCloudFormationのスタックを作成します。
パラメータのSOCI repository image tag filters
は、リポジトリ名:タグ名
のため、nginx-soci:latest
にします。
ECRにプッシュしたイメージ全て、SOCI インデックスを作成したい場合、*:*
にします。
他は、デフォルトです。
デプロイ成功したことを確認します。
イメージをECRにプッシュする
ディレクトリ構成は、以下のとおりです。
/ $ tree
.
├── 1GB.zip
├── Dockerfile
├── index.html
├── task-query-nginx.sh
└── task-query-nginx-soci.sh
イメージを作成し、自分のアカウントのECRリポジトリにプッシュします。
//アカウントIDは、自身のアカウントIDに変える
$ aws ecr get-login-password --region ap-northeast-1 | docker login --username AWS --password-stdin アカウントID.dkr.ecr.ap-northeast-1.amazonaws.com
$ docker build -t nginx. --platform linux/x86_64
$ docker tag nginx:latest アカウントID.dkr.ecr.ap-northeast-1.amazonaws.com/nginx:latest
$ docker push アカウントID.dkr.ecr.ap-northeast-1.amazonaws.com/nginx:latest
$ docker build -t nginx-soci . --platform linux/x86_64
$ docker tag nginx-soci:latest アカウントID.dkr.ecr.ap-northeast-1.amazonaws.com/nginx-soci:latest
$ docker push アカウントID.dkr.ecr.ap-northeast-1.amazonaws.com/nginx-soci:latest
nginx-soc
リポジトリには、SOCI インデックスとイメージインデックスという2 つの追加オブジェクトが確認できました。
イメージインデックスによって、Fargate はコンテナイメージに関連付けられた SOCI インデックスを検出できるようになります。
タスク定義を作成
タスク定義をそれぞれjson形式で作成します。(アカウントIDは、自身のアカウントIDに変えること)
nginx-soci
{
"taskDefinitionArn": "arn:aws:ecs:ap-northeast-1:アカウントID:task-definition/nginx-soci:1",
"containerDefinitions": [
{
"name": "nginx-soci",
"image": "アカウントID.dkr.ecr.ap-northeast-1.amazonaws.com/nginx-soci:latest",
"cpu": 0,
"portMappings": [
{
"name": "nginx-soci-80-tcp",
"containerPort": 80,
"hostPort": 80,
"protocol": "tcp",
"appProtocol": "http"
}
],
"essential": true,
"environment": [],
"environmentFiles": [],
"mountPoints": [],
"volumesFrom": [],
"ulimits": [],
"logConfiguration": {
"logDriver": "awslogs",
"options": {
"awslogs-create-group": "true",
"awslogs-group": "/ecs/nginx-soci",
"awslogs-region": "ap-northeast-1",
"awslogs-stream-prefix": "ecs"
}
}
}
],
"family": "nginx-soci",
"executionRoleArn": "arn:aws:iam::アカウントID:role/ecsTaskExecutionRole",
"networkMode": "awsvpc",
"revision": 1,
"volumes": [],
"status": "ACTIVE",
"requiresAttributes": [
{
"name": "com.amazonaws.ecs.capability.logging-driver.awslogs"
},
{
"name": "ecs.capability.execution-role-awslogs"
},
{
"name": "com.amazonaws.ecs.capability.ecr-auth"
},
{
"name": "com.amazonaws.ecs.capability.docker-remote-api.1.19"
},
{
"name": "ecs.capability.execution-role-ecr-pull"
},
{
"name": "com.amazonaws.ecs.capability.docker-remote-api.1.18"
},
{
"name": "ecs.capability.task-eni"
},
{
"name": "com.amazonaws.ecs.capability.docker-remote-api.1.29"
}
],
"placementConstraints": [],
"compatibilities": [
"EC2",
"FARGATE"
],
"requiresCompatibilities": [
"FARGATE"
],
"cpu": "256",
"memory": "512",
"runtimePlatform": {
"cpuArchitecture": "X86_64",
"operatingSystemFamily": "LINUX"
},
"registeredAt": "2023-07-18T06:22:41.983Z",
"registeredBy": "arn:aws:sts::アカウントID:assumed-role/cm-hirai.yuji/cm-hirai.yuji",
"tags": []
}
nginx
]
{
"taskDefinitionArn": "arn:aws:ecs:ap-northeast-1:アカウントID:task-definition/nginx:1",
"containerDefinitions": [
{
"name": "nginx",
"image": "アカウントID.dkr.ecr.ap-northeast-1.amazonaws.com/nginx:latest",
"cpu": 0,
"portMappings": [
{
"name": "nginx-80-tcp",
"containerPort": 80,
"hostPort": 80,
"protocol": "tcp",
"appProtocol": "http"
}
],
"essential": true,
"environment": [],
"environmentFiles": [],
"mountPoints": [],
"volumesFrom": [],
"ulimits": [],
"logConfiguration": {
"logDriver": "awslogs",
"options": {
"awslogs-create-group": "true",
"awslogs-group": "/ecs/nginx",
"awslogs-region": "ap-northeast-1",
"awslogs-stream-prefix": "ecs"
}
}
}
],
"family": "nginx",
"executionRoleArn": "arn:aws:iam::アカウントID:role/ecsTaskExecutionRole",
"networkMode": "awsvpc",
"revision": 1,
"volumes": [],
"status": "ACTIVE",
"requiresAttributes": [
{
"name": "com.amazonaws.ecs.capability.logging-driver.awslogs"
},
{
"name": "ecs.capability.execution-role-awslogs"
},
{
"name": "com.amazonaws.ecs.capability.ecr-auth"
},
{
"name": "com.amazonaws.ecs.capability.docker-remote-api.1.19"
},
{
"name": "ecs.capability.execution-role-ecr-pull"
},
{
"name": "com.amazonaws.ecs.capability.docker-remote-api.1.18"
},
{
"name": "ecs.capability.task-eni"
},
{
"name": "com.amazonaws.ecs.capability.docker-remote-api.1.29"
}
],
"placementConstraints": [],
"compatibilities": [
"EC2",
"FARGATE"
],
"requiresCompatibilities": [
"FARGATE"
],
"cpu": "256",
"memory": "512",
"runtimePlatform": {
"cpuArchitecture": "X86_64",
"operatingSystemFamily": "LINUX"
},
"registeredAt": "2023-07-18T06:25:51.408Z",
"registeredBy": "arn:aws:sts::アカウントID:assumed-role/cm-hirai.yuji/cm-hirai.yuji",
"tags": []
}
タスクを作成
SOCI インデックスが存在するECR リポジトリ(nginx-soci1
)とSOCI インデックスを存在しないECR リポジトリ(nginx
)からイメージをタスクを5つずつ作成し、起動までの時間を比較します。
タスク起動で必要なネットワーク設定は、以下のように設定します。
$ NETWORK_CONFIG="awsvpcConfiguration={subnets=[サブネットID],securityGroups=[セキュリティグループID],assignPublicIp=ENABLED}"
セキュリティグループは、HTTPのインバウンドを許可します。
サブネットは、パブリックサブネットです。
クラスター名は、nginx
です。
$ NETWORK_CONFIG="awsvpcConfiguration={subnets=[subnet-xxxxxxx],securityGroups=[sg-xxxxxxxx],assignPublicIp=ENABLED}"
// アカウントIDは、自身のアカウントIDに変えること
$ aws ecs run-task \
--task-definition arn:aws:ecs:ap-northeast-1:アカウントID:task-definition/nginx:1 \
--region ap-northeast-1 \
--count 5 \
--launch-type FARGATE \
--network-configuration "${NETWORK_CONFIG}" \
--cluster nginx
$ aws ecs run-task \
--task-definition arn:aws:ecs:ap-northeast-1:アカウントID:task-definition/nginx-soci:1 \
--region ap-northeast-1 \
--count 5 \
--launch-type FARGATE \
--network-configuration "${NETWORK_CONFIG}" \
--cluster nginx
起動時間の確認は、task-query-nginx-soci.sh
とtask-query-nginx.sh
のスクリプトを実行します
$ chmod 744 task-query-nginx.sh
$ ./task-query-nginx.sh
-----------------------------------------------------------------------------------------------------------------------------------------------------------------
| DescribeTasks |
+----------------------------------+-----------------------------------+----------------------------------------------------------------------------------------+
| createdAt | startedAt | taskArn |
+----------------------------------+-----------------------------------+----------------------------------------------------------------------------------------+
| 2023-07-18T18:17:24.551000+09:00| 2023-07-18T18:18:01.655000+09:00 | arn:aws:ecs:ap-northeast-1:303526711867:task/nginx/f36a06e0dea04d418d783072c3379dbe |
| 2023-07-18T18:17:24.551000+09:00| 2023-07-18T18:18:02.498000+09:00 | arn:aws:ecs:ap-northeast-1:303526711867:task/nginx/e5935fd181b14c32ba6006c398582cc3 |
| 2023-07-18T18:17:24.551000+09:00| 2023-07-18T18:18:02.288000+09:00 | arn:aws:ecs:ap-northeast-1:303526711867:task/nginx/d2ced06ac4b84d04a09e0092d0462dba |
| 2023-07-18T18:17:24.551000+09:00| 2023-07-18T18:18:02.956000+09:00 | arn:aws:ecs:ap-northeast-1:303526711867:task/nginx/c7dbfcd90aa84a4c96d4fbbefff58692 |
| 2023-07-18T18:17:24.551000+09:00| 2023-07-18T18:18:03.983000+09:00 | arn:aws:ecs:ap-northeast-1:303526711867:task/nginx/af82a62589354c7aa61bfbae11ef8d9f |
+----------------------------------+-----------------------------------+----------------------------------------------------------------------------------------+
$ chmod 744 task-query-nginx-soci.sh
$ ./task-query-nginx-soci.sh
-----------------------------------------------------------------------------------------------------------------------------------------------------------------
| DescribeTasks |
+----------------------------------+-----------------------------------+----------------------------------------------------------------------------------------+
| createdAt | startedAt | taskArn |
+----------------------------------+-----------------------------------+----------------------------------------------------------------------------------------+
| 2023-07-18T18:09:11.683000+09:00| 2023-07-18T18:09:33.585000+09:00 | arn:aws:ecs:ap-northeast-1:303526711867:task/nginx/a67582e8022242599a1fddf70766ef5c |
| 2023-07-18T18:09:11.683000+09:00| 2023-07-18T18:09:31.600000+09:00 | arn:aws:ecs:ap-northeast-1:303526711867:task/nginx/61f71fc8fb424647884f6c97c0188e3b |
| 2023-07-18T18:09:11.683000+09:00| 2023-07-18T18:09:31.714000+09:00 | arn:aws:ecs:ap-northeast-1:303526711867:task/nginx/48eaca68a5ae465998e10106dd542e30 |
| 2023-07-18T18:09:11.683000+09:00| 2023-07-18T18:09:32.283000+09:00 | arn:aws:ecs:ap-northeast-1:303526711867:task/nginx/37b2bf6431754faba283532c1293bfa2 |
| 2023-07-18T18:09:11.683000+09:00| 2023-07-18T18:09:32.749000+09:00 | arn:aws:ecs:ap-northeast-1:303526711867:task/nginx/20b84cd866824a98838476f9c4cafab8
+----------------------------------+-----------------------------------+----------------------------------------------------------------------------------------+
起動時間の改善結果
リポジトリ | SOCI インデックスの有無 | 起動時間 |
---|---|---|
nginx | なし | 38秒 |
nginx-soci | あり | 21秒 |
リポジトリにSOCI インデックスが存在する場合、存在しないリポジトリに比べて、コンテナの起動が45%高速化することがわかりました!
高速化の改善の差
下記の記事では、サンプルアプリケーションを利用し、Fargate で SOCI インデックスを使用すると、SOCI インデックスを使用しない場合に比べて約 50% 高速化しました。
アプリケーションによって差があることが分かりました。
最後に
今回は、SOCI インデックスにより、コンテナイメージを変更せずにアプリケーションをより速く起動できるようになりました。
AutoScalingの起動時間の速度に悩まれていた方は、導入を検討してみてください!