[アップデート] AWS Fargate の ECS タスク内で遅延読み込みするコンテナを指定可能になりました

AWS Fargate の ECS タスク内で遅延読み込みするコンテナを指定可能になりました。遅延読み込みする場合、以前は全てのコンテナに対して遅延読み込みを設定にしなければならなかったのが、今回のアップデートで遅延読み込みするコンテナを指定できるようになりました。
2024.02.05

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

2023年11月のアップデートです。書きかけで年を越してしまいました。

Fargate 上の ECS タスクで遅延読み込みするコンテナを指定できるようになりました!

SOCI について

Seekable OCI (SOCI) は、コンテナイメージの遅延読み込みするための技術です。

コンテナイメージを完全にダウンロードしてからコンテナを起動するのではなく、コンテナ起動に必要最低限なインデックスからコンテナを起動し、バックグラウンドで残りのファイルをコンテナ起動後に取得していく技術です。

インデックスを生成する SOCI Snapshotter は OSS で公開されており、 GitHub 上で公開されています。もし興味あればご覧下さい。

何が嬉しいか

今まで、 SOCI による遅延読み込みを行うには、タスク定義内のすべてのコンテナイメージで SOCI インデックスを生成して Amazon ECR にプッシュする必要がありました。そのため、以下のようなコンテナイメージも SOCI インデックスをイメージプッシュ時に含める必要がありました。

  • サイドカーコンテナを含むイメージサイズが 250 MiB より小さいコンテナイメージ
    • SOCI の効果が発揮しづらい
    • 各レイヤーのサイズが 10 MB 以下である可能性がある 1

遅延読み込みしたくないコンテナも、すべてインデックスを作成する必要があったため、導入障壁が少なからずあったのではないでしょうか。

今回のアップデート

今回、 AWS Fargate 側でリポジトリに SOCI インデックスが含まれていないコンテナイメージは、遅延読み込みをスキップする挙動に変更されました。そのため、リポジトリの SOCI インデックスが含まれているかどうかで、遅延読み込みしたいコンテナを指定可能になりました。

If you want to prevent a container image from being lazy loaded, delete the SOCI index from the container registry. If a container image in the task doesn't meet one of the considerations, that container image is downloaded by the default method.

Lazy loading container images using Seekable OCI (SOCI)

今回のアップデートで、遅延読み込みのハードルがかなり下がったと思います。

やってみた

遅延読み込みを行うアプリコンテナと、読み込まないサイドカーコンテナを起動してみたいと思います。

AWS SOCI Index Builder

SOCI のインデックスを自動で作成してくれる AWS SOCI Index Builder がソリューションとして公開されているので、そちらを使います。

マネジメントコンソールログイン後、コンソールリンク内の Deploy SOCI Index Builder を踏み、 CloudFormation スタックの作成画面で作成していきます。リージョンは東京リージョンを選びました。

次に スタックの詳細を指定します。

Firelens コンテナを意図的に外すため、 SOCI repository image tag filtersnginx-repo:* で設定します。残りはデフォルト値でスタックを作成します。

アプリケーションの作成

今回は AWS CDK を使ってアプリケーションをデプロイしていきます。

コードは以下になります。

git clone して、アプリケーションをデプロイしていきます。確認画面で y を入力し、スタックを作成します。

git clone https://github.com/takakuni-classmethod/blog-ecs-tasks-selectively-leverage-soci.git
cd blog-ecs-tasks-selectively-leverage-soci
npm install .
npx cdk deploy

動作確認

ECR の確認

まず、 AWS SOCI Index Builder で ECR リポジトリに SOCI インデックスが作成されていることを確認します。 nginx-repo:* で指定したため、 Nginx は SOCI インデックスが作成されている想定です。

nginx-repo を確認すると、確かに Soci Index が作成されていますね。

対して、 firelens-repo ですが、想定通り Soci Index が作成されていないことがわかります。

サービスの確認

ECR で SOCI インデックスの作成状況が確認できたため、 ECS サービス側も確認してみます。 ECS タスクも 2 つのコンテナを利用して起動していることがわかります。

遅延読み込みの確認

ECS サービス側で ECS タスクが 2 つのコンテナを利用して起動したことがわかりました。ただ、これらのコンテナが遅延読み込みしているかどうかはマネジメントコンソールからでは確認できません。

そこで、タスクのメタデータエンドポイントを使用して、各コンテナが遅延読み込みをしたかどうかを確認します。

以下のコマンドを利用して、 Nginx コンテナに乗り込みエンドポイントを実行します。実行結果を見やすくするため、 jq をインストールします。

# CloudShell で実行
aws ecs execute-command \
    --cluster soci-update-cluster \
    --task c19b57c1a9ee4a989e1588bd8bd17ca6 \
    --container nginxContainer \
    --interactive \
    --command "/bin/bash"

# コンテナに bash ログイン後実行
apt update -y
apt install -y jq
curl -s $ECS_CONTAINER_METADATA_URI_V4 | jq .

Snapshottersoci になっているので、遅延読み込みされていることがわかります。

実行結果

[cloudshell-user@ip-10-134-30-53 blog-ecs-tasks-selectively-leverage-soci]$ aws ecs execute-command \
>     --cluster soci-update-cluster \
>     --task c19b57c1a9ee4a989e1588bd8bd17ca6 \
>     --container nginxContainer \
>     --interactive \
>     --command "/bin/bash"

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


Starting session with SessionId: ecs-execute-command-0c2cda4c71efa6803
root@ip-10-0-3-20:/# apt update -y
Get:1 http://deb.debian.org/debian bookworm InRelease [151 kB]
Get:2 http://deb.debian.org/debian bookworm-updates InRelease [52.1 kB]
Get:3 http://deb.debian.org/debian-security bookworm-security InRelease [48.0 kB]
Get:4 http://deb.debian.org/debian bookworm/main arm64 Packages [8685 kB]
Get:5 http://deb.debian.org/debian bookworm-updates/main arm64 Packages [12.5 kB]
Get:6 http://deb.debian.org/debian-security bookworm-security/main arm64 Packages [134 kB]
Fetched 9083 kB in 5s (1747 kB/s)                         
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
4 packages can be upgraded. Run 'apt list --upgradable' to see them.
root@ip-10-0-3-20:/# apt install -y jq
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
The following additional packages will be installed:
  libjq1 libonig5
The following NEW packages will be installed:
  jq libjq1 libonig5
0 upgraded, 3 newly installed, 0 to remove and 4 not upgraded.
Need to get 364 kB of archives.
After this operation, 1132 kB of additional disk space will be used.
Get:1 http://deb.debian.org/debian bookworm/main arm64 libonig5 arm64 6.9.8-1 [179 kB]
Get:2 http://deb.debian.org/debian bookworm/main arm64 libjq1 arm64 1.6-2.1 [121 kB]
Get:3 http://deb.debian.org/debian bookworm/main arm64 jq arm64 1.6-2.1 [64.5 kB]
Fetched 364 kB in 0s (3078 kB/s)
debconf: delaying package configuration, since apt-utils is not installed
Selecting previously unselected package libonig5:arm64.
(Reading database ... 7584 files and directories currently installed.)
Preparing to unpack .../libonig5_6.9.8-1_arm64.deb ...
Unpacking libonig5:arm64 (6.9.8-1) ...
Selecting previously unselected package libjq1:arm64.
Preparing to unpack .../libjq1_1.6-2.1_arm64.deb ...
Unpacking libjq1:arm64 (1.6-2.1) ...
Selecting previously unselected package jq.
Preparing to unpack .../archives/jq_1.6-2.1_arm64.deb ...
Unpacking jq (1.6-2.1) ...
Setting up libonig5:arm64 (6.9.8-1) ...
Setting up libjq1:arm64 (1.6-2.1) ...
Setting up jq (1.6-2.1) ...
Processing triggers for libc-bin (2.36-9+deb12u3) ...
root@ip-10-0-3-20:/# curl -s $ECS_CONTAINER_METADATA_URI_V4 | jq .
{
  "DockerId": "c19b57c1a9ee4a989e1588bd8bd17ca6-3725726378",
  "Name": "nginxContainer",
  "DockerName": "nginxContainer",
  "Image": "XXXXXXXXXXXX.dkr.ecr.ap-northeast-1.amazonaws.com/nginx-repo:latest",
  "ImageID": "sha256:57be48bd3977c41b97115be09dc9b78036c9aa05ef50b8561c58ac53e78ed2ba",
  "Labels": {
    "com.amazonaws.ecs.cluster": "arn:aws:ecs:ap-northeast-1:XXXXXXXXXXXX:cluster/soci-update-cluster",
    "com.amazonaws.ecs.container-name": "nginxContainer",
    "com.amazonaws.ecs.task-arn": "arn:aws:ecs:ap-northeast-1:XXXXXXXXXXXX:task/soci-update-cluster/c19b57c1a9ee4a989e1588bd8bd17ca6",
    "com.amazonaws.ecs.task-definition-family": "soci-update-task-definition",
    "com.amazonaws.ecs.task-definition-version": "6"
  },
  "DesiredStatus": "RUNNING",
  "KnownStatus": "RUNNING",
  "Limits": {
    "CPU": 2
  },
  "CreatedAt": "2024-02-05T06:45:47.976912721Z",
  "StartedAt": "2024-02-05T06:45:47.976912721Z",
  "Type": "NORMAL",
  "LogDriver": "awsfirelens",
  "ContainerARN": "arn:aws:ecs:ap-northeast-1:XXXXXXXXXXXX:container/soci-update-cluster/c19b57c1a9ee4a989e1588bd8bd17ca6/16356531-4c82-437e-83ed-2f2ae2b833b9",
  "Networks": [
    {
      "NetworkMode": "awsvpc",
      "IPv4Addresses": [
        "10.0.3.20"
      ],
      "AttachmentIndex": 0,
      "MACAddress": "0a:af:e3:2f:c3:e7",
      "IPv4SubnetCIDRBlock": "10.0.3.0/24",
      "DomainNameServers": [
        "10.0.0.2"
      ],
      "DomainNameSearchList": [
        "ap-northeast-1.compute.internal"
      ],
      "PrivateDNSName": "ip-10-0-3-20.ap-northeast-1.compute.internal",
      "SubnetGatewayIpv4Address": "10.0.3.1/24"
    }
  ],
  "Snapshotter": "soci"
}
root@ip-10-0-3-20:/#

続いて、 Firelens コンテナに乗り込みます。

# CloudShell で実行
aws ecs execute-command \
    --cluster soci-update-cluster \
    --task c19b57c1a9ee4a989e1588bd8bd17ca6 \
    --container firelensContainer \
    --interactive \
    --command "/bin/bash"

# コンテナに bash ログイン後実行
yum install -y jq
curl -s $ECS_CONTAINER_METADATA_URI_V4 | jq .

実行結果から Snapshotteroverlayfs になっているので、遅延読み込みされていないことがわかります。よって、タスクのコンテナ毎によって、遅延読み込みするかどうかコントロールできていますね。

実行結果

[cloudshell-user@ip-10-134-30-53 blog-ecs-tasks-selectively-leverage-soci]$ aws ecs execute-command \
>     --cluster soci-update-cluster \
>     --task c19b57c1a9ee4a989e1588bd8bd17ca6 \
>     --container firelensContainer \
>     --interactive \
>     --command "/bin/bash"

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


Starting session with SessionId: ecs-execute-command-01bc5c9b6e4477037
bash-4.2# 
bash-4.2# yum install -y jq
Loaded plugins: ovl, priorities
amzn2-core                                                                                                                                                                                                                         | 3.6 kB  00:00:00     
(1/3): amzn2-core/2/aarch64/group_gz                                                                                                                                                                                               | 2.7 kB  00:00:00     
(2/3): amzn2-core/2/aarch64/updateinfo                                                                                                                                                                                             | 787 kB  00:00:00     
(3/3): amzn2-core/2/aarch64/primary_db                                                                                                                                                                                             |  56 MB  00:00:01     
Resolving Dependencies
--> Running transaction check
---> Package jq.aarch64 0:1.5-1.amzn2.0.2 will be installed
--> Processing Dependency: libonig.so.2()(64bit) for package: jq-1.5-1.amzn2.0.2.aarch64
--> Running transaction check
---> Package oniguruma.aarch64 0:5.9.6-1.amzn2.0.7 will be installed
--> Finished Dependency Resolution

Dependencies Resolved

==========================================================================================================================================================================================================================================================
 Package                                                    Arch                                                     Version                                                            Repository                                                   Size
==========================================================================================================================================================================================================================================================
Installing:
 jq                                                         aarch64                                                  1.5-1.amzn2.0.2                                                    amzn2-core                                                  146 k
Installing for dependencies:
 oniguruma                                                  aarch64                                                  5.9.6-1.amzn2.0.7                                                  amzn2-core                                                  128 k

Transaction Summary
==========================================================================================================================================================================================================================================================
Install  1 Package (+1 Dependent package)

Total download size: 273 k
Installed size: 1.0 M
Downloading packages:
(1/2): oniguruma-5.9.6-1.amzn2.0.7.aarch64.rpm                                                                                                                                                                                     | 128 kB  00:00:00     
(2/2): jq-1.5-1.amzn2.0.2.aarch64.rpm                                                                                                                                                                                              | 146 kB  00:00:00     
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Total                                                                                                                                                                                                                     454 kB/s | 273 kB  00:00:00     
Running transaction check
Running transaction test
Transaction test succeeded
Running transaction
  Installing : oniguruma-5.9.6-1.amzn2.0.7.aarch64                                                                                                                                                                                                    1/2 
  Installing : jq-1.5-1.amzn2.0.2.aarch64                                                                                                                                                                                                             2/2 
  Verifying  : jq-1.5-1.amzn2.0.2.aarch64                                                                                                                                                                                                             1/2 
  Verifying  : oniguruma-5.9.6-1.amzn2.0.7.aarch64                                                                                                                                                                                                    2/2 

Installed:
  jq.aarch64 0:1.5-1.amzn2.0.2                                                                                                                                                                                                                            

Dependency Installed:
  oniguruma.aarch64 0:5.9.6-1.amzn2.0.7                                                                                                                                                                                                                   

Complete!
bash-4.2# curl -s $ECS_CONTAINER_METADATA_URI_V4 | jq .
{
  "DockerId": "c19b57c1a9ee4a989e1588bd8bd17ca6-1930253740",
  "Name": "firelensContainer",
  "DockerName": "firelensContainer",
  "Image": "XXXXXXXXXXXX.dkr.ecr.ap-northeast-1.amazonaws.com/firelens-repo:latest",
  "ImageID": "sha256:422946c452a6f5dd5d175e41676a0b811ca224b4f267792c12bb29faa0df6d86",
  "Labels": {
    "com.amazonaws.ecs.cluster": "arn:aws:ecs:ap-northeast-1:XXXXXXXXXXXX:cluster/soci-update-cluster",
    "com.amazonaws.ecs.container-name": "firelensContainer",
    "com.amazonaws.ecs.task-arn": "arn:aws:ecs:ap-northeast-1:XXXXXXXXXXXX:task/soci-update-cluster/c19b57c1a9ee4a989e1588bd8bd17ca6",
    "com.amazonaws.ecs.task-definition-family": "soci-update-task-definition",
    "com.amazonaws.ecs.task-definition-version": "6"
  },
  "DesiredStatus": "RUNNING",
  "KnownStatus": "RUNNING",
  "Limits": {
    "CPU": 2
  },
  "CreatedAt": "2024-02-05T06:45:47.459429937Z",
  "StartedAt": "2024-02-05T06:45:47.459429937Z",
  "Type": "NORMAL",
  "LogDriver": "awslogs",
  "LogOptions": {
    "awslogs-group": "soci-update-firelens-log-group",
    "awslogs-region": "ap-northeast-1",
    "awslogs-stream": "firelens/firelensContainer/c19b57c1a9ee4a989e1588bd8bd17ca6"
  },
  "ContainerARN": "arn:aws:ecs:ap-northeast-1:XXXXXXXXXXXX:container/soci-update-cluster/c19b57c1a9ee4a989e1588bd8bd17ca6/030d15c3-5f7e-4b80-b116-5aa638bc8477",
  "Networks": [
    {
      "NetworkMode": "awsvpc",
      "IPv4Addresses": [
        "10.0.3.20"
      ],
      "AttachmentIndex": 0,
      "MACAddress": "0a:af:e3:2f:c3:e7",
      "IPv4SubnetCIDRBlock": "10.0.3.0/24",
      "DomainNameServers": [
        "10.0.0.2"
      ],
      "DomainNameSearchList": [
        "ap-northeast-1.compute.internal"
      ],
      "PrivateDNSName": "ip-10-0-3-20.ap-northeast-1.compute.internal",
      "SubnetGatewayIpv4Address": "10.0.3.1/24"
    }
  ],
  "Snapshotter": "overlayfs"
}
bash-4.2#

参考: Snapshotter

まとめ

以上、 「AWS Fargate の ECS タスク内で遅延読み込みするコンテナを指定可能になりました」でした。

Fargate 側で遅延読み込みするかどうかを自動で判断してくれるのは、とてもありがたいですね。 AWS SOCI Index Builder の機能がマネコンでポチッと押せるくらい簡単になれば、導入がさらに加速しそうな予感がしました。

このブログがどなたかの参考になれば幸いです。

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


  1. soci create コマンドおよび、 AWS SOCI Index Builder はデフォルトで 10MB 以下のレイヤーは zToc を作成しません。しきい値の変更にはコマンドにオプション追加やアプリケーションの改修が必要になります。