谷歌云 | 减少 Google Kubernetes Engine 冷启动延迟的 4 种方法

如果您在 Kubernetes 上运行工作负载,您很可能经历过“冷启动”:当工作负载被调度到之前未托管该工作负载的节点并且 Pod 需要从头开始启动时,会出现应用程序启动延迟的情况。延长的启动时间可能会导致更长的响应时间和更糟糕的用户体验 – 特别是当应用程序自动扩展以应对流量激增时。

冷启动时发生了什么?在 Kubernetes 上部署容器化应用程序通常涉及几个步骤,包括拉取容器映像、启动容器和初始化应用程序代码。这些过程都会增加 Pod 开始提供流量之前的时间,从而导致新 Pod 提供的第一个请求的延迟增加。由于新节点没有预先存在的容器映像,因此初始启动时间可能会明显延长。对于后续请求,Pod 已经启动并预热,因此它可以快速处理请求,而无需额外的启动时间。

当 Pod 不断关闭和重新启动时,冷启动很频繁,因为这会强制将请求路由到新的冷 Pod。常见的解决方案是让 Pod 池保持就绪状态,以减少冷启动延迟。

然而,对于 AI/ML 等较大的工作负载,尤其是在昂贵且稀缺的 GPU 上,温池实践的成本可能非常高。因此,冷启动对于 AI/ML 工作负载尤其普遍,通常在完成请求后关闭 pod。

Google Kubernetes Engine (GKE) 是 Google Cloud 的托管 Kubernetes 服务,可以让您更轻松地部署和维护复杂的容器化工作负载。在这篇文章中,我们将讨论四种不同的技术来减少 GKE 上的冷启动延迟,以便您可以提供响应式服务。

克服冷启动挑战的技术

1. 将临时存储与本地 SSD 或更大的启动磁盘结合使用

节点将Kubelet和容器运行时(docker或containerd)根目录安装在本地SSD上。因此,容器层由本地 SSD 支持,IOPS 和吞吐量记录在关于本地 SSD 中。这通常比增加 PD 尺寸更具成本效益。

下表对这些选项进行了比较,并表明,在相同的成本下,LocalSSD 的吞吐量比 PD 高约 3 倍,从而使映像拉取运行得更快并减少工作负载的启动延迟。

您可以在 GKE 版本1.25.3-gke.1800 或更高版本上运行的现有集群中创建一个节点池,该节点池使用带有本地 SSD 的临时存储。

gcloud container node-pools create POOL_NAME \
–cluster=CLUSTER_NAME \
–ephemeral-storage-local-ssd count=<NUMBER_OF_DISKS> \
–machine-type=MACHINE_TYPE

有关更多信息,请参阅使用本地 SSD 配置临时存储

2. 启用容器镜像流式传输

图像流可以允许工作负载无需等待整个图像下载完毕即可启动,从而显着缩短工作负载启动时间。例如,借助 GKE 镜像流,NVIDIA Triton 服务器(5.4GB 容器镜像)的端到端启动时间(从工作负载创建到服务器启动以获取流量)可从 191 秒缩短至 30 秒。

您必须为您的容器使用 ArtifactRegistry 并满足要求。可以通过以下方式在集群上启用图像流。

gcloud container clusters create CLUSTER_NAME \
–zone=COMPUTE_ZONE \
–image-type=”COS_CONTAINERD” \
–enable-image-streaming

要了解更多信息,请参阅使用镜像流拉取容器镜像

3.使用Zstandard压缩容器镜像

Zstandard 压缩是 ContainerD 支持的一项功能。Zstandard 基准测试显示 zstd 的解压缩速度比 gzip(当前默认值)快 3 倍以上。

以下是如何在 docker buildx 中使用 zstd 构建器:

docker buildx create –name zstd-builder –driver docker-container \
–driver-opt image=moby/buildkit:v0.10.3
docker buildx use zstd-builder

以下是构建和推送镜像的方法:

IMAGE_URI=us-central1-docker.pkg.dev/taohe-gke-dev/example
IMAGE_TAG=v1

<Create your Dockerfile>

docker buildx build –file Dockerfile –output type=image,name=$IMAGE_URI:$IMAGE_TAG,oci-mediatypes=true,compression=zstd,compression-level=3,force-compression=true,push=true .

请注意,Zstandard 与图像流不兼容。如果您的应用程序需要在启动之前加载大部分容器镜像内容,那么最好使用 Zstandard。如果您的应用程序只需要加载整个容器映像的一小部分即可开始执行,那么请尝试图像流。

4. 使用预加载器 DaemonSet 在节点上预加载基础容器

最后但并非最不重要的一点是,如果不同容器共享相同的基础容器,ContainerD 会在不同容器之间重用图像层。预加载器 DaemonSet 甚至可以在安装 GPU 驱动程序之前开始运行(驱动程序安装大约需要 30 秒)。这意味着它可以在将 GPU 工作负载调度到 GPU 节点并开始提前拉取映像之前预加载所需的容器。

下面是预加载器 DaemonSet 的示例:

apiVersion: apps/v1
kind: DaemonSet
metadata:
name: container-preloader
labels:
k8s-app: container-preloader
spec:
selector:
matchLabels:
k8s-app: container-preloader
updateStrategy:
type: RollingUpdate
template:
metadata:
labels:
name: container-preloader
k8s-app: container-preloader
spec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
– matchExpressions:
– key: cloud.google.com/gke-accelerator
operator: Exists
tolerations:
– operator: “Exists”
containers:
– image: “<CONTAINER_TO_BE_PRELOADED>”
name: container-preloader
command: [ “sleep”, “inf” ]

超越冷启动

冷启动挑战是容器编排系统中的常见问题。通过仔细规划和优化,您可以减轻其对 GKE 上运行的应用程序的影响。通过使用具有更大启动磁盘的临时存储、启用容器流或 Zstandard 压缩以及使用守护程序集预加载基础容器,您可以减少冷启动延迟并确保系统响应更快、更高效。如果您想要了解有关 GKE 的更多信息,可以留言联系我们。

Leave a Reply