摘要:最理想的情况下,我们希望或者变动的时候会重新的安装包,在没有变动的情况下使用缓存缩短构建时间。
在使用Docker部署PHP或者node.js应用时,常用的方法是将代码和环境镜像打包成一个镜像然后运行,一些云厂商提供了非常便捷的操作,只需要把我们的代码提交到VCS上,然后它们就会帮我们拉取代码并根据代码包内的Dockerfile构建我们的镜像然后部署到集群里。
PHP和node.js都有非常不错的生态,有各种各样的包,但是一旦引入的包多了我们的项目内的文件就会变得非常多,所以在使用VCS协作的时候我们都会忽略掉依赖包目录(node_modules / vendor)。但是我们忽略了包目录后在构建镜像的时候就要使用composer或者npm把包重新装回去,所以Dockerfile大概长这样
FROM node COPY . /src RUN cd /src && npm install
这样看起来没什么问题,但是如果包一旦多起来安装的时候需要花费很长的时间,修复紧急bug的情况下等待的时间就是煎熬,那我们有没有什么办法能让这个过程更快一些呢?
我们知道Docker构建是分层的,一条指令一层,在没有带--no-cache=true指令的情况下如果某一层没有改动,Docker就不会重新构建这一层而是会使用缓存,先来看看Docker官方文档的描述
Starting with a parent image that is already in the cache, the next instruction is compared against all child images derived from that base image to see if one of them was built using the exact same instruction. If not, the cache is invalidated.
In most cases, simply comparing the instruction in the Dockerfile with one of the child images is sufficient. However, certain instructions require more examination and explanation.
For the ADD and COPY instructions, the contents of the file(s) in the image are examined and a checksum is calculated for each file. The last-modified and last-accessed times of the file(s) are not considered in these checksums. During the cache lookup, the checksum is compared against the checksum in the existing images. If anything has changed in the file(s), such as the contents and metadata, then the cache is invalidated.
简单来说就是如果第n层有改动,则n层以后的缓存都会失效,大多数情况下判断有无改动的方法是判断这层的指令和缓存中的构建指令是否一致,但是对于COPY和ADD命令会计算镜像内的文件和构建目录文件的校验和然后做比较来判断本层是否有改动。
最理想的情况下,我们希望package.json或者composer.json变动的时候会重新的安装包,在没有变动的情况下使用缓存缩短构建时间。
了解上面的规则后我们再来看看上面那个Dockerfile,如果我们不修改任何代码的话第二次构建也是能使用缓存的,但是如果我们修改了代码,COPY . /src这层的缓存就会失效,同时下一层的缓存也会失效。但是大多数情况下,重新构建镜像就意味着代码有修改,但是package.json和composer.json这两个文件并不会频繁的修改,所以我们需要把这两个文件以及install的操作分离出来,所以有
FROM node COPY package.json /src/package.json RUN cd /src && npm install COPY . /src
在package.json里面写一个依赖包
{ "dependencies": { "express": "^4.16.4" } }
然后再写一个index.js
const app = require("express")(); app.listen(8080)
然后我们进行第一次构建,看看docker history的输出
LIN2UR:~ lin2ur$ docker history demo IMAGE CREATED CREATED BY SIZE COMMENT 3c913c9e997b 6 seconds ago /bin/sh -c #(nop) COPY dir:e3c12f06720cf5f3b… 1.6MB 21373087419a 6 seconds ago /bin/sh -c cd /src && npm install 3MB 64896ee5240d 14 seconds ago /bin/sh -c #(nop) COPY file:87de28b86afd2c1c… 53B
把每一层的IMAGE ID和Dockerfile里面的指令对应起来就是
64896ee5240d => COPY package.json /src/package.json
21373087419a => RUN cd /src && npm install
3c913c9e997b => COPY . /src
现在我们来修改一下index.js模拟我们业务代码变动然后再进行构建
LIN2UR:~ lin2ur$ docker history demo IMAGE CREATED CREATED BY SIZE COMMENT 5d697905ad0a 6 seconds ago /bin/sh -c #(nop) COPY dir:d698db67dac047bd2… 1.6MB 21373087419a 4 minutes ago /bin/sh -c cd /src && npm install 3MB 64896ee5240d 4 minutes ago /bin/sh -c #(nop) COPY file:87de28b86afd2c1c… 53B
可以看到除了最上一层外其他两层的IMAGE ID是没有变化的,再来看看docker build命令的输出
LIN2UR:~ lin2ur$ docker build --rm -f "Dockerfile" -t demo . Sending build context to Docker daemon 1.902MB Step 1/4 : FROM node ---> c63e58f0a7b2 Step 2/4 : COPY package.json /src/package.json ---> Using cache ---> 64896ee5240d Step 3/4 : RUN cd /src && npm install ---> Using cache ---> 21373087419a Step 4/4 : COPY . /src ---> 5d697905ad0a Successfully built 5d697905ad0a Successfully tagged demo:latest
可以看到步骤2和3都使用了缓存,比第一次构建的时间缩短不少。现在我们在package.json里面再加一个包模拟依赖包变动
LIN2UR:~ lin2ur$ docker history demo IMAGE CREATED CREATED BY SIZE COMMENT 020ce95b1987 29 seconds ago /bin/sh -c #(nop) COPY dir:ea4d7afd475895520… 1.6MB d9697dfc7022 31 seconds ago /bin/sh -c cd /src && npm install 3MB 71d8a2fb458a 38 seconds ago /bin/sh -c #(nop) COPY file:87bd25345a96e6b3… 51B
这次底下两层的IMAGE ID都变了,意味着没有使用缓存,再来看看docker build命令的输出
LIN2UR:~ lin2ur$ docker build --rm -f "Dockerfile" -t demo . Sending build context to Docker daemon 1.902MB Step 1/4 : FROM node ---> c63e58f0a7b2 Step 2/4 : COPY package.json /src/package.json ---> 71d8a2fb458a Step 3/4 : RUN cd /src && npm install ---> Running in ce424d6af936 Step 4/4 : COPY . /src ---> 020ce95b1987 Successfully built 020ce95b1987 Successfully tagged demo:latest
由于第二层的package.json改动导致这层及后续的缓存失效,然后重新安装包,实现了我们希望的结果。
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/27676.html
摘要:最理想的情况下,我们希望或者变动的时候会重新的安装包,在没有变动的情况下使用缓存缩短构建时间。 在使用Docker部署PHP或者node.js应用时,常用的方法是将代码和环境镜像打包成一个镜像然后运行,一些云厂商提供了非常便捷的操作,只需要把我们的代码提交到VCS上,然后它们就会帮我们拉取代码并根据代码包内的Dockerfile构建我们的镜像然后部署到集群里。 PHP和node.js都...
摘要:本文将介绍精简容器镜像的必要性并以基于的应用为例描述最小化容器镜像的常用技巧。经过这一优化,最终镜像的大小为。 背景 随着容器技术的普及,越来越多的应用被容器化。人们使用容器的频率越来越高,但常常忽略一个基本但又非常重要的问题 - 容器镜像的体积。本文将介绍精简容器镜像的必要性并以基于 spring boot 的 java 应用为例描述最小化容器镜像的常用技巧。 精简容器镜像的必要性 ...
摘要:接下来我们将逐步的减少这个镜像的体积。优化生产环境镜像使用镜像大幅减小镜像体积的最简单和最快的方法是选择一个小得多的基本镜像。使用多阶段构建可以充分利用镜像的缓存,大大减少最终部署到生产环境的时间。 关注作者github每日一道面试题详解 你讨厌部署你的应用程序花费很长时间吗? 对于单个容器来说,超过gb并不是最佳实践。每次部署新版本时都要处理数十亿字节,这对我们来说并不太合适。 本文...
摘要:极大地降低了平台的复杂度,更加方便企业开发人员实现各种业务应用,帮助企业轻松打造基于云计算的软件基础设施。本文将从实际案例出发,结合不同的使用场景,为各位介绍的这些特性。是未来数据中心操作系统的核心。 0.前言 随着 Docker 技术的日渐火热,本就火爆的云计算行业进入了一个加速阶段。云计算最大的特点是弹性和灵活,帮助企业应对复杂的业务需求。由于云计算的IT构架和上一代的IT构架有很...
阅读 2565·2021-11-18 10:07
阅读 1061·2021-08-03 14:04
阅读 709·2019-08-30 13:08
阅读 2543·2019-08-29 15:33
阅读 1036·2019-08-29 14:07
阅读 2941·2019-08-29 14:04
阅读 1413·2019-08-29 11:19
阅读 1128·2019-08-29 10:59