Docker 镜像的缓存

2018-08-18 17:42:47 +08:00
 wangxiaoaer

docker 镜像每个 RUN 命令都会创建一层缓存:

比如

1 RUN apt-get xx

2 mkdir xx && cd xx

3 RUN make xx

上面的第一行命令装了一大堆依赖,大概 500 多 M,每次 build 都比较耗时。

这个命令会不会创建一个缓存?如果可以,并且如果这行命令一直不变的话,修改后面命令,重新构建的时候会不会利用这个缓存?还是重新 apt 安装?因为根据我自己的测试,好像并没有用到缓存,具体是什么情况?

换句话说 docker 的缓存有么有直接跟 dockerfile 中的命令关联起来?能不能跨 dockefile 利用呢?

4567 次点击
所在节点    问与答
30 条回复
qsnow6
2018-08-18 18:37:21 +08:00
可以
KeatingSmith
2018-08-18 19:08:59 +08:00
每层镜像会有唯一的 Hash 码,每一层镜像,都会在本地存在缓存。

假如我现在构建 C 容器,C 依赖 B。第一次在本地构建的时候,会先构建 B,再构建 C。假如还需要构建 D,D 也依赖于 B,因为之前已经构建 B 了,所以只系要直接构建 D 就行了。

如果你换台机器,那么需要全部重新构建。
KeatingSmith
2018-08-18 19:13:40 +08:00
如果你在 Dockerfile 中使用每一层的命令,因为每一次 apt 不能保证对镜像都有相同的修改,导致 hash 不同。
presoul
2018-08-18 19:17:31 +08:00
cd xx 没用 不是 shell
willxiang
2018-08-18 19:19:27 +08:00
会的,2-3L 解释的很清楚了
只要你生成的镜像不立马删除,重新 run build 时会直接使用之前 run 过的缓存
momocraft
2018-08-18 19:21:23 +08:00
"缓存"是个结果, 如果某一层可以复用以前的中间层, 才会跳过执行来直接使用上次的. 你不讲具体怎么测试鬼知道什么具体情况.
shiny
2018-08-18 19:21:56 +08:00
我看到很多 Dockerfile 会尽量把构建合并到一条指令里,是不是因为这样生成出来的镜像尺寸比较小?
whileFalse
2018-08-18 19:24:11 +08:00
关键是你在哪一步 add 你的代码的。如果在 apt-get 之前,什么缓存也没用。
yuanfnadi
2018-08-18 19:33:31 +08:00
@shiny 对的 是因为一句命令就是一层。
你上一句话加了一个文件 下一句把文件删了。不会缩小镜像的体积,因为不是一层。


另外 docker 支持多步构建,可以在镜像 a 把代码 build 好,然后把二进制放到一个超级小的镜像。最终结果会非常小。
Bardon
2018-08-18 19:47:31 +08:00
@yuanfnadi 写到一句,并不会使得最终镜像变小,而是层少了,层的数目会影响到容器执行后的 IO 性能。
wangxiaoaer
2018-08-18 19:59:46 +08:00
@KeatingSmith #2 你说的这个依赖是通过 from 这种方式吗?里面的 A B C D 是指一个单独的镜像还是 dockerfile 里面的一条命令?
wangxiaoaer
2018-08-18 20:25:58 +08:00
@momocraft #6 看 append
DiamondYuan
2018-08-18 21:16:00 +08:00
@Bardon

会变小的。例如我的前端项目。最终结果就是一个 nginx 的镜像加一层 html 脚本。

FROM node:alpine as build

COPY . /project/

WORKDIR /project
RUN echo "Installing dependencies..." && \
npm install
RUN echo "Starting dist build..." && \
npm run-script build

FROM nginx:stable-alpine

COPY --from=build /project/dist /usr/share/nginx/html/

EXPOSE 80
Havee
2018-08-18 21:25:22 +08:00
@DiamondYuan 这是因为没有进行清理操作,或者清理到位

@wangxiaoaer 因为每一次 apt 结果的 hash 不可能相同,如果你想省去每一次的 apt,那么第一次在 apt 后就打一个 tag,后面的构建都 from 这个 tag 来进行。
wangxiaoaer
2018-08-18 21:35:45 +08:00
@Havee 我想过这样子做,把耗时操作打成一个镜像,但这样分发的时候就要把那个镜像也拷过去,除非搭建私服。
Havee
2018-08-18 21:46:31 +08:00
譬如如下的两次构建,会直接用缓存,你可以试一下

FROM alpine
RUN echo "1" > 1

FROM alpine
RUN echo "1" > 1
RUN echo "2" > 2
Havee
2018-08-18 21:53:34 +08:00
第一次回复说错了,同样的安装环境,应该同样的 hash,譬如

FROM alpine
RUN apk add --no-cache curl

FROM alpine
RUN apk add --no-cache curl
RUN apk add --no-cache git

第二次构建会直接使用前一次 cache
Havee
2018-08-18 21:55:47 +08:00
或许,是因为 apt-get 后产生的日志文件中,时间不同,导致最后的 hash 不一致?
derek80
2018-08-18 22:21:19 +08:00
https://docs.docker.com/develop/develop-images/multistage-build/

编译一个静态文件放 alpine 这种镜像里就好。
Kilerd
2018-08-18 22:49:51 +08:00
如果是编译成二进制的,那么用多端构建,放进 alpine 里面就好了
如果是 Python 等类型的项目,可以试下 docker-slim 来缩小 image 的大小

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/481011

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX