前言
破事水系列。回刚刚群有疑惑详解。
相同点
Dockerfile中的COPY和ADD命令都是构建命令,在构建镜像的过程中执行。大部分场景没有区别,只有在考虑两者区别的时候才需要特地正确的选择,如果不需要使用ADD命令的特性,笔者建议优先使用COPY。
笔者专门构架了一个专用测试的dockerfile,测试设备为rock pi 4b 2g,使用M.2接口上的傲腾16G进行测试,ADD与COPY各自执行1000次,插入单文件到镜像,前者需要的时间多好几倍,由于傲腾4K性能,特别是操作延迟显著优于普通的使用闪存作为存储介质的固态硬盘,此时硬盘模式的奥腾仍然比较空闲,因此可以认为磁盘性能在这个测试中不存在瓶颈。
具体目前懒得研究源码、阅读文档,也懒得找大佬们的解析,随意猜测是由于COPY命令只从当前能直接访问的文件系统路径提取文件,且不对文件进行解析,所以速度上比较快。至于日常大多数场景构建瓶颈在硬盘,因此实际场景上两个命令不存在太大的区别。
另外提醒,文件添加过程基本上不存在失败的问题,考虑镜像体积,尽可能一次覆盖文件,减少容器层级。
什么时候用ADD
如果源文件是tar这样的归档文件或者压缩包,在构建过程中使用ADD指令,文件会被直接解压。另外ADD可以从类似http\https这类的外部地址获取文件存入,如果有这个需求,更建议先保存在本地,校验文件正常再存入,避免反复构建多次传输,以及互联网传输过程中网络异常,导致文件不完整不正确。
一些小技巧
普通bash能用的很多方式都是可以正常在构建过程中发挥作用的,例如可以执行类似这样的命令,一次就增加全部相似路径的文件。
COPY /data*/cache*/disk_cache*.bdf /data
类似普通文件管理操作,在构建过程中,Dockerfile以 \ 结尾判断目标性质为文件夹或者文件。所以复制过程中也可以直接重命名,例如
FROM scratch
COPY xxxxxxx.bin /run
CMD ["/run"]
这里提到了FROM scratch,那么什么是scratch?
这是一个空的镜像,使用这个之后,将第二步作为镜像的基础层。其实许多二进制文件是静态编译的,对系统的glibc版本这些没有什么要求,仅添加二进制文件本身以及可能需要的配置文件,其他的资源文件这类,就可以直接运行了。
虽然静态编译的二进制文件本身也没什么太大的必要搞成docker镜像。