容器镜像加速指南:探索 Kubernetes 缓存最佳实践
介绍
将容器化应用程序部署到 Kubernetes 集群时,由于从 registry 中提取必要的容器镜像需要时间,因此可能会出现延迟。在应用程序需要横向扩展或处理高速实时数据的情况下,这种延迟尤其容易造成问题。幸运的是,有几种工具和策略可以改善 Kubernetes 中容器镜像的可用性和缓存。在本篇文章中,我们将全面介绍这些工具和策略,包括 kube-fledged、kuik、Kubernetes 内置的镜像缓存功能、本地缓存以及监控和清理未使用的镜像。

前提
将工作负载部署到 Kubernetes 时,某个 Pod 中的容器自然会基于 OCI 容器镜像。这些镜像可以从多种私有/公共存储库中提取。Kubernetes 会在拉取镜像的每个节点上本地缓存镜像,以便其他 Pod 使用相同的镜像。

然而在大多数用例中,这还不够。如今,大多数云 Kubernetes 集群都需要自动扩展,并根据客户的使用情况动态分配节点。如果多个节点必须多次调用同一个镜像怎么办?如果这个镜像很重,那可能需要几分钟时间。在应用自动伸缩的情况下,需要相对较长的时间。
现有解决方案
预期的解决方案需要在 Kubernetes 上建立一个缓存层,这样 Kubernetes 就有了一个集中的镜像缓存,所有节点都能从其中 "提取 "镜像。但是,由于缓存需要非常快,因此缓存解决方案需要位于 Kubernetes 内部,所有节点都应该以最快的延迟到达缓存。
要解决从 registry 中提取容器镜像的延迟问题,广泛使用的方法是在集群内运行 registry 镜像。
两种广泛使用的解决方案是集群内自托管 registry 和推送缓存 (pull-through cache)。
在前一种解决方案中,本地 registry 在 Kubernetes 集群内运行,并在容器运行时配置为镜像 registry。任何镜像拉取请求都会指向集群内的 registry。在后一种解决方案中,容器镜像的缓存直接在工作节点上构建和管理。
其他现有解决方案包括使用 kuik 等可靠的缓存解决方案、在 Kubernetes 中启用镜像缓存、使用本地缓存、优化容器镜像构建以及监控和清理未使用的镜像。
Harbor
Harbor 是一个 CNCF 毕业项目,它的功能是容器 registry ,但最重要的是它还是一个推送代理缓存 (Pull Through Proxy Cache)。
推送代理缓存是一种缓存机制,旨在优化容器 registry 环境中容器镜像的分发和检索。它充当用户端(如容器运行时或构建系统)和上游容器 registry 之间的中介。
当用户端请求容器镜像时,直通式代理缓存会检查它是否已经拥有所请求镜像的本地副本。如果镜像存在,代理缓存会直接将其提供给客户端,而无需从上游 registry 下载。这样可以减少网络延迟并节省带宽。
如果本地缓存中没有请求的镜像,代理缓存就会充当普通代理,将请求转发到上游 registry。然后,代理缓存会从 registry 中检索镜像,并将其提供给客户端。此外,代理缓存还会在其本地缓存中存储一份镜像副本,以备将来请求之用。

kube-fledged
kube-fledged 是一个 K8s 附加组件或 operator,用于直接在 Kubernetes 集群的工作节点上创建和管理容器镜像缓存。它允许用户定义镜像列表,并将这些镜像缓存到哪个工作节点上。kube-fledged 提供了 CRUD API 来管理镜像缓存的生命周期,并支持多个可配置参数,以便根据个人需求定制功能。
kube-fledged 是为管理 Kubernetes 中的镜像缓存而设计和构建的通用解决方案。虽然主要用例是实现 Pod 的快速启动和扩展,但该解决方案支持下列的各种实例。
工作原理

kube-fledged 定义了一种名为 “ImageCache” 的自定义资源,并实现了一个自定义控制器(名为 kubefledged-controller)。用户可以使用 kubectl 命令创建和删除 ImageCache 资源。
Kubernetes-image-puller
为了缓存镜像,Kubernetes Image Puller 会在所需集群上创建一个 Daemonset,然后在集群中的每个节点上创建一个 pod,其中包含一个命令 sleep 720h 的容器列表。这样就能确保集群中的所有节点都缓存了这些镜像。使用的 sleep 二进制基于 golang(请参阅 Scratch Images:https://github.com/che-incubator/kubernetes-image-puller#scratch-images)。
我们还会定期检查守护进程集的健康状况,并在必要时重新创建它。
可以通过 Helm 或处理和应 OpenShift 模板来部署应用程序。此外,OperatorHub 上还有一个社区支持的 Operator。

kubernetes-image-puller 部署了大量容器(每个镜像和每个节点一个容器,缓存机制使用 daemonset),以实现缓存功能。
举个例子:缓存中有 5 个节点和 10 个镜像,而我们在集群中已经有 50 个容器专门用于缓存功能。
Tugger
Tugger 使用单一配置文件,通过其 Helm 文件值定义。它不允许我们将“系统”配置(例如:从缓存系统中排除特定图片)和 “用户”配置分开。
Tugger 使用通过 Helm 文件值定义的单一配置文件。它不允许分离 "系统 "配置,比如从缓存系统中排除特定镜像,和 "用户 "配置。
kube-image-keeper (kuik)
kube-image-keeper(又名 kuik,类似于 “quick”)是 Kubernetes 的容器镜像缓存系统。它能将 pod 使用的容器镜像保存在自己的本地 registry 中,这样在原始镜像不可用时,这些镜像仍可使用。
工作原理
创建 pod 时,kuik 的 webhook 会即时重写其镜像,并添加 localhost:{port}/ 前缀(默认 port 为 7439,可配置)。
在 localhost:{port} 上有一个镜像代理,它从 kuik 的缓存 registry (当镜像已被缓存时)或直接从原始 registry (当镜像尚未被缓存时)提供镜像。
控制器负责监控 pod,当发现新的镜像时,就会为这些镜像创建 CachedImage 自定义资源。另一个控制器会监测这些 CachedImage 自定义资源,并相应地将镜像从源 registry 复制到 kuik 的缓存 registry 中。
架构和组件
在 kuik 的命名空间中,您可以找到:
- 运行 kuik 控制器的
Deployment - 运行 kuik 镜像代理的
DaemonSet - 当该组件在 HA 模式下运行时,会使用
StatefulSet来运行 kuik 的镜像缓存,而不是Deployment。
运行镜像缓存显然需要一定的磁盘空间(请参考 Garbage collection and limitations:https://github.com/enix/kube-image-keeper#garbage-collection-and-limitations)。除此之外,就计算资源而言,kuik 组件是相当轻量级的。这显示了默认设置下的 CPU 和 RAM 使用情况,其中两个控制器处于 HA 模式:
$ kubectl top pods
NAME CPU(cores) MEMORY(bytes)
kube-image-keeper-0 1m 86Mi
kube-image-keeper-controllers-5b5cc9fcc6-bv6cp 1m 16Mi
kube-image-keeper-controllers-5b5cc9fcc6-tjl7t 3m 24Mi
kube-image-keeper-proxy-54lzk 1m 19Mi

Warm-image
WarmImage CRD 获取镜像参考,并将其预取到集群中的每个节点上。
要在集群中安装这一自定义资源,只需运行:
# Install the CRD and Controller.
curl https://raw.githubusercontent.com/mattmoor/warm-image/master/release.yaml \
| kubectl create -f -
或者,您也可以 git clone 该仓库并运行:
# Install the CRD and Controller.
kubectl create -f release.yaml
结论
在这篇文章中,我们向您展示了如何通过在节点上缓存镜像来加快 Pod 的启动速度。通过在 kubernetes 集群的工作节点上预取容器镜像,您可以显著缩短 Pod 的启动时间,即使是大型镜像,也可以缩短到几秒钟。这项技术能让运行机器学习、仿真、数据分析和代码构建等工作负载的客户受益匪浅,提高容器启动性能和整体工作负载效率。
由于无需额外管理基础设施或 Kubernetes 资源,这种方法为解决基于 Kubernetes 的环境中容器启动缓慢的问题提供了一种经济高效的解决方案。
容器镜像加速指南:探索 Kubernetes 缓存最佳实践的更多相关文章
- 在 Kubernetes 容器集群,微服务项目最佳实践
转载自:https://mp.weixin.qq.com/s/WYu3gDwKKf06f_FYbO9YRg 本文主要介绍我个人在使用 Kubernetes 的过程中,总结出的一套「Kubernetes ...
- Kubernetes Deployment 最佳实践
零.示例 首先给出一个 Deployment+HPA+ PodDisruptionBudget 的完整 demo,后面再详细介绍其中的每一个部分: apiVersion: apps/v1 kind: ...
- Kubernetes YAML最佳实践和策略
Kubernetes工作负载最常用YAML格式的文件来定义. YAML的问题之一就是很难描述清单文件之间的约束或关系. 如果你希望检查是否已从受信任的注册表中提取部署到群集中的所有映像,该怎么办? 如 ...
- 探索云数据库最佳实践 阿里云开发者大会数据库专场邀你一起Code up!
盛夏.魔都.科技 三者在一起有什么惊喜? 7月24日,阿里云峰会·上海——开发者大会将在上海世博中心盛大启程,与未来世界的开发者们分享数据库.云原生.开源大数据等领域的技术干货,共同探讨前沿科技趋势, ...
- vue项目缓存最佳实践
需求 在开发vue的项目中有遇到了这样一个需求:一个视频列表页面,展示视频名称和是否收藏,点击进去某一项观看,可以收藏或者取消收藏,返回的时候需要记住列表页面的页码等状态,同时这条视频的收藏状态也需要 ...
- [转载]三小时学会Kubernetes:容器编排详细指南
原翻译by梁晓勇 原英文:Learn Kubernetes in Under 3 Hours: A Detailed Guide to Orchestrating Containers 我很奇怪,为什 ...
- 生产环境容器落地最佳实践 --JFrog 内部K8s落地旅程
引言 Kubernetes已经成为市场上事实上领先的编配工具,不仅对技术公司如此,对所有公司都是如此,因为它允许您快速且可预测地部署应用程序.动态地伸缩应用程序.无缝地推出新特性,同时有效地利用硬件资 ...
- ImageApparate(幻影)镜像加速服务让镜像分发效率提升 5-10 倍
作者介绍 李昂,腾讯高级开发工程师,主要关注容器存储和镜像存储相关领域,目前主要负责腾讯容器镜像服务和镜像存储加速系统的研发和设计工作. 李志宇,腾讯云后台开发工程师.负责腾讯云 TKE 集群节点和运 ...
- Kubernetes生产环境最佳实践
点击上方"开源Linux",选择"设为星标" 回复"学习"获取独家整理的学习资料! 众所周知,Kubernetes很难! 以下是在生产中使用 ...
- 制作 Python Docker 镜像的最佳实践
概述 ️Reference: 制作容器镜像的最佳实践 这篇文章是关于制作 Python Docker 容器镜像的最佳实践.(2022 年 12 月更新) 最佳实践的目的一方面是为了减小镜像体积,提升 ...
随机推荐
- Linux 中Yum命令使用方法
Linux系统下常用yum安装命令详解 yum常用安装命令 使用yum安装和卸载软件,有个前提是yum安装的软件包都是rpm格式的. 1.安装killall命令yum install -y psm ...
- Zabbix 配置笔记
Zabbix Server 安装参考 https://www.cnblogs.com/clsn/p/7885990.html 安装脚本 #!/bin/bash #clsn #设置解析 注意:网络条件较 ...
- Android项目结构和文件间关联
版本选择 Android 开发 SDK一般选择用最新的SDK版本, 这是Google官方建议的, App能运行的Android版本不是由SDK决定的, 是由每一个项目的minSDK决定的. SDK都是 ...
- MYSQL服务无法启动:InnoDB: .\ibdata1 can't be opened in read-write mode
今天在那做实验倒腾mysql数据库,后来发现服务无法启动,查看日志报错如下: 2015-01-07 17:48:54 9136 [ERROR] InnoDB: .\ibdata1 can't be o ...
- zTree如何实现模糊查找实战
1.说明 最近在研究zTree树控件.过程中涉及到了实现模糊查找结点的功能,特此分享一下. 有关zTree的有关介绍和使用,请访问其官网:zTree -- jQuery 树插件 本文假设你已经比较熟悉 ...
- VS2019 配置 Qt 库
如标题所说,在 VS 编译器中调用 Qt 库 首先安装一个适合 VS 的 Qt 版本 不知道怎么安装的,可以参考:Visual Studio+Qt配置开发环境 Qt 安装之后,需要在 VS 编译器中 ...
- 多线程系列(七) -ThreadLocal 用法及内存泄露分析
一.简介 在 Java web 项目中,想必很多的同学对ThreadLocal这个类并不陌生,它最常用的应用场景就是用来做对象的跨层传递,避免多次传递,打破层次之间的约束. 比如下面这个HttpSer ...
- C++ STL学习
C++ STL学习 目录 C++ STL学习 容器库概览 对可以保存在容器中的元素的限制 容器支持的操作 所有容器都支持的操作或容器成员 迭代器 迭代器的公共操作 迭代器的类型 迭代器的const属性 ...
- 2021-07-01 原生js获取文件数据
原理 手动用js创建一个type为file的DOM元素. 在读取到数据后,清空手动创建的DOM元素.返回得到的Promise类型的文件数据files. const getFilesPromise = ...
- K6 在 Nebula Graph 上的压测实践
背景 对于数据库来说,性能测试是一个非常频繁的事情.优化查询引擎的规则,调整存储引擎的参数等,都需要通过性能测试,查看系统在不同场景下的影响. 即便是同样的代码,同样的参数配置,在不同的机器资源配置, ...