关于容器:Serverless-场景下-Pod-创建效率优化

1次阅读

共计 5906 个字符,预计需要花费 15 分钟才能阅读完成。

作者 | 张翼飞  阿里云技术专家
起源 | 阿里巴巴云原生公众号

导读:家喻户晓,Kubernetes 是云原生畛域的基石,作为容器编排的基础设施,被广泛应用在 Serverless 畛域。弹性能力是 Serverless 畛域的外围竞争力,本次分享将重点介绍基于 Kubernetes 的 Serverless 服务中,如何优化 Pod 创立效率,晋升弹性效率。

Serverless 计算简介

 
在进入主题之前,先简略回顾下 Serverless 计算的定义。

从维基百科能够理解到,Serverless 计算是云计算的一种状态,由云厂商治理服务器,向用户动态分配机器资源,基于理论应用的资源量计费。

用户构建和运行服务时,不必思考服务器,升高了用户治理服务器的累赘。在业务高峰期通过平台的弹性能力主动扩容实例,在业务低峰期主动缩容实例,升高资源老本。

Serverless 计算平台

 
下述是以后常见的 Serverless 计算产品的架构。
 

整个产品架构通常会有管控立体和数据立体两层,管控立体服务开发者,治理利用生命周期,满足开发者对利用治理的需要,数据立体服务利用的拜访方,如开发者业务的用户,满足利用的流量治理和拜访诉求。

管控立体通常采纳 Kubernetes 做资源管理和调度,master 通常是 3 节点,满足对高可用的需要,节点通过内网 SLB 拜访 K8s master。

在节点层面,通常会有两种类型的节点:

  • 一种是运行 kubelet 的节点,如裸金属服务器、虚拟机等,这类节点上会运行平安容器作为 Pod 运行时,每个 Pod 领有独立的 kernel,升高共享宿主机 kernel 带来的平安危险。同时会通过云产品 VPC 网络或其余网络技术,在数据链路层隔离租户的网络拜访。通过 平安容器 + 二层网络隔离,单个节点上能够提供牢靠的多租运行环境。
  • 还有一种是虚构节点,通过 VirtualKubelet 连接 K8s 和弹性实例。弹性实例是云产品中相似虚拟机的一种轻量资源状态,提供有限资源池的容器组服务,该容器组的概念对应 K8s 中的 Pod 概念。AWS 提供有 Fargate 弹性实例,阿里云提供有 ECI 弹性实例。

Serverless 产品会提供基于 K8s 的 PaaS 层,负责向开发者提供部署、开发等相干的服务,屏蔽 K8s 相干的概念,升高开发者开发、运维利用的老本。

在数据立体,用户可通过 SLB 实现对利用实例的拜访。PaaS 层也通常会在该立体提供诸如流量灰度、A/B 测试等流量治理服务,满足开发者对流量治理的需要。

弹性能力是 Serverless 计算平台的外围竞争力,须要满足开发者对 Pod 规模 的诉求,提供相似有限资源池的能力,同时还要满足创立 Pod 效率的诉求,及时响应申请。

Pod 规模可通过减少 IaaS 层资源来满足,接下来重点介绍晋升 Pod 创立效率的技术。

Pod 创立相干场景

 
先理解下 Pod 创立相干的场景,这样能够更无效通过技术满足业务诉求。

业务中会有两种场景波及到 Pod 创立:

  • 第一种是创立利用,这个过程会先通过调度,决策最适宜 Pod 的节点,而后在节点上创立 Pod。
  • 第二种是降级利用,在这个过程中,通常是一直进行 创立新 Pod 和 销毁旧 Pod。

Serverless 服务中,开发者关怀的重点在于利用的生命周期,尤其是创立和降级阶段,Pod 创立效率会影响这两个阶段的整体耗时,进而影响开发者的体验。面对突发流量时,创立效率的高下会对开发者服务的响应速度产生重要影响,严重者会使开发者的业务受损。

面对上述业务场景,接下来重点剖析如何晋升 Pod 创立效率。

创立 Pod 流程

 
整体剖析下 Pod 创立的阶段,依照影响 Pod 创立效率的优先级来顺次解决。

这是简化后的创立 Pod 流程:

当有 Pod 创立申请时,先进行调度,为 Pod 选取最合适的节点。在节点上,先进行拉取镜像的操作,镜像在本地筹备好后,再进行创立容器组的操作。在拉取镜像阶段,又顺次分为下载镜像和解压镜像两个步骤。

咱们针对两种类型的镜像进行了测试,后果如下:

从测试后果可看到,解压镜像耗时在整个拉取镜像过程中的占比不容忽视,对于解压前 248MB 左右的 golang:1.10 镜像,解压镜像耗时居然占到了拉取镜像耗时的 77.02%,对于节解压前 506MB 左右的 hadoop namenode 镜像,解压镜像耗时和下载镜像耗时各占 40% 和 60% 左右,即对于拉取镜像过程的总耗时也不容忽视。

接下来就别离针对上述过程的不同节点进行优化解决,别离从上述整个流程、解压镜像、下载镜像等方面进行探讨。
 

拉取镜像效率晋升

 

镜像预热

 
能够疾速想到的办法是进行镜像预热,在 Pod 调度到节点前事后在节点上筹备好镜像,将拉取镜像从创立 Pod 的主链路中移除,如下图:

能够在调度前进行全局预热,在所有节点上行提前拉取镜像。也能够在调度过程中进行预热,在确定调度到的
节点后,在指标节点上拉取镜像。

两种形式无可非议,可依据集群理论状况进行抉择。

社区里 OpenKruise 我的项目行将推出镜像预热服务,能够关注下。下述是该服务的应用形式:

通过 ImagePullJob CRD 下发镜像预热工作,指定指标镜像和节点,可配置拉取的并发度、Job 解决的超时工夫以及 Job Object 主动回收的工夫。若是公有镜像,可指定拉取镜像时的 secret 配置。ImagePullJob 的 Events 会提镜工作的状态信息,可思考适当增大 Job Object 主动回收的工夫,便于通过 ImagePullJob Events 查看工作的解决状态。
 

晋升解压效率

 
从方才看到的拉取镜像的数据来看,解压镜像耗时会占拉取镜像总耗时很大的比例,测试的例子最大占比到了 77%,所以须要思考如何晋升解压效率。

先回顾下 docker pull 的技术细节:

在 docker pull 时,整体会进行两个阶段:

  • 并行下载 image 层
  • 拆解 image 层

在解压 image 层时,默认采纳的 gunzip。

再简略理解下 docker push 的过程:

  • 先对 image 层进行打包操作,这个过程中会通过 gzip 进行压缩。
  • 而后并行上传。

gzip/gunzip 是单线程的压缩 / 解压工具,可思考采纳 pigz/unpigz 进行多线程的压缩 / 解压,充分利用多核优势。

containerd 从 1.2 版本开始反对 pigz,节点上装置 unpigz 工具后,会优先用其进行解压。通过这种办法,可通过节点多核能力晋升镜像解压效率。

这个过程也须要关注 下载 / 上传 的并发度问题,docker daemon 提供了两个参数来管制并发度,管制并行处理的镜像层的数量,–max-concurrent-downloads 和 –max-concurrent-uploads。默认状况下,下载的并发度是 3,上传的并发度是 5,可依据测试后果调整到适合的值。

应用 unpigz 后的解压镜像效率:

在雷同环境下,golang:1.10 镜像解压效率晋升了 35.88%,hadoop namenode 镜像解压效率晋升了 16.41%。

非压缩镜像

 
通常内网的带宽足够大,是否有可能省去 解压缩 / 压缩 的逻辑,将拉取镜像的耗时集中在下载镜像方面?即适量增大下载耗时,缩短解压耗时。

再回顾下 docker pull/push 的流程,在 unpack/pack 阶段,能够思考将 gunzip 和 gzip 的逻辑去掉:
 

对于 docker 镜像,若 docker push 时的镜像是非压缩的,则 docker pull 时是无需进行解压缩操作,故要实现上述指标,就须要在 docker push 时去掉压缩逻辑。

docker daemon 临时不反对上述操作,咱们对 docker 进行了一番批改,在上传镜像时不进行压缩操作,测试后果如下:

这里重点关注解压镜像耗时,可看到 golang:1.10 镜像解压效率晋升了 50% 左右,hadoop namenode 镜像解压效率替身挂了 28% 左右。在拉取镜像总耗时方面,该计划有肯定的成果。
 

镜像散发

 
小规模集群中,晋升拉取镜像效率的重点须要放在晋升解压效率方面,下载镜像通常不是瓶颈。而在大规模集群中,因为节点数众多,核心式的 Image Registry 的带宽和稳定性也会影响拉取镜像的效率,如下图:

下载镜像的压力集中在核心式的 Image Registry 上。

这里介绍一种基于 P2P 的镜像散发零碎来解决上述问题,以 CNCF 的 DragonFly 我的项目为例:
 

这里有几个外围组件:

ClusterManager

它实质上是一个核心式的 SuperNode,在 P2P 网络中作为 tracker 和 scheduler 协调节点的下载工作。同时它还是一个缓存服务,缓存从 Image Registry 中下载的镜像,升高节点的减少对 Image Registry 带来的压力。

Dfget

它既是节点上下载镜像的客户端,同时又充当向其余节点提供数据的能力,能够将本地已有的镜像数据按需提供给其余节点。

Dfdaemon

在每个节点上有个 Dfdaemon 组件,它实质上是一个 proxy,对 docker daemon 的拉取镜像的申请实现通明代理服务,应用 Dfget 下载镜像。

通过 P2P 网络,核心式的 Image Registry 数据被缓存到 ClusterManager 中,ClusterManager 协调节点对镜像的下载需要,将下载镜像的压力摊派到集群节点上,集群节点既是镜像数据的拉取方,又是镜像数据的提供方,充分利用内网带宽的能力进行镜像散发。

按需加载镜像

 
除了上述介绍到的办法,是否还有其余优化办法?

以后节点上创立容器时,是须要先把镜像全副数据拉取到本地,而后能力启动容器。再思考下启动虚拟机的过程,即便是几百 GB 的虚拟机镜像,启动虚拟机也通常是在秒级别,简直感触不到虚拟机镜像大小带来的影响。

那么容器畛域是否也能够用到相似的技术?

再看一篇发表在 usenix 上的题为《Slacker: Fast Distribution with Lazy Docker Containers》的 paper 形容:

Our analysis shows that pulling packages accounts for 76% of container start time, but only 6.4% of  
that data is read.

该 paper 剖析,在镜像启动耗时中,拉取镜像占比 76%,然而在启动时,仅有 6.4% 的数据被应用到,即镜像启动时须要的镜像数据量很少,须要思考在镜像启动阶段按需加载镜像,扭转对镜像的应用形式。

对于「Image 所有 layers 下载完后能力启动镜像」,须要改为启动容器时按需加载镜像,相似启动虚拟机的形式,仅对启动阶段须要的数据进行网络传输。

但以后镜像格局通常是 tar.gz 或 tar,而 tar 文件没有索引,gzip 文件不能从任意地位读取数据,这样就不能满足按需拉取时拉取指定文件的需要,镜像格局须要改为可索引的文件格式。

Google 提出了一种新的镜像格局,stargz,全称是 seeable tar.gz。它兼容以后的镜像格局,但提供了文件索引,可从指定地位读取数据。

传统的 .tar.gz 文件是这样生成的: Gzip(TarF(file1) + TarF(file2) + TarF(file3) + TarFooter))。别离对每个文件进行打包,而后对文件组进行压缩操作。

stargz 文件做了这样的翻新:Gzip(TarF(file1)) + Gzip(TarF(file2)) + Gzip(TarF(file3_chunk1)) + Gzip(F(file3_chunk2)) + Gzip(F(index of earlier files in magic file), TarFooter)。针对每个文件进行打包和压缩操作,同时造成一个索引文件,和 TarFooter 一起进行压缩。

这样就能够通过索引文件疾速定位要拉取的文件的地位,而后从指定地位拉取文件。

而后在 containerd 拉取镜像环节,对 containerd 提供一种 remote snapshotter,在创立容器 rootfs 层时,不通过先下载镜像层再构建的形式,而是间接 mount 近程存储层,如下图所示:

要实现这样的能力,一方面须要批改 containerd 以后的逻辑,在 filter 阶段辨认近程镜像层,对于这样的镜像层不进行 download 操作,一方面须要实现一个 remote snapshotter,来反对对于近程层的治理。

当 containerd 通过 remote snapshotter 创立容器时,省去了拉取镜像的阶段,对于启动过程中须要的文件,可对 stargz 格局的镜像数据发动 HTTP Range GET 申请,拉取指标数据。

阿里云实现了名为 DADI 的加速器,相似上述的思维,目前利用在了阿里云容器服务,实现了 3.01s 启动  
10000 个容器,完满杜绝了冷启动的漫长期待。感兴趣的读者也参考该文章:https://developer.aliyun.com/article/742103
 

原地降级

 
上述都是针对创立 Pod 过程提供的技术计划,对于降级场景,在现有的技术下,是否有效率晋升的可能性?是否能够达到下述成果,即免去创立 Pod 的过程,实现 Pod 原地降级?

在降级场景中,占比拟大的场景是仅降级镜像。针对这种场景,可应用 K8s 本身的 patch 能力。通过 patch image,Pod 不会重建,仅指标 container 重建,这样就不必残缺通过 调度 + 新建 Pod 流程,仅对须要降级的容器进行原地降级。

在原地降级过程中,借助 K8s readinessGates 能力,能够管制 Pod 优雅下线,由 K8s Endpoint Controller 被动摘除行将降级的 Pod,在 Pod 原地降级后退出降级后的 Pod,实现降级过程中流量无损。

OpenKruise 我的项目中的 CloneSet Controller 提供了上述能力:

开发者应用 CloneSet 申明利用,用法相似 Deployment。在降级镜像时,由 CloneSet Controller 负责执行 patch 操作,同时确保降级过程中业务流量无损。

小结

 
从业务场景登程,咱们理解了晋升 Pod 创立效率带来收益的场景。而后通过剖析 Pod 创立的流程,针对不同的阶段做相应的优化,对症下药。

通过这样的剖析解决流程,使得能够无效通过技术满足业务需要。

作者简介

张翼飞,就任于阿里云容器服务团队,次要专一 Serverless 畛域的产品研发。

Serverless 对春联领双肩包流动开始啦!云开发平台与函数计算联合推出新年流动,极速迁徙和部署春联神器等利用,领阿里云定制牛年背包和代金券。新老用户均可加入!加入链接:https://workbench.aliyun.com/activities/niu

正文完
 0