虽然在部署和扩展应用程序时,使用容器进行开发的方式已日趋流行,但仍有一些领域可以改进。扩展容器化应用程序的主要问题之一是启动时间长,尤其是在纵向扩展期间,需要添加较新的实例。此问题可能会对客户体验(例如,当网站需要横向扩展以提供额外流量时)产生负面影响。
一份研究论文表明\[1],容器镜像下载占容器启动时间的 76%,但容器平均只需要 6.4% 的数据即可有效运行。启动和横向扩展容器化应用程序,需要从远程容器注册表下载容器镜像,因为必须先下载并解压缩整个镜像,然后才能启动应用程序,这会带来较大延迟。
该问题的解决方法之一是延迟加载(也称为异步加载)容器镜像。这种方法在启动应用程序的同时从容器注册表下载数据,例如 stargz-snapshotter 项目就是为了缩短容器的整体启动时间。
去年,我们推出了 Seekable OCI(SOCI),这是一项由亚马逊云科技开源的技术,它使容器运行时系统能够实现延迟加载容器镜像,从而在不修改容器镜像的情况下更快地启动应用程序。作为这项工作的一部分,我们开源了 SOCI Snapshotter,这是一款 snapshotter 插件,可在 containerd 中使用 SOCI 进行延迟加载。
### **Amazon Fargate 对 SOCI 的支持**
Amazon Fargate 现在支持 Seekable OCI(SOCI),它使容器无需等待下载整个容器镜像即可启动,从而帮助应用程序更快地部署和横向扩展。在发布时,这项新功能可用于在 Amazon Fargate 上运行的 [Amazon Elastic Container Service](https://aws.amazon.com/cn/ecs/?trk=cndc-detail)([Amazon ECS](https://aws.amazon.com/cn/ecs/?trk=cndc-detail))应用程序。
以下简要介绍一下 Amazon Fargate 对 SOCI 的支持是如何运作的:
<video src="https://s3.cn-north-1.amazonaws.com.cn/dev-media.amazoncloud.cn/d8ec848e-87e4-471e-b8ee-95246a042c4c_0908%20%E6%96%87%E4%B8%AD%E8%A7%86%E9%A2%91.mp4" class="bytemdVideo" controls="controls"></video>
SOCI 通过在现有容器镜像中创建文件索引(SOCI 索引)来运作。此索引是加快启动容器的关键因素,它可以从容器镜像中提取单个文件而不必下载整个镜像。应用程序不再需要等待完成对容器镜像的提取和解压操作,就可以开始运行。这使您可以更快地部署和横向扩展应用程序,并缩短应用程序更新的发布时间。
\
SOCI 索引与容器镜像分开生成和存储。这意味着无需转换容器镜像即可使用 SOCI,因此不会破坏基于安全哈希算法(SHA)的安全性,例如容器镜像签名。然后,索引与容器镜像一起存储于注册表中。在发布时,Amazon Fargate 对 SOCI 的支持与 Amazon Elastic Container Registry(Amazon ECR)配合使用。
当您将 [Amazon ECS](https://aws.amazon.com/cn/ecs/?trk=cndc-detail) 与 Amazon Fargate 配合使用来运行 SOCI 索引的容器化镜像时,Amazon Fargate 会自动检测是否存在该镜像的 SOCI 索引,并启动容器,而无需等待提取整个镜像。这也意味着 Amazon Fargate 仍将继续运行没有 SOCI 索引的容器镜像。
**我们开始吧!**
有两种方法可以为容器镜像创建 SOCI 索引。
* **使用 Amazon SOCI Index Builder**:Amazon SOCI Index Builder 是一款在 Amazon Cloud 中索引容器镜像的[无服务器](https://aws.amazon.com/cn/serverless/?trk=cndc-detail)解决方案。此 Amazon CloudFormation 堆栈部署 [Amazon EventBridge](https://aws.amazon.com/cn/eventbridge/?trk=cndc-detail) 规则来识别 Amazon ECR 操作事件,并调用 Amazon Lambda 函数来匹配定义的筛选条件。然后,另一个 Amazon Lambda 函数生成 SOCI 索引并将其推送到 Amazon ECR 注册表中的存储库。
* **手动创建 SOCI 索引**:这种方法可以更灵活地创建 SOCI 索引,包括为 Amazon ECR 存储库中的现有容器镜像创建索引。要创建 SOCI 索引,您可以使用 soci-snapshotter 项目提供的 `soci` CLI。
Amazon SOCI Index Builder 为您提供了一种自动化流程,让您可以开始为容器镜像构建 SOCI 索引。 `soci CLI` 在索引生成方面为您提供更大的灵活性,并能够将索引生成原生集成到 CI/CD 管道中。
在本文中,我们将使用 `soci-snapshotter` 项目中的 `soci CLI` 手动生成 SOCI 索引。
### **创建存储库并推送容器镜像**
首先,使用 Amazon CLI 为容器镜像创建了一个名为 `pytorch-soci` 的 Amazon ECR 存储库。
```Bash
\$ aws ecr create-repository --region us-east-1 --repository-name pytorch-soci
```
对于示例应用程序,我们使用来自亚马逊云科技深度学习容器的 PyTorch 训练(基于 CPU)容器镜像。因为默认情况下,Docker Engine 将容器镜像存储在 Docker Engine 镜像存储中,而不是 containerd 镜像存储中,所以使用 `nerdctl` CLI 来提取容器镜像。
```Bash
\$ SAMPLE_IMAGE="763104351884.dkr.ecr.us-east-1.amazonaws.com/pytorch-training:1.5.1-cpu-py36-ubuntu16.04"
\$ aws ecr get-login-password --region us-east-1 | sudo nerdctl login --username AWS --password-stdin xyz.dkr.ecr.ap-southeast-1.amazonaws.com
\$ sudo nerdctl pull --platform linux/amd64 \$SAMPLE_IMAGE
```
然后,标记在上一步中创建的存储库的容器镜像。
```Bash
\$ sudo nerdctl tag \$SAMPLE_IMAGE \$ECRSOCIURI
```
接下来,需要将容器镜像推送到 ECR 存储库中。
```Bash
\$ sudo nerdctl push \$ECRSOCIURI
```
此时,容器镜像已经存在于 Amazon ECR 存储库中。
![image.png](https://dev-media.amazoncloud.cn/f198a188464043b292ca911f761acfaa_image.png "image.png")
### 创建 SOCI 索引
接下来,我们需要创建 SOCI 索引。
SOCI 索引是允许延迟加载容器镜像的构件。SOCI 索引由 1) 一个 SOCI 索引清单和 2) 一组 zTOC 组成。下图说明了 SOCI 索引清单中的组件,以及它如何引用容器镜像清单。
![image.png](https://dev-media.amazoncloud.cn/f5576d216ea643d7bedbe8c4fbc7ebf5_image.png "image.png")
SOCI 索引清单包含 zTOC 列表以及对生成清单的镜像的引用。zTOC 或压缩数据的目录,由两部分组成:
TOC,一个包含文件元数据和解压后的 TAR 归档中相应偏移量的目录。
zInfo,检查点集合,表示压缩引擎在容器镜像层中不同点的状态。
要了解有关该概念和术语的更多信息,请访问 `soci-snapshotter` 术语页面(https://github.com/awslabs/soci-snapshotter/blob/main/docs/glossary.md?trk=cndc-detail )。
在创建 SOCI 索引之前,需要安装 `soci` CLI。要了解有关如何安装 `soci` 的更多信息,请访问 soci-snapshotter 入门(https://github.com/awslabs/soci-snapshotter/blob/main/docs/getting-started.md?trk=cndc-detail )。
我们使用 `soci create` 命令来创建 SOCI 索引。
```Bash
\$ sudo soci create \$ECRSOCIURI
layer sha256:4c6ec688ebe374ea7d89ce967576d221a177ebd2c02ca9f053197f954102e30b -> ztoc skipped
layer sha256:ab09082b308205f9bf973c4b887132374f34ec64b923deef7e2f7ea1a34c1dad -> ztoc skipped
layer sha256:cd413555f0d1643e96fe0d4da7f5ed5e8dc9c6004b0731a0a810acab381d8c61 -> ztoc skipped
layer sha256:eee85b8a173b8fde0e319d42ae4adb7990ed2a0ce97ca5563cf85f529879a301 -> ztoc skipped
layer sha256:3a1b659108d7aaa52a58355c7f5704fcd6ab1b348ec9b61da925f3c3affa7efc -> ztoc skipped
layer sha256:d8f520dcac6d926130409c7b3a8f77aea639642ba1347359aaf81a8b43ce1f99 -> ztoc skipped
layer sha256:d75d26599d366ecd2aa1bfa72926948ce821815f89604b6a0a49cfca100570a0 -> ztoc skipped
layer sha256:a429d26ed72a85a6588f4b2af0049ae75761dac1bb8ba8017b8830878fb51124 -> ztoc skipped
layer sha256:5bebf55933a382e053394e285accaecb1dec9e215a5c7da0b9962a2d09a579bc -> ztoc skipped
layer sha256:5dfa26c6b9c9d1ccbcb1eaa65befa376805d9324174ac580ca76fdedc3575f54 -> ztoc skipped
layer sha256:0ba7bf18aa406cb7dc372ac732de222b04d1c824ff1705d8900831c3d1361ff5 -> ztoc skipped
layer sha256:4007a89234b4f56c03e6831dc220550d2e5fba935d9f5f5bcea64857ac4f4888 -> ztoc sha256:0b4d78c856b7e9e3d507ac6ba64e2e2468997639608ef43c088637f379bb47e4
layer sha256:089632f60d8cfe243c5bc355a77401c9a8d2f415d730f00f6f91d44bb96c251b -> ztoc sha256:f6a16d3d07326fe3bddbdb1aab5fbd4e924ec357b4292a6933158cc7cc33605b
layer sha256:f18dd99041c3095ade3d5013a61a00eeab8b878ba9be8545c2eabfbca3f3a7f3 -> ztoc sha256:95d7966c964dabb54cb110a1a8373d7b88cfc479336d473f6ba0f275afa629dd
layer sha256:69e1edcfbd217582677d4636de8be2a25a24775469d677664c8714ed64f557c3 -> ztoc sha256:ac0e18bd39d398917942c4b87ac75b90240df1e5cb13999869158877b400b86
```
从上面的输出中,可以看出 soci CLI 为四层容器镜像层创建了 zTOC,这意味着将在容器镜像启动之前完整下载其他容器镜像层,只会延迟提取这四层。这是因为延迟加载非常小的容器镜像层对启动时间的影响较小。但是,在运行 soci create 时,您可以使用 --min-layer-size 标志来配置此行为。
### 验证并推送 SOCI 索引
soci CLI 还提供了几个命令来帮助您查看已生成的 SOCI 索引。
要查看所有索引清单的列表,可以运行以下命令。
```Bash
\$ sudo soci index list
DIGEST SIZE IMAGE REF PLATFORM MEDIA TYPE CREATED
sha256:ea5c3489622d4e97d4ad5e300c8482c3d30b2be44a12c68779776014b15c5822 1931 xyz.dkr.ecr.us-east-1.amazonaws.com/pytorch-soci:latest linux/amd64 application/vnd.oci.image.manifest.v1+json 10m4s ago
sha256:ea5c3489622d4e97d4ad5e300c8482c3d30b2be44a12c68779776014b15c5822 1931 763104351884.dkr.ecr.us-east-1.amazonaws.com/pytorch-training:1.5.1-cpu-py36-ubuntu16.04 linux/amd64 application/vnd.oci.image.manifest.v1+json 10m4s ago
```
虽然查看 zTOC 列表是选择性的,但在需要时,可以使用以下命令:
```Bash
\$ sudo soci ztoc list
DIGEST SIZE LAYER DIGEST
sha256:0b4d78c856b7e9e3d507ac6ba64e2e2468997639608ef43c088637f379bb47e4 2038072 sha256:4007a89234b4f56c03e6831dc220550d2e5fba935d9f5f5bcea64857ac4f4888
sha256:95d7966c964dabb54cb110a1a8373d7b88cfc479336d473f6ba0f275afa629dd 11442416 sha256:f18dd99041c3095ade3d5013a61a00eeab8b878ba9be8545c2eabfbca3f3a7f3
sha256:ac0e18bd39d398917942c4b87ac75b90240df1e5cb13999869158877b400b865 36277264 sha256:69e1edcfbd217582677d4636de8be2a25a24775469d677664c8714ed64f557c3
sha256:f6a16d3d07326fe3bddbdb1aab5fbd4e924ec357b4292a6933158cc7cc33605b 10152696 sha256:089632f60d8cfe243c5bc355a77401c9a8d2f415d730f00f6f91d44bb96c251b
```
这一系列 zTOC 包含 SOCI 所需的所有信息,可以在容器镜像层中查找给定文件。要查看每一层的 zTOC,可以使用前面输出的摘要总和之一,然后使用以下命令。
```Bash
\$ sudo soci ztoc info sha256:0b4d78c856b7e9e3d507ac6ba64e2e2468997639608ef43c088637f379bb47e4
{
"version": "0.9",
"build_tool": "AWS SOCI CLI v0.1",
"size": 2038072,
"span_size": 4194304,
"num_spans": 33,
"num_files": 5552,
"num_multi_span_files": 26,
"files": [
{
"filename": "bin/",
"offset": 512,
"size": 0,
"type": "dir",
"start_span": 0,
"end_span": 0
},
{
"filename": "bin/bash",
"offset": 1024,
"size": 1037528,
"type": "reg",
"start_span": 0,
"end_span": 0
}
---Trimmed for brevity---
```
现在,需要使用以下命令将所有与 SOCI 相关的构件推送到 Amazon ECR 中。
```Bash
\$ PASSWORD=\$(aws ecr get-login-password --region us-east-1)
\$ sudo soci push --user AWS:\$PASSWORD \$ECRSOCIURI
```
访问 Amazon ECR 存储库,就可以验证是否已创建索引。在这里,我们可以看到容器镜像旁边列出了另外两个对象:**SOCI 索引**和**镜像索引**。镜像索引让 Amazon Fargate 可以查找与容器镜像关联的 SOCI 索引。
![image.png](https://dev-media.amazoncloud.cn/d4f5c95e3a904f2aba95c268e71d61d2_image.png "image.png")
### **了解 SOCI 性能**
SOCI 的主要目标是最大限度地减少启动容器化应用程序所需的时间。要使用 SOCI 衡量 Amazon Fargate 延迟加载容器镜像的性能,我们需要了解容器镜像启动 SOCI 和不启动 SOCI 需要多长时间。
要了解每个容器镜像启动所需的持续时间,我可以使用 [Amazon ECS](https://aws.amazon.com/cn/ecs/?trk=cndc-detail) 上的 `DescribeTasks` API 提供的指标。第一个指标是 `createdAt` ,这是创建任务并进入 `PENDING` 状态的时间戳。第二个指标是 `startedAt` ,即任务从 `PENDING` 状态转变为 `RUNNING` 状态的时间。
为此,我们使用相同的容器镜像创建了另一个 Amazon ECR 存储库,但没有生成 SOCI 索引,名为 `pytorch-without-soci` 。 如果要比较这些容器镜像,在 `pytorch-soci` 中还有另外两个对象(一个镜像索引和一个 SOCI 索引),它们在 `pytorch-without-soci` 中不存在。
![image.png](https://dev-media.amazoncloud.cn/88dcb737e49e43308adc75e79ce8e7d6_image.png "image.png")
### **部署和运行应用程序**
为了运行这些应用程序,我创建了一个名为 demo-pytorch-soci-cluster 的 [Amazon ECS](https://aws.amazon.com/cn/ecs/?trk=cndc-detail) 集群、一个 VPC 和所需的 ECS 任务执行角色。如果您不熟悉 [Amazon ECS](https://aws.amazon.com/cn/ecs/?trk=cndc-detail),可以参阅 [Amazon ECS 入门](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/getting-started.html?trk=cndc-detail),了解如何部署和运行容器化应用程序。
现在,让我们以 FARGATE 为启动类型来部署和运行这两个容器镜像。我们为每个 pytorch-soci 和 pytorch-without-soci 定义了五个任务。
```Bash
\$ aws ecs \\
--region us-east-1 \\
run-task \\
--count 5 \\
--launch-type FARGATE \\
--task-definition arn:aws:ecs:us-east-1:XYZ:task-definition/pytorch-soci \\
--cluster socidemo
\$ aws ecs \\
--region us-east-1 \\
run-task \\
--count 5 \\
--launch-type FARGATE \\
--task-definition arn:aws:ecs:us-east-1:XYZ:task-definition/pytorch-without-soci \\
--cluster socidemo
```
几分钟后,ECS 集群上有 10 个正在运行的任务。
![image.png](https://dev-media.amazoncloud.cn/4f62221eafe8416688730985098bc486_image.png "image.png")
确认所有任务都在运行后,我们运行以下脚本以获取两个指标: `createdAt` 和 `startedAt` 。
```Bash
#!/bin/bash
CLUSTER=<CLUSTER_NAME>
TASKDEF=<TASK_DEFINITION>
REGION="us-east-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
```
对没有 SOCI 索引的容器镜像( `pytorch-without-soci` )运行上述命令会产生以下输出:
```Bash
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
| DescribeTasks |
+----------------------------------+-----------------------------------+------------------------------------------------------------------------------------------------------------+
| createdAt | startedAt | taskArn |
+----------------------------------+-----------------------------------+------------------------------------------------------------------------------------------------------------+
| 2023-07-07T17:43:59.233000+00:00| 2023-07-07T17:46:09.856000+00:00 | arn:aws:ecs:ap-southeast-1:xyz:task/demo-pytorch-soci-cluster/dcdf19b6e66444aeb3bc607a3114fae0 |
| 2023-07-07T17:43:59.233000+00:00| 2023-07-07T17:46:09.459000+00:00 | arn:aws:ecs:ap-southeast-1:xyz:task/demo-pytorch-soci-cluster/9178b75c98ee4c4e8d9c681ddb26f2ca |
| 2023-07-07T17:43:59.233000+00:00| 2023-07-07T17:46:21.645000+00:00 | arn:aws:ecs:ap-southeast-1:xyz:task/demo-pytorch-soci-cluster/7da51e036c414cbab7690409ce08cc99 |
| 2023-07-07T17:43:59.233000+00:00| 2023-07-07T17:46:00.606000+00:00 | arn:aws:ecs:ap-southeast-1:xyz:task/demo-pytorch-soci-cluster/5ee8f48194874e6dbba75a5ef753cad2 |
| 2023-07-07T17:43:59.233000+00:00| 2023-07-07T17:46:02.461000+00:00 | arn:aws:ecs:ap-southeast-1:xyz:task/demo-pytorch-soci-cluster/58531a9e94ed44deb5377fa997caec36 |
+----------------------------------+-----------------------------------+------------------------------------------------------------------------------------------------------------+
```
根据每项任务的平均累计时间差异(从 `startedAt` 到 `createdAt` 之间), `pytorch-without-soci` (没有 SOCI 索引)在 129 秒后成功运行。
接下来,对带有 SOCI 索引的 `pytorch-soci` 运行同样的命令。
```Bash
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
| DescribeTasks |
+----------------------------------+-----------------------------------+------------------------------------------------------------------------------------------------------------+
| createdAt | startedAt | taskArn |
+----------------------------------+-----------------------------------+------------------------------------------------------------------------------------------------------------+
| 2023-07-07T17:43:53.318000+00:00| 2023-07-07T17:44:51.076000+00:00 | arn:aws:ecs:ap-southeast-1:xyz:task/demo-pytorch-soci-cluster/c57d8cff6033494b97f6fd0e1b797b8f |
| 2023-07-07T17:43:53.318000+00:00| 2023-07-07T17:44:52.212000+00:00 | arn:aws:ecs:ap-southeast-1:xyz:task/demo-pytorch-soci-cluster/6d168f9e99324a59bd6e28de36289456 |
| 2023-07-07T17:43:53.318000+00:00| 2023-07-07T17:45:05.443000+00:00 | arn:aws:ecs:ap-southeast-1:xyz:task/demo-pytorch-soci-cluster/4bdc43b4c1f84f8d9d40dbd1a41645da |
| 2023-07-07T17:43:53.318000+00:00| 2023-07-07T17:44:50.618000+00:00 | arn:aws:ecs:ap-southeast-1:xyz:task/demo-pytorch-soci-cluster/43ea53ea84154d5aa90f8fdd7414c6df |
| 2023-07-07T17:43:53.318000+00:00| 2023-07-07T17:44:50.777000+00:00 | arn:aws:ecs:ap-southeast-1:xyz:task/demo-pytorch-soci-cluster/0731bea30d42449e9006a5d8902756d5 |
+----------------------------------+-----------------------------------+------------------------------------------------------------------------------------------------------------+
```
此处看到启用了 SOCI 的容器镜像 pytorch-soci 是在创建 60 秒后启动的。
这意味着,与不使用 SOCI 索引运行示例应用程序相比,在 Amazon Fargate 上运行使用 SOCI 索引的示例应用程序要快约 50%。
建议在使用 SOCI 和不使用 SOCI 的情况下对应用程序的启动和横向扩展时间进行基准测试。这可以帮助您更好地了解应用程序的运行情况,以及您的应用程序是否受益于 Amazon Fargate 对 SOCI 的支持。
### **客户心声**
在专属预览期间,我们听到了客户对 Amazon Fargate 对 SOCI 的支持的大量反馈。以下是客户的话:
![image.png](https://dev-media.amazoncloud.cn/5f52de73aac441f681a1803847bc5b1c_image.png "image.png")
### 注意事项
可用性:Amazon Fargate 对 SOCI 的支持适用于所有提供 [Amazon ECS](https://aws.amazon.com/cn/ecs/?trk=cndc-detail)、Amazon Fargate 和 Amazon ECR 的亚马逊云科技区域。
定价:Amazon Fargate 对 SOCI 的支持无需额外付费,您只需为在 Amazon ECR 中存储 SOCI 索引付费。
入门:在 Amazon Fargate 对 SOCI 的支持页面上详细了解优势以及入门指南。
祝大家构建顺利。
[1] https://www.usenix.org/conference/fast16/technical-sessions/presentation/harter?trk=cndc-detail
![开发者尾巴.gif](https://dev-media.amazoncloud.cn/4841597703804853bfea475ea9b657be_%E5%BC%80%E5%8F%91%E8%80%85%E5%B0%BE%E5%B7%B4.gif "开发者尾巴.gif")