【レポート】コンテナイメージとはなにかを徹底的にDeepDive!SOCIについて学べるワークショップに参加してきました #AWSreInvent #SVS402
お疲れさまです。とーちです。re:Invent2024に参加してます。
この記事では「 SVS402 | Lazy loading container images with Seekable OCI (SOCI) 」のセッションレポートをお届けします。
セッションの概要
タイトル
SVS402 | Lazy loading container images with Seekable OCI (SOCI)
概要
Seekable OCI (SOCI) is an open source AWS technology that enables containers to launch faster by lazily loading the container image. In this workshop, get hands-on with SOCI. Learn how to create SOCI indexes for existing container images and how index generation can be automated in the cloud. Then, practice deploying workloads to Amazon ECS with AWS Fargate, considering how launch times are reduced by lazily loading container images. You must bring your laptop to participate.
※日本語訳
Seekable OCI (SOCI) は、コンテナイメージの遅延読み込みによりコンテナの起動を高速化するオープンソースのAWSテクノロジーです。このワークショップでは、SOCIを実際に体験します。既存のコンテナイメージに対するSOCIインデックスの作成方法と、インデックス生成のクラウドでの自動化方法を学びます。次に、コンテナイメージの遅延読み込みによる起動時間の短縮を考慮しながら、AWS Fargateを使用したAmazon ECSへのワークロードのデプロイを実践します。参加するには、ノートパソコンを持参する必要があります。
スピーカー
Phil Estes, Principal Engineer, AWS
Olly Pomeroy, Specialist Solution Architect, Containers, Amazon Web Services
セッションタイプ
Workshop
概要
SOCI(Seekable OCI)を学ぶためにコンテナイメージの実体とはそもそもどういったものなのかを深堀りし、SOCIと通常のコンテナイメージとの違いやSOCIインデックスの作り方、ECRへのpushの仕方、また通常のコンテナイメージとどのくらいスピードに差があるのかといったところまで体験するセッションでした。
ワークショップの流れ
ワークショップの流れとしては以下のような形です。
- コンテナイメージとはなにかをDeepDiveする
- SOCI CLIでSOCIインデックスを生成する
- SOCIインデックスビルダーを使いSOCIインデックスを生成する
- Amazon ECS(以下ECS)Fargateでコンテナイメージの遅延読み込みをやってみる
- ECSタスクでSOCIインデックスの使用有無によりどの程度の差がでるかを確認する
実際のワークショップで体験したこと
実際のワークショップで行ったことを印象深かったポイントを中心にお届けします。
コンテナイメージとはなにかをDeepDiveする
SOCIはコンテナイメージのレイヤーの仕組みと密接に関わるので、まずはコンテナイメージとはなにかを理解しよう、というところから始まりました。
この項目ではコマンドを使いつつコンテナイメージのかなり細かいところまでを知ることが出来る内容になっており、とても勉強になりました。復習もかねてこの記事で出来る限りお伝えしようと思います。
コンテナイメージの内部構造
コンテナイメージを理解しやすくするために、amazonlinux2023のベースイメージにnginxをインストールしたDockerfileを使って進めていきました。
Dockerfileは以下のような内容です。
FROM public.ecr.aws/amazonlinux/amazonlinux:2023-minimal
RUN dnf install -y nginx
COPY index.html /usr/share/nginx/html/index.html
CMD ["nginx", "-g", "daemon off; error_log /dev/stdout info;"]
このDockerfileをビルドするのですが、ビルドにfinchを使っていました。私は初めて使ったのですが、かなりdockerコマンドライクに使えるんですね。例えばビルドは以下のコマンドでした。
finch build --tag nginx-demo .
まず、finch image inspect
コマンドでコンテナイメージの詳細を見ます。出力結果の中にイメージのレイヤー情報が含まれています。
"RootFS": {
"Type": "layers",
"Layers": [
"sha256:628e1e71d54a534c27a15d57d228fd692284434973429550643615d7547785cb",
"sha256:a99c6640830bff93f9029b80f92f67a528e925072f50884d84d32ab69905075a",
"sha256:4a423038deabae8732f3ebf59f382e133539eeca3008df808cdd9cb1610645e4"
]
},
レイヤーとは個々のファイルシステムであり、UnionFSによってコンテナ起動時にまとめられるということでした。
UnionFSを知らなかったので、少し調べてみたところ、以下のサイトの例がわかりやすかったです。
まとめて束ねるUnionFSの不思議な世界 | TECHSCORE BLOG
別々のディレクトリにあるファイルを一つのディレクトリにまとめるといった動きをするようです。
上記のDockerfileは以下のように3つのレイヤーが積み重なっているようなイメージになるとのこと
また、finch image inspect
コマンドで表示された各レイヤーの sha256
から始まる値ですが、これは各レイヤーのファイルシステム全体のSHA256ハッシュ値とのことでした。これも知らなかったことです。(そもそも意識したことがなかった。。)
続いてビルドしたDockerイメージをECRにpushします。push後に aws ecr list-images
コマンドを実行すると以下のようにECR上コンテナイメージのimageDigestを取得することができます。
$ aws ecr list-images --repository-name nginx-demo
{
"imageIds": [
{
"imageDigest": "sha256:e55ec1cc522ed443723b483bbaecb51b750e612bb97eeb31b3906092afdb82d7",
"imageTag": "latest"
}
]
}
このimageDigestは何らかの値をSHA256ハッシュ化したものなわけですが、何をハッシュ化したものなのでしょうか?それもちゃんとワークショップの中で説明がありました。
ハッシュ化されているのはイメージマニフェストというコンテナのメタデータファイルになります。
コンテナイメージをECRにpushしたとき、実際には3つのレイヤーと2つのメタデータファイルをアップロードしているそうです。そのうちの一つがイメージマニフェストになります。以下のイメージです。
イメージマニフェストとは何なのでしょうか?実は aws ecr batch-get-image
コマンドでECR上のイメージマニフェストを取得することができます。
取得したマニフェストファイルは以下のようなものになっています。
{
"schemaVersion": 2,
"mediaType": "application/vnd.docker.distribution.manifest.v2+json",
"config": {
"mediaType": "application/vnd.docker.container.image.v1+json",
"digest": "sha256:1d09f59dd311c8f61fcf4784efb856d0e30ad5d8f3a2a1b10539efe6d6ecfedf",
"size": 1322
},
"layers": [
{
"mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
"digest": "sha256:808624112091b2c7033d4058144489bdca4c01777436e89b4d8d4a197f2dd9c1",
"size": 34236251
},
{
"mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
"digest": "sha256:0bd62ec97db90bde06777498677f3ee17a293206dcefb79931743df997e8aeea",
"size": 77316296
},
{
"mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
"digest": "sha256:60347bdb18d2a8fa73376605b701acc86408e861eebe45bfd13c69f8af6c6510",
"size": 623
}
]
}
マニフェストファイルにはコンテナイメージの構成情報であるレイヤーの情報やmediaTypeというマニフェストファイルがどの形式であるのかを示す情報が含まれています。上の例でいうと application/vnd.docker.distribution.manifest.v2+json
と書かれており、これは Docker Manifest v2コンテナイメージ仕様になるようです。
上記のマニフェストファイルをハッシュ化したものが、イメージダイジェストになるとのことでした。ワークショップではローカル上にあるコンテナイメージからマニフェストファイルを取り出しそのハッシュ値と aws ecr list-images
の結果を比較するといったこともやりました。
また、重要な点として、ECRは各コンテナイメージのレイヤーをS3に保存しているそうです。そうだったのか、、という感じです。
ワークショップでは実際に aws ecr get-download-url-for-layer
というコマンドを使用して、S3URLを取得し、レイヤーをダウンロードしてくるといったことまでやっていました。深すぎる。。
このレイヤーの中身というのがとても興味深かったので、共有します。 ダウンロードしてきたレイヤーはtar.gzで圧縮されています。このファイルを展開すると中身は以下のようになっていました。
.
└── usr
└── share
└── nginx
└── html
└── index.html
これがどこのレイヤーのファイルかわかりますでしょうか?そうです。以下の行のレイヤーになります。なるほどといった感じですよね。
COPY index.html /usr/share/nginx/html/index.html
この「ECRは各コンテナイメージのレイヤーをS3に保存している」という仕組みがSOCIに関係してきます。
SOCI CLIでSOCIインデックスを生成する
従来、ECSタスクが起動(コンテナイメージをpull)すると全てのコンテナイメージレイヤーがダウンロードされていました。SOCIという仕組みを用いることで「遅延読み込み」が可能になります。遅延読み込みでは、全てのレイヤーをダウンロードするのではなく、イメージマニフェストとSOCI Indexというコンテナイメージ内のすべてのファイルのインデックスのようなものを最初にダウンロードするそうです。
SOCI Indexは通常のdocker build(このワークショップではfinch build)ではDockerイメージに含まれないので専用のコマンドでビルドをする必要があります。
そのコマンドが、 SOCI CLI
になります。ここではSOCI CLIを使ったSOCIインデックスの作成方法を学びました。
ちなみにSOCIには2つの主要なコンポーネントがあります。
- soci-snapshotter:サーバー側で実行され、コンテナ イメージの遅延読み込みを処理するランタイム コンポーネント。
- SOCI CLI:ローカル マシン上で SOCI インデックスを作成するためのクライアント側CLI
以下のコマンドを実行することでSOCIインデックスを作成できました。なおワークショップ環境には最初からsociコマンドが入っていました。
soci create $ACCOUNT_ID.dkr.ecr.$AWS_REGION.amazonaws.com/nginx-demo:latest
上記のコマンドを実行することで、zTOCと呼ばれる全てのファイルのインデックスを作成します。
ワークショップではさらにSOCIインデックスの中身も確認しました。SOCIインデックスの内容はイメージマニフェストと似ていますが、異なる点として、subjectというフィールドがあり、ここにはこのSOCIインデックスがどのコンテナイメージに紐づけられているかが記載されていました。ちなみにSOCIインデックスはOCI準拠レジストリ(ECR等)にコンテナイメージとは別にアップロードされます。(そのため紐づけの定義が必要と思われる)
# SOCIインデックスの一部
"subject": {
"mediaType": "application/vnd.docker.distribution.manifest.v2+json",
"digest": "sha256:e55ec1cc522ed443723b483bbaecb51b750e612bb97eeb31b3906092afdb82d7",
"size": 897
},
SOCIインデックスとzTOCがごっちゃになりそう(私はなった)ですが、わかりやすい絵があったのでこちらも載せておきます。
SOCIインデックスビルダーを使いSOCIインデックスを生成する
上記のsociコマンドですが、各開発端末にいれるのが面倒そうだと思いませんか?
そんな方のためにSOCIインデックスビルダーというソリューションが提供されています。
これを使うとコンテナイメージがECRにプッシュされたときにSOCIインデックスを自動で生成してくれるとのことです。
アーキテクチャはこんな感じ
※CFN AWS SOCI Index Builder on AWS より参照
デプロイはCFnから実行できます。
Amazon ECS Fargateでコンテナイメージの遅延読み込みをやってみる
このセクションでは実際にECS FargateでSOCIを使った遅延読み込みを実施しました。
ECRにSOCIインデックスと紐づくコンテナイメージがpushされていれば、ECSタスク定義やECSサービス定義に特別な設定はいらないようです。(Fargateはデフォルトで全てのコンテナイメージを遅延読み込みしようとすると書いてありました)
遅延読み込みがちゃんとされたかどうかを確認するには通常の手段ではecs execでコンテナの中に入って、複雑なコマンドを実行して確認するしかないようです。
代替の確認手段として、am-i-lazyというサイドカーコンテナが紹介されていました。このコンテナを使うとCloudWatchLogsに遅延読み込みされたかどうかをログとして送信してくれるので、こういったものを使うのも一つの手かと思います。
ECSタスクでSOCIインデックスの使用有無によりどの程度の差がでるかを確認する
最後に遅延読み込みでどのくらいの差が出るかを確認しました。実際に試した際には遅延読み込みのほうが、起動開始が29秒だったのに対し、通常のものが86秒とだいぶ遅延読み込みのほうが早かったです。
しかしここで注意点があります。遅延読み込みは250 MB以上のコンテナイメージでないと効果は薄いということです。特に機械学習やデータ処理などコンテナイメージが大きくなるワークロードで効果を発揮するとのことでした。
まとめ
SOCI(Seekable OCI)を学ぶためにコンテナイメージの実体とはそもそもどういったものなのかを深堀りし、かなり具体的なところまで体験できるセッションになっており、私としてはとても学びになることが多いセッションでした。こういう深いところまでやるセッションって本当にいいですね。
以上、とーちでした。
参考
- まとめて束ねるUnionFSの不思議な世界 | TECHSCORE BLOG
- CFN AWS SOCI Index Builder on AWS
- awslabs/soci-snapshotter: A containerd snapshotter plugin which enables standard OCI images to be lazily loaded without requiring a build-time conversion step.
- aws-fargate-seekable-oci-toolbox/am-i-lazy at main · aws-samples/aws-fargate-seekable-oci-toolbox