当前位置: 首页 > 科技观察

如何在Kubernetes集群中优雅地缓存容器镜像

时间:2023-03-14 13:23:23 科技观察

简介当容器化应用程序部署到Kubernetes集群时,K8s控制平面将调度Pod到集群中的工作节点。在工作节点上运行的节点代理(Kubelet)与安装在节点上的容器运行时(例如containerd)协调,并从镜像注册表中拉取必要的容器镜像。根据图像的大小和可用的网络带宽,将所有图像拉到节点需要时间。因此,在任何容器化应用程序中,我们都应该意识到从注册表中获取图像所引入的延迟。然而,作为进程运行的传统应用程序(例如由systemd管理)不会受到这种延迟的影响,因为所有必要的文件都已经安装在机器中。想象一下,您的容器化应用程序流量突然激增,需要立即扩展(即需要创建额外的实例)。如果您配置Horizo??ntalPodAutoscaler(HPA),K8s控制平面会创建额外的Pod副本。但是,在拉取所需的图像并且容器启动并运行之前,这些Pod将无法用于处理增加的流量。或者假设您的应用程序需要处理高速实时数据。由于其服务目的的性质,此类应用程序对其启动和扩展的速度有严格的要求。简而言之,在某些用例中,从注册表中拉取图像所引入的延迟是不可接受的。此外,集群和镜像registry之间的网络连接可能会遇到带宽不足的问题,或者连接可能会完全丢失。在某些情况下,尤其是在边缘计算中,应用程序必须优雅地容忍间歇性网络连接。这些挑战可以通过不同的方式来应对。在这些场景中非常有用的一种解决方案是直接在集群工作节点上缓存容器镜像,这样Kubelet就不需要拉取这些镜像,而是立即使用已经缓存在节点上的镜像。在这篇博客中,我解释了如何使用开源项目kube-fledged在Kubernetes集群中构建和管理容器镜像缓存。现有解决方案在向您介绍kube-fledged之前,让我简要介绍一下针对该问题的现有解决方案。一种广泛使用的方法是在集群内运行注册表镜像。两种广泛使用的解决方案是集群内自托管注册表和直通缓存。在前一种解决方案中,本地注册表在k8s集群中运行,并在容器运行时配置为镜像注册表。任何图像拉取请求都会定向到集群内注册表。如果失败,请求将被定向到主注册表。在后一种解决方案中,本地注册表具有缓存功能。第一次拉取镜像时,它会缓存在本地注册表中。对镜像的后续请求由本地注册表提供服务。现有解决方案的缺点建立和维护本地注册表镜像会消耗大量的计算和人力资源。对于跨越多个区域的大型集群,我们需要有多个本地注册表镜像。当应用程序实例跨越多个区域时,这会引入不必要的复杂性。您可能需要多个部署清单,每个都指向该区域的本地注册表镜像。这些方法并没有完全解决Pod快速启动的需求,因为从本地镜像中拉取镜像还是有明显延迟的。有几个用例不能容忍这种延迟。节点可能会失去与本地注册表镜像的网络连接,因此Pod将被卡住,直到连接恢复。kube-fledged概述kube-fledged是一个kubernetes插件或操作符,用于直接在kubernetes集群的工作节点上创建和管理容器镜像缓存。它允许用户定义图像列表以及这些图像应该缓存(即从中提取)的工作节点。因此,应用程序pod几乎立即启动,因为不需要从注册表中提取图像。kube-fledged提供了一个CRUDAPI来管理图像缓存的生命周期,并支持多个可配置参数以根据需要自定义功能。https://github.com/senthilrch/kube-fledged)kube-fledged被设计和构建为在Kubernetes中管理图像缓存的通用解决方案。虽然主要用例是实现快速pod启动和扩展,但该解决方案支持各种用例,如下所述用例应用程序需要快速启动。例如,由于数据量呈爆炸式增长,执行实时数据处理的应用程序需要快速扩展。无服务器功能是因为它们需要立即对传入的事件做出反应。边缘设备上运行的物联网应用程序,因为边缘设备和镜像注册表之间的网络连接是间歇性的。如果需要从私有注册表中拉取镜像,并且不可能让每个人都可以从该注册表中拉取镜像,则可以在集群节点上提供这些镜像。如果集群管理员或运维人员需要升级应用,想提前验证新镜像是否能拉取成功。kube-fledged的??工作原理Kubernetes允许开发人员使用自定义资源扩展kubernetesapi。kube-fledged定义了一个类型为“ImageCache”的自定义资源,并实现了一个自定义控制器(名为kubefledged-controller)。kubefledged-controller负责管理图像缓存。用户可以使用kubectl命令创建和删除ImageCache资源。kubefledged-controller有一个内置的图像管理器例程,负责拉取和删除图像。使用kubernetes作业来拉取或删除图像。如果启用,刷新工作者会定期刷新图像缓存。kubefledged-controller在ImageCache资源的状态字段中更新镜像拉取、刷新和镜像删除的状态。kubefledged-webhook-server负责验证ImageCache资源的字段。如果需要在集群中创建图片缓存,只需要指定需要拉取的图片列表和nodeSelector来使用ImageCache即可。使用nodeSelector指定应在其上缓存图像的节点。如果您希望在集群的所有节点上缓存图像,请省略nodeSelector。当您将清单提交到集群时,API服务器将向kubefledged-webhook-server发布一个验证webhook事件。Webhook服务器验证的cacheSpecs列表。API服务器在收到webhook服务器的成功响应后,将ImageCache资源持久化到etcd中。这会触发一个Informer通知到kubefledged-controller,它将请求排队。该请求由图像缓存工作器接收,它创建多个图像拉取请求(每个节点每个图像一个请求)并将它们放入图像拉取/删除队列中。这些请求由镜像管理器例程处理。对于每个请求,图像管理器都会创建一个k8s作业,负责将图像拉入缓存。图像管理器跟踪它创建的作业,一旦作业完成,它将响应放在一个单独的队列中。ImageCacheWorker然后聚合来自ImageManager的所有结果,最后更新ImageCache资源的Status部分。kube-fledged有一个flushworker例程,它定期运行以保持图像缓存新鲜。如果它发现缓存中缺少任何图像(可能被kubelet的图像垃圾收集器删除),它会将图像拉回到缓存中。带有:latest标签的图像总是在刷新周期中被重新拉取。默认情况下,刷新周期为每5m。在部署kube-fledged时,用户可以将其修改为不同的值或完全禁用自动刷新机制。还支持按需刷新机制,用户可以通过该机制请求kube-fledged立即刷新图像缓存。kube-fledged支持的图像缓存操作kube-fledged支持以下图像缓存操作。所有这些操作都可以使用kubectl或通过直接向KubernetesAPI服务器提交RESTAPI请求来执行:创建图像缓存修改图像缓存刷新图像缓存清除图像缓存删除图像缓存支持的容器运行时DockerContainerdCri-o支持的平台linux/amd64linux/armlinux/arm64使用kube-fledged使用kube-fledged最快的方法是使用项目GitHubRepo(https://github.com/senthilrch/kube-fledged)中的YAML清单部署它。您还可以使用helmchart和helmoperator部署它。在下面找到使用清单部署kube-fledged的??步骤:HOME/src/github.com/senthilrch/kube-fledged$cd$HOME/src/github.com/senthilrch/kube-fledged将kube-fledged部署到集群$makedeploy-using-yaml验证kube-fledged是否已成功部署$kubectlgetpods-nkube-fledged-lapp=kubefledged$kubectlgetimagecaches-nkube-fledged(Outputsshouldbe:'Noresourcesfound')类似解决方案在下面找到我注意到的类似开源解决方案列表。这些解决方案尝试使用替代的StargzSnapshotter来解决问题:具有延迟拉取功能的快速容器图像分发插件(https://github.com/containerd/stargz-snapshotter)数秒内的数据(https://github.com/uber/kraken)Imagewolf:ImageWolf是一个PoC,它提供了一种将Docker图像加载到集群上的极快方法,从而实现更快的推送更新https://github.com/ContainerSolutions/ImageWolf)结论一些应用程序和用例需要快速启动和扩展。在这种情况下,从注册表中拉取图像的延迟可能是不可接受的。此外,与注册表的网络连接可能不稳定/间歇性。出于安全原因,可能不授予所有用户访问安全注册表的权限。Kube-fledged是一个简单而有用的解决方案,可以直接在集群工作节点上构建和管理容器镜像缓存