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