Dockerfile系列(二) 镜像分层与缓存-为什么你的构建这么慢
镜像分层与缓存为什么你的构建这么慢本文基于 Docker 24.x理解分层机制是写出高效 Dockerfile 的关键。场景引入改一行代码构建五分钟上篇咱们写了个能跑的 Dockerfile但用着用着发现问题了我就改了个res.send()里的字符串重新构建时居然又从头npm install了一遍看着终端里慢悠悠下载依赖的进度条我开始怀疑人生…其实啊这不是 Docker 慢是你没搞懂它的分层缓存机制。今天咱们就把这个汉堡分层原理扒清楚。核心原理UnionFS 与镜像分层镜像到底是什么结构Docker 镜像不是一个大文件而是像汉堡一样一层一层叠起来的最上层可读可写你的应用代码 ↓ 中间层npm install 安装的依赖 ↓ 中间层package.json 拷贝 ↓ 最底层基础镜像node:18-alpine 操作系统每一层都是只读的容器运行时在最上面加一层可写层。这种设计叫UnionFS联合文件系统。类比汉堡店的预制菜想象你去快餐店买汉堡基础镜像面包底工厂批量做好的大家一样RUN 安装依赖肉饼厨房提前煎好的换的人不多COPY 代码生菜番茄每次可能不一样容器运行你加的黄芥末最上面这层每人自定义关键是如果某一层没变就直接从冰箱里拿预制好的不用重做。这就是缓存的本质。缓存规则什么时候命中什么时候失效Docker 构建时从上往下逐层检查某一层的内容没变→ 直接用缓存跳过执行某一层变了→ 这一层及之后的所有层全部重新构建致命陷阱COPY . .的位置看个反例FROM node:18-alpine WORKDIR /app # ❌ 错误先把所有代码拷进去 COPY . . # 完蛋只要改任何代码这一层就变了 RUN npm install # 缓存失效重新安装 EXPOSE 3000 CMD [npm, start]因为COPY . .把package.json、app.js、README.md全拷进去了你改个注释这一层就变了后面的npm install必须重做。正确姿势让不常变的先拷贝FROM node:18-alpine WORKDIR /app # ✅ 正确先单独拷 package.json不常变 COPY package*.json ./ RUN npm install # 依赖没变直接命中缓存 # 经常变的代码放后面 COPY . . EXPOSE 3000 CMD [npm, start]这样只有package.json或package-lock.json变了才重新npm install。改业务代码缓存稳稳命中。实战验证用docker history看分层构建完成后看看镜像的分层结构dockerhistorymy-first-app输出大概长这样IMAGE CREATED CREATED BY SIZE abc123 2 min ago CMD [npm start] 0B missing 2 min ago EXPOSE map[3000/tcp:{}] 0B missing 2 min ago COPY . . # buildkit 12.3kB missing 2 min ago RUN /bin/sh -c npm install # buildkit 45.6MB missing 2 min ago COPY package*.json ./ # buildkit 2.1kB missing 2 min ago WORKDIR /app 0B missing 2 min ago /bin/sh -c #(nop) CMD [node] 0B每一行就是一层SIZE 表示这层新增的数据量。看到没npm install那层占了 45MB这就是我们要极力避免重复执行的原因。进阶技巧强制不用缓存有时候你想彻底重新构建比如基础镜像更新了# 加 --no-cache从头来dockerbuild --no-cache-tmy-app.或者只让某一层失效在 Dockerfile 里加个小技巧——# 通过 ARG 传入时间戳让这层总是变 ARG CACHEBUST1 RUN npm install构建时换一下参数缓存就失效了dockerbuild --build-argCACHEBUST$(date%s)-tmy-app.更多缓存优化技巧1. 合并 RUN 指令减少层数每条RUN创建一层。如果多个命令有依赖关系可以合并# 之前3 层 RUN apt-get update RUN apt-get install -y curl RUN apt-get install -y vim # 优化1 层顺便清理缓存 RUN apt-get update \ apt-get install -y curl vim \ rm -rf /var/lib/apt/lists/*最后那个清理很重要不然apt的缓存会永久留在镜像里占空间。2. 利用 BuildKit 的缓存挂载Docker 新版支持更高级的缓存需要启用 BuildKit# syntaxdocker/dockerfile:1 FROM node:18-alpine WORKDIR /app COPY package*.json ./ # 把 npm 缓存挂在主机上跨构建复用 RUN --mounttypecache,target/root/.npm \ npm install COPY . . CMD [npm, start]这样即使package.json变了npm 的下载缓存还在不用重新从网络拉。一句话总结Dockerfile 的缓存像叠汉堡一层变了上面全重做。把不常变的指令依赖安装放前面常变的业务代码放后面构建速度能快几倍。
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2557408.html
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!