1、Docker Kubernetes容器云平台性能调优详解 Docker+Kubernetes 容器云平台性能调优详解 2 容器引擎docker的性能瓶颈和调优docker容器承载于容器引擎之上,对于开发者和容器云平台管理员来说,统一标准的包格式简化了二者的工作量,而容器格式让使用者加快速迭代应用程序的版本并进行管理。开发、测试、部署的时间也得到降低,这是容器引擎的最核心功能。因此,容器引擎的性能优势和瓶颈基于容器的轻量化和启动速度来分析,主要涉及的组件为docker容器和镜像仓库。在对容器引擎的性能瓶颈分析方面,基于以下几点来考虑,(1)容器引擎的稳定性,在容器云平台架构分析和容器云平台可靠性
2、设计中已体现,在此不再阐述。(2)镜像仓库的瘦身和启动速度,在实际使用过程中,由于经常会下载应用程序所对应的镜像运行库,使得开发的时间在增加,而docker hub的速度拖慢了部署时间,造成部署时间的偏差。而docker hub的不稳定因素也会导致部署时间的不确定性,另docker镜像的大小存在超大的行为,容器更新的时间也将不受控制。基于以上的因素,本小节基于docker容器引擎的性能瓶颈和优化集中于以下三点,(1)镜像的部署时间,(2)镜像的编译时间,(3)镜像的大小。2.1 镜像的部署时间在使用容器云平台过程中,存在一种情况,构建的docker容器尺寸变得越来越大,在现有的docker宿主
3、机中运行的容器是可以避免此类问题。docker会合理利用docker镜像层,这些镜像层会随着所部署的应用的增长而随之创建。但是有一种场景,当我们准备水平扩展应用的时候,这些应用所承载的docker容器会越来越多的需要docker宿主机进行支撑,因此每一个新的docker宿主机需要下载我们所需要的镜像层。本小节会举例复现一个大的docker应用如何影响docker宿主机上的部署时间。首先我们来复现这个docker应用的场景问题,如下所示。(1)编写一个dockerfile来创建一个大docker镜像from debian:iessierun dd if=/dev/urandom of=/larg
4、efile bs=1024 count=524288(2)编译dockerfile ,并对hubuser/largeapp打标签,具体命令如下dockerhost$ docker build t hubuser/largeapp(3)检查这个docker容器的尺寸,从执行后的输出看出,这个docker容器占用了接近700m的空间,具体命令如下dockerhost$ docker images(4)通过time命令来查看这个docker镜像上传到docker hub和从docker hub拉取的时间,具体命令如下docker $ time docker push hubuser/largeapp
5、docker $ time docker pull hubuser/largeapp从二者执行的时间上可以看出,当执行docker push命令时,上传镜像到docker hub花费了大量的时间,同样的在部署的过程中,docker pull拉取我们新建的镜像到生产环境的docker宿主机上同样花费了很长的时间。所以上传和下载的时间取决于docker宿主机到docker hub之间的网络环境和网络带宽,如果docker hub出现异常,对部署新的docker容器存在很大的时效调整,有可能会引发部署失败。在容器云平台架构的介绍中,我们为了利用docker的快速分发和便捷部署的特性,上传和下载镜像的
6、稳定性是我们需要解决的需求。在本章中,我们通过docker容器镜像组件registry来解决这个性能瓶颈,docker registry用于存储和分发docker镜像,无需依赖公共的docker hub服务,具体步骤如下。(1)部署docker registry私有仓库,具体架构不在本小节中阐述。(2)确认docker镜像部署的速度是否已经提升,首先,将先前创建的镜像打上标签,用于推送至本地私有仓库。(3)实测docker镜像到本地仓库的上传的速率,实测结果为docker hub的十倍。(4)实测docker镜像到本地仓库的上传的速率,实测结果为docker hub的三十倍。2.2 镜像的编译
7、时间docker镜像是容器云平台的重要组成构建,也是性能瓶颈的优先考虑的点,因此简化docker文件和加速容器技术至关重要,可以让我们更快速的迭代应用开发。一旦编译docker镜像所需要的时间存在过长或不受控制,那么使用容器云平台的优势将打很大的折扣。本小节中,我们将以几个维度来分析构建docker镜像中耗时过长的问题,来优化此类问题的瓶颈。(1)通过本地化仓库来提升速度在提升镜像部署时间的段落中,我们已经采用了本地化仓库的方式,避免从docker hub中上传和下载镜像,速度有很大的提升,在构建镜像的过程中,同样的需要花费较多的时间在获取上游镜像的过程中。当我们使用一台新的docker宿主机
8、,通过docker hub进行下载镜像进行编译,整体耗时将会显著的增加,因此通过本地化仓库也能缩短镜像编译的整体耗时,通常运用传递-registry-mirror的参数的方式给予docker的守护进程,用来配置docker宿主机寻找本地的镜像仓库,大概步骤如下。在任意一台docker宿主机中,通过更新或创建一个systemd的插件文件来配置docker守护进程,文件核心配置参数为execstart=/usr/bin/docker daemon h df:/-registry-mirror=http:/dockerhost:5000。接着上一步骤,重启systemd来加载socker servi
9、ce的新配置文件,重启新配置的systemd单元来重启docker守护进程,两个命令如下。dockerhost$ systemctl daemon-reloaddockerhost$ systemctl restartdocker-service最后运行作为进行的registry的docker容器,确保该进行registry正常工作。下面开始验证二者的速度区别,先编译一个简单的dockerfile,通过docker hub进行下载上游镜像,可以发现编译镜像的大部分时间在下载进行部分,结果如下。移除该进行以及上游的依赖进行,重新进行编译,结果如下(2)复用镜像层来提升整体的编译速度根据容器云平台
10、架构一章节中得知,docker镜像是由一系列的层合并而成,所使用的是一个单一的镜像联合文件系统。当我们在构建docker镜像的时候,docker会检查dockerfile中正在处理的指令,判断缓存中是否存在可以复用的镜像,而不是一味的重复创建同一个镜像,因此复用镜像层也是提升镜像编译能力之一,提高创建docker镜像的速度。(3)减小构建上下文的大小在容器云自动化集成的过程中,持续集成是核心的环节,基于代码的版本控制中,通过dickerfile来定义代码的基本属性。某种程度上,以git为例,当项目代码的git文件占有太多磁盘空间的时候,可能存在代码提交过多,或者代码引用太多的情况,具体方法如下
11、。dockerhost$ du hsc .git当编译docker应用时,如果git文件占用太多磁盘空间,造成代码空间较大的情况下,编译docker进行的时间也会非常大,间接造成整体编译的时间拉长,具体查看方法如下。dockerhost$ time docker build t hubuser/largecontext通过这个案例我们来回溯,docker客户端上传了整个项目git文件夹,而仅仅是因为它在镜像的编译路径下,这种情况针对于开发能力不是很强的同学来说,轻易会造成这种局面,所以在编译docker镜像的过程中,docker守护经常需要花费较多的时间来接收相关的信息。由于很多文件对于编译过
12、程是无用的,尤其是在编译该应用程序的docker镜像阶段,所以这些文件对于在生产环境中运行的应用程序也是无用的。所以我们在编译docker镜像之前可以设定忽略这些无用文件,也就是通过减少上下文的大小来达到优化编译过程的性能,操作方法如下。在dockerfile所在目录下创建一个.dockerignore文件,文件中包括.git的内容。重新编译docker镜像,具体命令为dockerhost$ time docker build t hubuser/largecontext,输出如下通过减少构建上下文的大小,达到的效果是提升业务代码编译的时间大约500倍,同时还大大减少了编译内容的大小。(4)使
13、用缓存代理的方式除了构建上下文庞大以外,还有一个因素会导致编译docker进行环境,那就是下载系统依赖库指令。举一个简单的例子,一个基于centos系统的docker镜像需要从公共资源库中下载依赖包,编译过程中,yuminstall指令运行时间的长短取决于所需要下载的依赖包的大小。因此降低依赖包的下载消耗时间对于减少编译时间也非常重要,所以使用缓存代理的方式能够提高docker镜像编译工作的效率。2.3 镜像的大小在容器云平台的使用过程中,随着对docker应用的持续使用,如果不加注意,那么镜像的尺寸会变得越来越大。在使用docker容器期间,应用承载的docker镜像尺寸如果达到gb规模,会
14、导致编译和部署docker应用的时间变得不受控制。因此我们需要减少需要部署的镜像尺寸,会抵消容器云平台的优点,失去快速迭代开发和部署应用的特点。本小节的优化点也将减少容器云平台对于容器编译的时间。(1)链式指令docker镜像尺寸变大的一个重要原因是很多对编译或者运行无关的质量被引入到镜像中,举一个常见的案例,打包元数据和缓存过程中,在安装完编译和运行相关的依赖包以后,下载的文件就没有存留的必要,类似于clean的指令可以在很多仓库的dockerfile中发现,用于清理这些无效的文件。from centos:jessierun echo cenos http:/xx.xx.xx.orgjess
15、ie-backports main /etc/apt/sources.list.d/jessie-backports.listrun yum updaterun yum install no-install-recommends install y gcc*run rm rfv /var/lib/apt/lists/*在这个案例之中,一个docker镜像的尺寸是每一个独立镜像层的尺寸总和,也就是联合文件系统的工作机制,因此clear步骤并没有真正删除相应的硬盘空间,可以通过以下命令来查看。dockerhost$ docker build t fakecleandockerhost$ docke
16、r history fakeclean由此可见,本案例中并不存在为“负”的镜像层尺寸。在dockerfile中每一个指令要么保持镜像尺寸的不变,要么增加尺寸,同时每一步骤还有可能会引入新的元数据的信息,将会导致整体的尺寸增大。为了降低整个镜像的尺寸,清楚操作应该在同一个镜像层中来执行。解决方案是将先前的多条指令合并为一条,当docker使用/bin/sh来执行每一条指令,我们可以使用bourne shell提供的&操作符来实现链接,通过减少独立层的尺寸来减少整个镜像的尺寸。(2)编译镜像和部署镜像的分离docker镜像中还一种无用文件也会造成整个镜像尺寸的变大,这类无用文件是编译过程中的依赖文
17、件,例如在编译应用程序过程中所依赖的源代码库。一般情况下,编译文件和头文件的存在只是在程序编译过程中起到相应的作用,一旦编译完成,这类文件就不再使用,因此需要对编译镜像和部署镜像进行分离。使用进行构建 Dockerfile可以优化分层缓存,以减少图像层的拉入和推送时间。在以下示例中,使用此方法减小了更新大小,因为分成几层是基于更改频率。重新定义一下,将缓存所有未更改的层,如图所示:让我们来看一个例子。该映像的层很小,但是在进行映像构建时,始终会更新35M层:但是此映像比上面的映像具有更多的层,5M层是唯一更新的层。缓存其他未更改的层:在对构建过程进行故障排除时,应该检查构建日志,因为Kuber
18、netes只能检测到构建容器是否成功完成。如果在应用程序容器启动时使用连接池的DB服务器出现性能问题或达到最大连接数,则应用程序容器初始化可能比预期的延迟得更多。因此,如果您的应用程序具有外部依赖关系,则还应检查它们是否运行良好。而如果Readiness Probes和Liveness Probes配置您的应用程序pod,你应该设置initialDelaySeconds和periodSeconds足够大的为您的应用pod初始化。如果 initialDelaySeconds和periodSeconds 太短而无法检查应用程序状态,则您的应用程序将反复重启,并可能导致延迟或部署应用程序pod失败。
copyright@ 2008-2022 冰豆网网站版权所有
经营许可证编号:鄂ICP备2022015515号-1