简介
参考文章:https://mp.weixin.qq.com/s/HSD5PARjWba0cEUAyS-Ntw
多阶段构建
多阶段构建的含义:
Dockerfile中每一条语句都会在原来的镜像中新增一个对应的层, 并且每build一层就会cache下来。所以我们若用 && 来合并RUN语句(或COPY语句),便无法充分利用这一层cache。多阶段构建可以部分解决这个问题:
您可以在Dockerfile中使用多个FROM语句。每个FROM指令可以使用不同的基础,并且每个指令都开始一个新的构建。您可以选择性地将工件从一个阶段复制到另一个阶段,从而在最终image中只留下您想要的内容。
在那些讲述如何减小docker image size的文章中,多阶段构建一直是一个不可或缺的内容。但是要真正理解什么时候该做这个并不容易,看几个例子:
- https://www.cnblogs.com/shanyou/p/12088659.html 需要先用sdk镜像编译处.dll文件,然后再运行
dotnet xxx.dll
- http://dockone.io/article/8179 官方的例子则是需要golang的tookit来编译go文件,然后运行。
可以看到这两个例子的共同点是第一个阶段利用复杂镜像做了编译等工作,并生成了下一阶段所需的文件,下一阶段用一个小型镜像作为基础镜像,将上一阶段的文件拷贝过来在此运行。
所以,如果你是想用docker创建一个含有各种依赖的python运行环境,而非跑一个程序在上面,那么多阶段构建是无效的。
基础镜像的选择
说到最小的镜像,alpine一定是立刻浮现在脑海中的。然而alpine更多的是作为一个轻型的运行linux环境,没有bash而是sh,没有apt-get or yum而是apk,并且用的是musl libc。
拿nvidia/cuda为例,到dockerhub上查看其tag:
- base: 基于CUDA,包含最精简的依赖,用于部署预编译的CUDA应用,需要手工安装所需的其他依赖。
- runtime: 基于base,添加了CUDA toolkit共享的库
- devel: 基于runtime,添加了编译工具链,调试工具,头文件,静态库。用于从源码编译CUDA应用
apt-get 包管理器
使用apt-get包管理器来下载时,有一些通用的技巧:
1.更换源为