转载自https://github.com/qianlei90/Blog/issues/35
构建
docker构建一个镜像,需要:
- Dockerfile文件
- 构建所需的上下文
$ docker build .
这条命令中,docker CLI会:
- 把当前目录及子目录当做上下文传递给docker服务
- 从当前目录(不包括子目录)中找到Dockerfile
- 检查Dockerfile的语法
- 依次执行Dockerfile中的指令,根据指令生成中间过度镜像(存储在本地,为之后的指令或构建作缓存)
当然也可以用远程git仓库来代替本地路径,docker服务会把整个git仓库(包括git子模块)当做上下文,在仓库的根目录中寻找Dockerfile。
注意
为了加快构建速度,减少传递给docker服务的文件数量,最好将Dockerfile放在单独的空目录中。如果目录中含有大量文件,可以使用.dockerignore
(后述)来忽略构建时用不到的文件。
例子:
$ docker build --no-cache=true -f /path/to/Dockerfile -t some_tag -t image_name:image_version /path/to/build
--no-cache
:不使用缓存,每条指令都重新生成镜像(速度会很慢)
-f
:明确指定Dockerfile
-t
:给生成的镜像打上标签
寻找缓存的逻辑
docker寻找缓存的逻辑其实就是树型结构根据Dockerfile指令遍历子节点的过程。下图可以说明这个逻辑。
FROM base_image:version Dockerfile:
+----------+ FROM base_image:version
|base image| RUN cmd1 --> use cache because we found base image
+-----X----+ RUN cmd11 --> use cache because we found cmd1
/ \
/ \
RUN cmd1 RUN cmd2 Dockerfile:
+------+ +------+ FROM base_image:version
|image1| |image2| RUN cmd2 --> use cache because we found base image
+---X--+ +------+ RUN cmd21 --> not use cache because there's no child node
/ \ running cmd21, so we build a new image here
/ \
RUN cmd11 RUN cmd12
+-------+ +-------+
|image11| |image12|
+-------+ +-------+
大部分指令可以根据上述逻辑去寻找缓存,除了ADD
和COPY
。
这两个指令会复制文件内容到镜像内,除了指令相同以外,docker还会检查每个文件内容校验和(不包括最后修改时间和最后访问时间),如果校验和不一致,则不会使用缓存。
注意
除了这两个命令,docker并不会去检查容器内的文件内容,比如RUN apt-get -y update
,每次执行时文件可能都不一样,但是docker认为命令一致,会继续使用缓存。这样一来,以后构建时都不会再重新运行apt-get -y update
。
如果docker没有找到当前指令的缓存,则会构建一个新的镜像,并且之后的所有指令都不会再去寻找缓存。
3 .dockerignore
在docker构建镜像的第一步,docker CLI会先在上下文目录中寻找.dockerignore
文件,根据.dockerignore文件排除上下文目录中的部分文件和目录,,然后把剩下的文件和目录传递给docker 服务。
.dockerignore
语法同.gitignore
,具体不表,可以参考官方文档。