科学计算Docker镜像的优化

前因

由于工作中大量接触科学计算相关的镜像,也经手打包了数十个镜像,深谙科学背景的科学家们操起python与Dockerfile到底可以结合出什么“美妙”的东西。然而一次数据采集后的调研发现,除了一些不了解docker原理导致的错误之外,问题的根源还可能出现在“人”的身上

科学计算镜像有什么特点

科学计算镜像,顾名思义就是用于一些一次性科学计算的镜像。与常见的服务镜像主要的区别在于,它是一个可能会多次,并发运行的独立计算节点。计算时间从数分钟到数天不等,保证无状态与幂等性

一般来说科学计算镜像都由一些科学领域的计算二进制python库,和一个具体执行计算逻辑的loader构成。

在需要庞大计算量的量化模拟,统计学模拟计算领域。将一个成熟的算法打包在容器内进行稳定的发布,大批量并发执行已经是一个司空见惯的操作了,但是由于算法专业性的影响,很大一部分镜像都是由领域专业的科学家简单学习后打包的,这样就带来了诸多计算机领域中不合理的问题。

问题调研

在进行实际调研之前,我先列出了一些根据平时使用观察与用户反馈的到的信息:

  • 依赖太多二进制与python包导致镜像过大
  • Docker build时间过长导致迭代测试效率低
  • 运行时间过长,出现异常中断后浪费过多计算资源

这些信息看似合理,实际上并没有经过核实,猜想想要转化为实际需求还是需要更多的数据支撑的。为了从事实出发并寻找性价比最高的需求进行解决,我使用Python爬取了Jenkins的所有镜像打包记录,并同时爬取了Bitbucket上触发这些打包的Commit信息。

得到原始数据后,通过commit信息的change_files列表可以简单归因打包镜像的原因,如修改了Dockerfile意味着用户改变了镜像环境,修改了*.py, *.go, *.sh, *.cpp等意味着用户改变了镜像代码or脚本,而修改了Jenkinsfile或配置文件意味着用户修改了CI配置等等。

基于change_files这样的简单分类之后,我们便得到了一个从提交构建原因维度的数据表以及不同原因的venn图等,通过分析这些数据大概可以得出如下的一些结论:

  • 改变Dockerfile的构建平均时长是最长的
  • 无论是构建时间,还是构建次数,修改代码原因占比~50%
  • 一次构建可能掺杂着多个原因,如同时修改代码与Dockerfile,其中修改代码的需求是迫不及待的,单独修改代码的构建占所有包含修改代码的构建的~85%,而修改CI配置的构建往往放在与其他改动一起进行,独立修改占比极低。
  • 用户往往会因为依赖库升级而空commit进行镜像rebuild,这样的情形占用时间约10%

得到了这样的结论之后,我们会发现其实通过数据所获得的结论和猜想还是有较大差异的,虽然镜像打包占用时间较长,但是与其根据猜想直接优化镜像打包速度,远不如直接砍掉用户更新代码的提交次数对时间的影响更大。

解决方案

有了数据支持的结论之后,接下来就是解决方案了,根据科学计算镜像的特点以及数据的支撑,我们可以得到一些高效的解决方案:

将loader.py等镜像内代码与镜像分离,可以直接减少50%的打包时间**

实际上,代码与环境分离并不复杂,使用一个通用的loader,在其中执行下载指定代码文件并执行就可以实现。这样会牺牲一些初始化代码文件的时间,但带来的镜像构建体验的提升是巨大的。在准备好一个成熟的环境之后,Debug代码不需要反复的构建镜像,直接修改代码并上传执行,容器内下载即可快速在容器平台上进行大规模调试。

合理将大型镜像分层

这个思想其实在Dockerfile最佳实践中便可以找到,通过寻找Dockerfile中长期不变的环境依赖,将其汇总固化成基镜像,在基镜像上构建频繁变化的环境,就可以有效减少每次构建中重复构建的时间。

发散思维,换个维度解决问题

以上都是基于计算机背景知识得出的解决方案,看上去行之有效且充满可行性,那么有没有更加好的方案呢?我们可以跳出计算机领域,从人的关系上来分析。

低效镜像之所以出现,是由于算法镜像是由非计算机背景的科学家构建的,如果我们从组织架构上尝试解决问题,直接对科学家们屏蔽容器这一概念,能不能更好的解决问题呢?

通过对之前爬取的数据进行进一步的清洗与整理,我们发现公司的镜像数量总数不多,较为可控,并且根据领域可以集中分类为几大理化原理的算法,镜像的迭代如果抛开代码变动,二进制版本与环境的迭代频率也非常低,平均每个镜像一个月变动一次左右。

那么如果我们接手原有的镜像进行分类合并与优化,向科学家们不断收集新的计算环境需求并以专业技术实现。便可以用较低的人力成本来解决镜像质量低下,效率低下带来的迭代测试缓慢问题与构建成本。提升了稳定性与专业性,同时减少了科学家的学习成本,他们只需要写好loader脚本提交到我们提供的环境中,即可大批量分布式执行,这无疑是一件双赢的方案。

软件工程无论在什么领域中,都是一个划分边界与分层治理的思路,这样的思路同样也可以应用在组织结构,人员分工中。科学家应该focus在算法实现与应用上,而Engineer则应该focus在系统效率,架构优化,成本控制,需求实现等方面。将镜像与科学家完全解耦之后,不仅减少了双方的学习成本与时间成本,Engineer还可以更好的迭代容器技术,想要推进或者换代新的容器平台,任务系统,支持MPI等种种迭代也不会再有镜像分散难以维护的阻力,这也恰恰是康威定律的有力体现。

有些时候问题的根源并不一定是技术问题,遇到一个怎么都不能优雅解决的问题,也许是组织架构限制了你的思路,重构技术架构时不妨多思考一下组织结构和人员分工是否出现了问题。


“设计系统的架构受制于产生这些设计的组织的沟通结构。” ——M. Conway

Built with Hugo
Theme Stack designed by Jimmy