0%

每周更新 weekly update (5/52)

2020年第五周

使用Docker的一些感悟

在进入实验室之后,使用实验室的server来跑任务是一件很让人心情愉快的事情,尤其是我们实验室的服务器有多块GPU,目前使用这个server的人只有我和另一个同学,简直不能再爽了。

但是有个头痛的问题,那就是大家在用server时会安装各种软件(不同版本的CUDA或者是ROS),而不同软件版本的API可能会互相干扰。 那么如何在大家共用的基础上,把实验环境给独立开来,是一个亟需解决的问题吧。我们实验室使用的是最简单的方法--用容器Docker去独立开发环境。

在这里简单分享几点,稍微总结一下这段时间使用Docker的感悟:

1. 强烈建议新手使用别人成熟的容器作为Base层

毫无疑问,很多时候我们会用到CUDA来加速深度学习库,如PyTorch。之前一个Ph.D.同事在我们实验室里曾经分享过一个Dockerfile,里面基本上就是把CUDA从NVidia显卡开始安装起,十分繁杂,可维护性相当的低(并不是说不能用,只是在有很好的官方cuda image下,没啥必要这么做)。

考虑到这个原因,在上个寒假要开启一个新的项目之前,我就决定从零开始写了一份自己的Dockerfile,彻底解决这个问题。 在对比了各种实现方式,我觉得将CUDA官方给的docker imag是一个极好的选择,也算是一个相当优雅的方式。

首先你再也不用担心驱动问题或系统环境变量没设置调用不了显卡;而且在实际用过之后,个人感觉这个base image是比较纯净的,基本上不太会影响到你后面自己的开发需求;最后就是它有丰富的选择,满足不同的需要,包括系统版本、CuDNN版本以及具体使用场景而区分的几个不同的”flavors“:

CUDA images come in three flavors and are available through the NVIDIA public hub repository.

  • base: starting from CUDA 9.0, contains the bare minimum (libcudart) to deploy a pre-built CUDA application. Use this image if you want to manually select which CUDA packages you want to install.
  • runtime: extends the base image by adding all the shared libraries from the CUDA toolkit. Use this image if you have a pre-built application using multiple CUDA libraries.
  • devel: extends the runtime image by adding the compiler toolchain, the debugging tools, the headers and the static libraries. Use this image to compile a CUDA application from sources.

这里主要区别是runtime和devel版本。前者是可以现成跑需要显卡相关的应用,不再需要有关的CUDA开发环境;而我选择了devel版本,因为后续需要去从源码编译一些CUDA相关的代码,如libTorch。

2. 一定要包含安装包的版本号

很多时候,我们会去clone一些github的repo,用来源码编译之类的。

我们之前就是这样去安装PyTorch。但后来有一天重新编译镜像之后,我发现原来的PyTorch代码编译报错了,让我苦恼了好一会儿。经过多番debug调试,我后来发现是因为PyTorch的版本更新(从1.1到1.2),使得C++的前端接口发生了改变,导入网络模型的API不同了,

这就有点尴尬了,因为在跑代码出bug的时候根本没有相关的报错信息,这种因为版本不同的环境Dependency而出的错,在少数情况可能是无解。正因此,我们在写Dockerfile的时候,一定要写下相应的版本号,为了今后的代码鲁棒性打下基础吧。

3. 一个完整动作构建一层缓存

在编译镜像的时候,会产生许多中间层的cache方便rebuild。然而过多的RUN、ADD、COPY指令会使得Dockerfile非常杂乱,而且中间产生许多cache占用系统空间,随便一下就是10+GB。

理想的做法就是把多个RUN指令合并,尽可能地用一个RUN命令去完成一整套动作,比如编译PyTorch,可以就是从git clone指令到最后的python setup.py install一气呵成。这样减少了许多中间layers.(很显然,如果想这么做,你必须能够确保一次写对,否则一有错误,就要花多倍的时间去多次执行这行指令)

更多需要怎么写Dockerfile, 可以参考这篇文章Best practices for writing Dockerfiles。 而docker常用指令(command)这类东西,相对来说比较简单,别人总结也挺多,也就不再赘述.

科比,传奇永在

Kobe

最后,让我们一起记住这个传奇!