Docker Cache

Docker 镜像在build的过程中,默认会有一套缓存机制。

用自己的语言直白描述 ,能更容易记住呢。

  1. Docker 镜像默认是一层一层的叠加上去。dockerfile中的每一行,对应就是一层。

  2. 每次构建,Docker会比对每一层是否有变化,如果构建命令没有–no-cache=true 参数,默认都会尽量用上缓存。

  3. Docker如何判断这一层是否变化呢。ADD,COPY的层,docker会去比对文件,计算文件的校验和。(校验和中不考虑最后修改和最后访问时间)。其余的层,会去比对字符串。一旦其中一层发生了变化,在此之上的所有层,都不会再用到缓存了。

学了原理,当然要知道怎么优雅的使用呢:

  • 据一个🌰
1
2
3
from centos-alpha
RUN yum update -y && yum install epel -y && yum xxxx
CMD COMMAND

如上,我们在调试dockerfile的时候,常常会多次构建,过程中,可能发现缺少依赖包,变反复修改第二层的RUN指令。

而yum update -y ,却是每次最耗时的指令。如果独立层单独一层,就发现速度飞快了。

  • 再举一个🌰
1
2
3
FROM node-alpha
COPY . /src
RUN cd /src && npm install

如上,第三层中,每一次npm install 会安装package.json中指定的依赖。而如果一个项目在定型后,package.json在变更的频率会非常少,于是聪明的做法是将其改为

1
2
3
4
5
FROM node-alpha
COPY package.json
RUN npm install
COPY . /src
RUN xxxx

这样,在第二层package.json文件不变的情况下,在jenkins 构建编译的时候,可以重复利用第二层。速度也随之加快多了。

好的,那么新的问题来了,docker 镜像在开发测试与生产环境物理距离遥远的企业中,应该如何放置呢。像现在的公司,开发测试等环节都在内部的办公机房里。而生产环境远在aws 俄勒冈。镜像的同步受网络条件制约。对此我们内部出现了多种设想。

  1. 异地编译,生成镜像。同事说在aws环境内,单独完成生产环境的构建编译镜像封装。

  2. 镜像同步,开发测试环境,在稳定后将镜像同步到特定的仓库。改仓库再通过mirror同步到海外的registey。

    我选择了2。原因是容器的目的之一,便是将运行环境也纳入到版本控制中,方案一存在巨大的漏洞,两次构建编译,其中存在不确定因素,所以被彻底否决。

Author: Chandler Kwok
Link: http://yoursite.com/2020/04/16/docker-cache/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.