5.Dockerfile详解
通过网盘分享的文件:MD文档笔记
链接: https://pan.baidu.com/s/1ao2wfyLEdN50YmIqdzfGYQ?pwd=5w5z 提取码: 5w5z
–来自百度网盘超级会员v6的分享
一.Dockerfile简介
1.什么是Dockerfile
Dockerfile 是用于构建 Docker 镜像的脚本文件,由一系列指令构成
通过 docker build 命令构建镜像时,Dockerfile 中的指令会由上到下依次执行,每条指令都将会构建出一个镜像,这就是镜像的分层
因此指令越多,层次就越多,创建的镜像就越多,效率就越低
所以在定义 Dockerfile 时能在一个指令完成的动作就不要分为两条
支持以 # 开头的注释行
一般的Dockerfile 分为四部分
- 基础镜像信息
- 维护者信息
- 镜像操作指令
- 容器启动时执行指令
【示例】
# This dockerfile uses the ubuntu image
# VERSION 2 - EDITION 1
# Author: docker_user
# Command format: Instruction [arguments / command] ..
# 所基于的镜像名称
FROM ubuntu
# 维护者信息
MAINTAINER docker_user docker_user@email.com
# 镜像操作指令
RUN echo "deb http://archive.ubuntu.com/ubuntu/ raring main universe" >> /etc/apt/sources.list
RUN apt-get update && apt-get install -y nginx
RUN echo "\ndaemon off;" >> /etc/nginx/nginx.conf
# 指定运行容器时的操作命令
CMD /usr/sbin/nginx
其中一开始必须指明所基于的镜像名称,接下来推荐说明维护者信息
后面则是镜像操作指令(例如 RUN 指令:RUN 指令将对镜像执行跟随的命令),每运行一条 RUN 指令,镜像添加新的一层并提交
最后是 CMD 指令,来指定运行容器时的操作命令
2.Dockerfile构建镜像流程
- 编写Dokcerfile文件
- docker build 生成新的镜像
- docker run 运行镜像
3.Dockerfile基础知识
- 每条指令都必须为大写字母,后面要跟随至少一个参数
- 指令从上到下顺序执行
- #表示注释
- 每条指令都会创建一个新的镜像层,并对镜像进行提交
4.Dockerfile大致流程
- docker从基础镜像运行一个容器
- 执行一条指令并对容器进行修改
- 执行类似于docker commit的操作提交一个新的镜像
- docker再基于刚提交的新的镜像运行一个新的容器
- 执行dockerfile的下一个指令再从执行第2点直到没有指令
5.Dockerfile、Docker镜像与Docker容器的关系
从应用软件的角度来看Dockerfile、Docker镜像与Docker容器分别代表软件的三个不同阶段
Dockerfile面向开发,Docker镜像成为交付标准,Docker容器则涉及部署与运维,三者缺一不可,合力充当Docker体系的基石

-
Dockerfile是软件的原材料
需要定义一个Dockerfile,Dockerfile定义了进程需要的一切东西
Dockerfile涉及的内容包括执行代码或者是文件、环境变量、依赖包、运行时环境、动态链接库、操作系统的发行版、
服务进程和内核进程(当应用进程需要和系统服务和内核进程打交道,这时需要考虑如何设计namespace的权限控制)等等
-
Docker镜像是软件的交付品
在用Dockerfile定义一个文件之后,docker build时会产生一个Docker镜像,当运行 Docker镜像时,会真正开始提供服务;
-
Docker容器则可以认为是软件的运行态
容器是直接提供服务的
二.Docker指令
1.FROM
(1).语法格式
FROM <image>[:<tag>]
(2).语法解析
用于指定基础镜像且必须是第一条指令
若省略了 tag则默认为 latest
如果在同一个Dockerfile中创建多个镜像时,可以使用多个 FROM 指令(每个镜像一次)
(3).使用示例
[root@docker ~]# mkdir -p /root/dockerfile/from
[root@docker ~]# cd /root/dockerfile/from/
[root@docker from]# vim Dockerfile
# 基于centos7创建镜像
FROM centos:7
[root@docker from]# docker build -t my_from_01:1.0 /root/dockerfile/from/

2.MAINTAINER
(1).语法格式
MAINTAINER <name>
(2).语法解析
MAINTAINER 指令的参数填写的一般是维护者姓名和信箱
该指令官方已不建议使用,而是使用LABEL 指令代替
(3).使用示例
[root@docker ~]# mkdir -p /root/dockerfile/maintainer
[root@docker ~]# cd /root/dockerfile/maintainer/
[root@docker maintainer]# vim Dockerfile
# 基于centos7创建镜像
FROM centos:7
# 设置创建者信息
MAINTAINER zhangsan hailong111@126.com
[root@docker maintainer]# docker build -t mymaintainer01:1.0 /root/dockerfile/maintainer/

5.2.3.LABEL
(1).语法格式
LABEL <key>=<value> <key>=<value>
(2).语法解析
LABEL指令中可以以键值对的方式包含任意镜像的元数据信息,用于替代MAINTAINER 指令
通过 docker inspect 可查看到 LABEL 与 MAINTAINER 的内容
(3).使用示例
[root@docker ~]# mkdir -p /root/dockerfile/label
[root@docker ~]# cd /root/dockerfile/label/
[root@docker label]# vim Dockerfile
# 基于centos7创建镜像
FROM centos:7
# 设置创建者信息
LABEL name=zhangsan email=hailong111@126.com
[root@docker label]# docker build -t mylabel01 /root/dockerfile/label/
[root@docker label]# docker run --name mylabel -it mylabel01

5.2.1.4.ENV
用于指定环境变量,这些环境变量后续可以被 RUN 、WORKDIR等指令使用,容器运行起来之后也可以在容器中获取这些环境变量
(1).语法格式
-
格式一
ENV <key> <value> -
格式二
ENV <key1>=<value1> <key2>=<value2> ...可以设置多个变量,每个变量为一对<key>=<value>
(2).使用示例
-
创建Dockerfile
[root@docker ~]# mkdir -p /root/dockerfile/env [root@docker ~]# cd /root/dockerfile/env [root@docker env]# vim Dockerfile [root@docker env]# FROM centos:7 MAINTAINER zhangsan zs@163.com LABEL version="1.0" description="this is a custom centos image" ENV WORKPATH /usr/local WORKDIR $WORKPATH CMD /bin/bash -
构建镜像
docker build -t myenv:1.0 .
5.ARG
(1).语法格式
ARG <varname>[=<default value>]
(2).语法解析
该指令用于定义一个变量,该变量将会在镜像构建时使用
构建镜像时如果使用ARG参数,那么该参数必须在Dockfile文件中定义后才能在构建时使用,否则不能使用
注意不是容器启动时,容器启动时镜像构建早已完成
若要定义多个变量,则需要定义多个 ARG 指令
(3).使用示例
-
第一步:创建 Dockerfile
在/root目录下mkdir 一个名称为 arg 的目录,在其中新建文件 Dockerfile,内容如下
[root@docker ~]# mkdir -p /root/dockerfile/args [root@docker ~]# cd /root/dockerfile/args [root@docker args]# vim Dockerfile FROM centos:7 ARG name=Tom RUN echo $nameRUN 指令用于指定在 docker build 执行时要执行的内容
-
第二步:使用 ARG 默认值构建
使用 Dockerfile 构建镜像 myargs:1.0
docker build -t myargs:1.0 .
可以看到在镜像构建时读取了 ARG 中参数,只不过 docker build 中并没有给变量 name 赋予新值,所以 name 使用的是其默认值 Tom
-
第三步:使用 ARG 指定值构建
使用 Dockerfile 构建镜像 myargs:2.0
在 docker build 命令中指定了 ARG 中参数值,覆盖了默认值
docker build -t myargs:2.0 --build-arg name=Jerry .
-
第四步:使用 ARG 指定不存在的值构建
使用 Dockerfile 构建镜像 myargs:3.0
在 docker build 命令中指定了 ARG 中参数值,但是该参数没有在Dockerfile中定义
docker build -t myargs:2.0 --build-arg age=21 .
6.ADD
将宿主机目录下的文件拷贝进镜像
(1).语法格式
【语法 1】ADD <src> <dest>
【语法 2】ADD [“<src>”, “<dest>”] # 路径中存在空格时使用双引号引起来
(2).语法解析
该指令将复制当前宿主机中指定文件(文件夹) src 到容器中的指定目录 dest 中
-
src 的路径
- 可以是宿主机中的绝对路径
- 可以是相对路径,相对路径是相对于
docker build命令所指定的路径的(docker build -t myargs:2.0 Dockerfile文件的路径)中所指定的Dockerfile文件的路径
-
src 的文件
- 指定的文件可以是一个压缩文件,压缩文件复制到容器后会自动解压为目录
-
src 也可以是一个URL,此时的 ADD 指令相当于wget 命令
-
src 最好不要是目录,其会将该目录中所有内容复制到容器的指定目录中
-
dest 是一个绝对路径,其最后面的路径必须要加上斜杠,否则系统会将最后的目录名称当做是文件名的
(3).使用示例
【示例1】
-
创建目录
在/root/目录下创建目录
[root@docker ~]# mkdir -p /root/dockerfile/add [root@docker ~]# cd /root/dockerfile/add将jdk-8u251-linux-x64.tar.gz压缩包上传到该目录

-
在add目录新建文件 Dockerfile
[root@docker add]# vim Dockerfile FROM centos:7 WORKDIR /opt ADD jdk-8u251-linux-x64.tar.gz /opt/add/ CMD /bin/bash -
构建镜像 build
使用 Dockerfile 构建镜像 myadd01
docker build -t myadd01 .
-
运行新建镜像
启动 myadd01镜像,在容器的/opt 目录中发现自动生成目录 add
docker run --name myadd -it myadd01通过 ADD 指令添加的是解压过的目录

【示例2】
-
创建目录
在/root/目录下创建目录
[root@docker ~]# mkdir -p /root/dockerfile/add [root@docker ~]# cd /root/dockerfile/add将jdk-8u251-linux-x64.tar.gz压缩包上传到该目录

-
在add目录新建文件 Dockerfile2
[root@docker add]# vim Dockerfile2 FROM centos:7 WORKDIR /opt # 注意add后面没有/ ADD jdk-8u251-linux-x64.tar.gz /opt/add CMD /bin/bash -
构建镜像 build
使用 Dockerfile 构建镜像
myadd02:1.0docker build -f Dockerfile2 -t myadd02:1.0 .
-
运行新建镜像
启动
myadd02:1.0镜像,在容器的/opt 目录中发现自动生成目录 adddocker run --name myadd02 -it myadd02:1.0
注意这里: add后面没有/,因此add会被当成文件,但是add命令会先解压压缩包,因此会将解压后的文件夹复制到add下面,add就成了目录
7.COPY
复制指令,从宿主机目录中复制文件或者目录到容器里指定路径
容器内的指定路径不用事先建好,路径不存在的话会自动创建
(1).语法格式
【语法1】COPY src dest
【语法2】COPY [“src”,“dest”]
(2).语法解析
功能与 ADD 指令相同,只不过 src 不能是 URL
若 src 为压缩文件,复制到容器后不会自动解压
(3).使用示例
【示例1】
-
创建目录
在/root/目录下创建目录
[root@docker ~]# mkdir -p /root/dockerfile/copy [root@docker ~]# cd /root/dockerfile/copy将jdk-8u251-linux-x64.tar.gz压缩包上传到该目录

-
在copy目录新建文件 Dockerfile
[root@docker copy]# vim Dockerfile FROM centos:7 WORKDIR /opt COPY jdk-8u251-linux-x64.tar.gz /opt/copy/ CMD /bin/bash -
构建镜像 build
使用 Dockerfile 构建镜像 mycopy01
docker build -t mycopy01 .
-
运行新建镜像
启动 mycopy01镜像,在容器的/opt 目录中发现自动生成目录copy
docker run --name mycopy -it mycopy01通过 COPY 指令添加的是未解压的

【示例2】
-
创建目录
在/root/目录下创建目录
[root@docker ~]# mkdir -p /root/dockerfile/copy [root@docker ~]# cd /root/dockerfile/copy将jdk-8u251-linux-x64.tar.gz压缩包上传到该目录

-
在copy目录新建文件 Dockerfile2
[root@docker add]# vim Dockerfile2 FROM centos:7 WORKDIR /opt # 注意copy后面没有/ COPY jdk-8u251-linux-x64.tar.gz /opt/copy CMD /bin/bash -
构建镜像 build
使用 Dockerfile 构建镜像
mycopy02:1.0docker build -f Dockerfile2 -t mycopy02:1.0 .
-
运行新建镜像
启动 mycopy02镜像,在容器的/opt 目录中发现自动生成目录copy
docker run --name mycopy02 -it mycopy02:1.0
注意这里: copy后面没有/,因此copy会被当成文件,copy不会解压,所以直接将jdk压缩包复制过来,因为copy是个文件,因此这里就成了替换操作,将jdk-8u251-linux-x64.tar.gz改名为copy
8.ONBUILD
8.1.语法格式
ONBUILD [INSTRUCTION]
8.2.语法解析
该指令用于指定当前镜像的子镜像进行构建时要执行的指令
8.3.使用示例
8.3.1.创建父镜像操作
(1).父镜像 Dockerfile
在/root目录下mkdir 一个名称为 onbuild 的目录,并在其中新建文件 Dockerfile,内容如下
[root@docker ~]# mkdir -p /root/dockerfile/onbuild
[root@docker ~]#
[root@docker ~]# cd /root/dockerfile/onbuild
[root@docker onbuild]#
[root@docker onbuild]# vim Dockerfile
FROM centos:7
ENV WORKPATH /usr/local
WORKDIR $WORKPATH
ONBUILD RUN mkdir -p /usr/local/onbuild
CMD /bin/bash
当前镜像及其将来子镜像的工作目录都将是/usr/local,将来以交互模式运行后都会直接进入到 bash 命令行
ONBUILD 中指定创建文件夹的语句,是在子镜像进行 docker build 时会执行的命令
(2).构建父镜像
使用 Dockerfile构建镜像parent:1.0
docker build -t parent:1.0 .

(3).运行父镜像
运行父镜像,其工作目录为/usr/local,且没有onbuild目录
docker run -it parent:1.0

8.3.2.创建子镜像操作
(1).创建子镜像 Dockerfile
新建一个会话,在 onbuild 目录中新建文件 Dockerfile2,内容仅包含一句话,指定父镜像
[root@docker ~]# cd /root/dockerfile/onbuild
[root@docker onbuild]# vim Dockerfile2
FROM parent:1.0
(2).构建子镜像
子镜像在构建过程中下载了 wget 命令
docker build -f Dockerfile2 -t son:1.0 .

(3).运行子镜像
子镜像不仅能够直接进入到 bash 命令行,工作目录为/usr/local,其还直接具有onbuild目录
而这些功能除了继承自父镜像外,就是在构建过程中来自于 ONBUILD 指定的指令
docker run -it son:1.0

5.2.9.USER
(1).语法格式
USER <用户名>[:<用户组>]
(2).语法解析
用于指定执行后续命令的用户和用户组,这边只是切换后续命令执行的用户(用户和用户组必须提前已经存在)
10.WORKDIR
(1).语法格式
WORKDIR path
(2).语法解析
指定容器打开后默认进入的目录,一般在后续的 RUN、CMD、ENTRYPOINT、ADD 等指令中会引用该目录
可以设置多个 WORKDIR 指令
后续 WORKDIR 指令若用的是相对路径,则会基于之前WORKDIR 指令指定的路径
在使用 docker run 运行容器时,可以通过-w 参数覆盖构建时所设置的工作目录
docker build 构建镜像过程中的每一个 RUN 命令都是新建的一层,只有通过 WORKDIR 创建的目录才会一直存在
(3).使用示例
-
创建目录
在/root/目录下创建workdir 目录
将apache-tomcat-8.5.33.tar.gz压缩包上传到该目录
[root@docker ~]# mkdir -p /root/dockerfile/workdir [root@docker ~]# cd /root/dockerfile/workdir
-
在workdir目录新建文件 Dockerfile
[root@docker workdir]# vim Dockerfile FROM centos:7 WORKDIR /opt ADD apache-tomcat-8.5.33.tar.gz /opt/add/ COPY apache-tomcat-8.5.33.tar.gz /opt/copy/ CMD /bin/bash -
构建镜像 build
使用 Dockerfile 构建镜像 workdir镜像
docker build -t workdir:1.0 .
-
运行新建镜像
启动 workdir镜像,默认进入的目录是/opt
docker run --name myworkdir -it workdir:1.0
11.RUN
每条 RUN 指令将在当前镜像基础上执行指定命令,并提交为新的镜像
当命令较长时可以使用 \ 来换行
(1).语法格式1
【语法 】RUN <command>
【解析】
这里的<command>就是 shell 命令
docker build 执行过程中会使用 shell 运行指定的 command
(2).语法格式2
【语法 】RUN [“EXECUTABLE”,“PARAM1”,“PARAM2”, …]
【解析】
在 docker build 执行过程中会调用第一个参数"EXECUTABLE"指定的应用程序运行,并使用后面第二、三等参数作为应用程序的运行参数
(3).使用示例
创建镜像
[root@docker ~]# mkdir -p /root/dockerfile/run
[root@docker ~]# cd /root/dockerfile/run
[root@docker run]# vim Dockerfile
FROM centos:7
WORKDIR /usr/local
RUN mkdir -p /usr/local/run \
&& cd /usr/local/run \
&& touch run.txt
CMD /bin/bash
[root@docker run]# docker build -t myrun:1.0 .

运行容器
docker run --name myrun01 -it myrun:1.0

12.CMD
为启动的容器指定默认要运行的程序,程序运行结束,容器也就结束
CMD 指令指定的程序可被 docker run 命令行参数中指定要运行的程序所覆盖
注意:如果 Dockerfile 中如果存在多个 CMD 指令,仅最后一个生效
12.1.CMD-SHELL语法
(1).语法格式
CMD command param1 param2, ...
(2).语法解析
这里的 command 就是 shell 命令,在容器启动后会立即运行指定的 shell 命令
(3).使用示例
-
创建 Dockerfile
在/root/dockerfile/cmd/shell/目录中新建文件 Dockerfile,并定义内容如下
[root@docker ~]# mkdir -p /root/dockerfile/cmd/shell/ [root@docker ~]# cd /root/dockerfile/cmd/shell/ [root@docker shell]# vim Dockerfile FROM centos:7 CMD cal -
构建镜像 build
docker build -f ./Dockerfile -t mycal1 .说明:-f 用于指定本次构建所要使用的 Dockerfile 文件(如果文件名不是 docker build 默认加载的 Dockerfile 这个名称)

-
运行新建镜像
运行后可以查看到当前月份的日历
docker run -it mycal1
-
覆盖CMD
在 docker run 命令中指定要执行的命令,Dockerfile 中通过 CMD 指定的默认的命令就不会在执行
测试使用date指令覆盖CMD中指定的cal指令
docker run -it mycal1 date
-
不能添加命令选项
docker run -it mycal1 -yDockerfile 中的[command]如果是通过 CMD 指定的,则该镜像的启动命令 docker run 中是不能添加参数[ARG]的
因为 Dockerfile 中的 CMD 是可以被命令中的 [COMMAND]替代的
如果命令中的 IMAGE 后仍有内容,此时对于 docker daemon 来说,其首先认为是替代用的[COMMAND],如果有两个或两个以上的内容,后面的内容才会认为是 [ARG]
所以添加的-y 会报错,因为没有-y 这样的[COMMAND]

12.2.CMD-EXEC语法
(1).语法格式
CMD ["EXECUTABLE","PARAM1","PARAM2", ...]
(2).语法解析
在容器启动后,即在执行完 docker run 后会立即调用执行"EXECUTABLE"指定的可执行文件,并使用后面第二、三等参数作为应用程序的运行参数
(3).使用示例
-
创建 Dockerfile
在/root/dockerfile/cmd/exec/目录中新建文件 Dockerfile,并定义内容如下
[root@docker ~]# mkdir -p /root/dockerfile/cmd/exec/ [root@docker ~]# cd /root/dockerfile/cmd/exec/ [root@docker exec]# vim Dockerfile FROM centos:7 CMD ["/bin/bash", "-c", "cal"] -
构建镜像 build
docker build -f ./Dockerfile -t mycal2 .
-
运行新建镜像
运行结果与 shell 方式的相同
docker run -it mycal2
-
覆盖CMD
运行结果与 shell 方式的相同,也可以被覆盖
docker run -it mycal2 date
-
不能添加命令选项
虽然在 CMD 中指定可以从命令行接收选项,但运行结果与 shell 方式的相同,也不能添加命令选项
这是由 CMD 命令本身决定的
Dockerfile 中的[“EXECUTABLE”]如果是通过 CMD 指定的,则该镜像的启动命令 docker run 中是不能添加参数[ARG]的
因为 Dockerfile 中的 CMD 是可以被命令中的 [COMMAND]替代的
如果命令中的 IMAGE 后仍有内容,此时对于 docker daemon 来说,其首先认为是替代用的[COMMAND],如果有两个或两个以上的内容,后面的内容才会认为是 [ARG]
所以添加的-y 会报错,因为没有-y 这样的[COMMAND]
docker run -it mycal2 -y
12.3.使用总结
CMD指令都用于指定容器启动时要执行的命令
每个 Dockerfile 中都只能有一个 CMD 指令,如果有多个 CMD指令只会执行最后一个
CMD 指定的是容器启动时默认的命令
即 docker run 时若指定了要运行的命令,Dockerfile 中的 CMD 指令指定的命令是不会执行的
Dockerfile 中的[command]或[“EXECUTABLE”]如果是通过 CMD 指定的,则该镜像的启动命令 docker run 中是不能添加参数[ARG]的
因为 Dockerfile 中的 CMD 是可以被命令中的 [COMMAND]替代的
如果命令中的 IMAGE 后仍有内容,此时对于 docker daemon 来说,其首先认为是替代用的[COMMAND],如果有两个或两个以上的内容,后面的内容才会认为是 [ARG]
结论:无论是 CMD 还是 ENTRYPOINT,使用[“EXECUTABLE”]方式的通用性会更强些
13.ENTRYPOINT指令
用于设定容器启动时第一个运行的命令及其参数
ENTRYPOINT的目地和CMD一样,都是在指定容器启动程序及参数
但其不会被 docker run 的命令行参数指定的指令所覆盖,而且这些"docker run"命令行设置的参数会被追加到ENTRYPOINT 指令之后
但是如果运行 docker run 时使用了 --entrypoint 选项,此选项的参数可当作要运行的程序覆盖 ENTRYPOINT 指令指定的程序
注意:如果 Dockerfile 中如果存在多个 ENTRYPOINT 指令,仅最后一个生效
13.1.ENTRYPOINT-SHELL语法
(1).语法格式
ENTRYPOINT command param1 param2, ...
(2).语法解析
这里的 command 就是 shell 命令,在容器启动过程中,即在执行 docker run 时,会运行指定的shell 命令
(3).使用示例
-
创建 Dockerfile
在/root/ce目录中新建文件 Dockerfile3,并定义内容如下
[root@docker ~]# mkdir -p /root/dockerfile/entrypoint/shell/ [root@docker ~]# cd /root/dockerfile/entrypoint/shell/ [root@docker shell]# vim Dockerfile FROM centos:7 ENTRYPOINT cal -
构建镜像 build
docker build -f ./Dockerfile -t mycal3 .说明:-f 用于指定本次构建所要使用的 Dockerfile 文件(如果文件名不是 docker build 默认加载的 Dockerfile 这个名称)

-
运行新建镜像
docker run -it mycal3
-
ENTRYPOINT不会被覆盖
ENTRYPOINT 指定的命令是不会被 docker run 中指定的命令给覆盖掉的
docker run -it mycal3 date
-
添加命令选项无效
在 docker run 中添加的命令选项,对于 ENTRYPOINT 中指定的命令是无效的
这里不生效是因为SHELL这种语法是直接执行SHELL中的指令,不会将docker run后面的参数拼接到shell指令的后面
Dockerfile 中的[command]或[“EXECUTABLE”]如果是通过 ENTRYPOINT 指定的,则该镜像的启动命令 docker run 中是可以添加参数[ARG]的
因为 Dockerfile 中的 ENTRYPOINT 是不能被命令中的[COMMAND]替代的
如果命令中的 IMAGE 后仍有内容,此时对于 docker daemon来说,其只能是[ARG]
不过docker daemon 对于 ENTRYPOINT 指定的[command]与[“EXECUTABLE”]的处理方式是不同的
-
如果是[command]指定的 shell,daemon 会直接运行,而不会与 docker run 中的 [ARG]进行拼接后运行
-
如果是[“EXECUTABLE”]指定的命令,daemon 则会先与 docker run 中的[ARG]进行拼接,然后再运行拼接后的结果
docker run -it mycal3 -y
-
13.2.ENTRYPOINT-EXEC语法
(1).语法格式
ENTRYPOINT ["EXECUTABLE","PARAM1","PARAM2", ...]
(2).语法解析
在容器启动过程中,即在执行 docker run 时,会调用执行"EXECUTABLE"指定的应用程序,并使用后面第二、三等参数作为应用程序的运行参数
(3).使用示例
-
创建 Dockerfile
在/root/ce目录中新建文件 Dockerfile4,并定义内容如下
[root@docker ~]# mkdir -p /root/dockerfile/entrypoint/exec/ [root@docker ~]# cd /root/dockerfile/entrypoint/exec/ [root@docker ce]# vim Dockerfile FROM centos:7 ENTRYPOINT ["cal"] -
构建镜像 build
docker build -f ./Dockerfile -t mycal4 .
-
运行新建镜像
运行结果与 shell 方式的相同
docker run -it mycal4
-
ENTRYPOINT不会被覆盖
运行结果会报错,系统认为 date 是 cal 的非法参数
docker run -it mycal4 date
-
添加命令选项无效
与之前不同的是,这种情况下在 docker run 中添加的命令选项是有效的
这是因为
-y实际上是作为了ENTRYPOINT ["cal"]指令的参数,cal是有-y参数的Dockerfile 中的[command]或[“EXECUTABLE”]如果是通过 ENTRYPOINT 指定的,则该镜像的启动命令 docker run 中是可以添加参数[ARG]的
因为 Dockerfile 中的 ENTRYPOINT 是不能被命令中的[COMMAND]替代的
如果命令中的 IMAGE 后仍有内容,此时对于 docker daemon来说,其只能是[ARG]
不过docker daemon 对于 ENTRYPOINT 指定的[command]与[“EXECUTABLE”]的处理方式是不同的
-
如果是[command]指定的 shell,daemon 会直接运行,而不会与 docker run 中的 [ARG]进行拼接后运行
-
如果是[“EXECUTABLE”]指定的命令,daemon 则会先与 docker run 中的[ARG]进行拼接,然后再运行拼接后的结果
docker run -it mycal4 -y
-
13.3.ENTRYPOINT 与CMD 同用
(1).语法格式
CMD ["PARAM1","PARAM2", ...]
ENTERYPOINT ["EXECUTABLE"]
(2).语法解析
提供给 ENTERYPOINT 的默认参数
(3).使用示例
-
创建 Dockerfile
在/root/ce目录中新建文件 Dockerfile5,并定义内容如下
[root@docker ~]# mkdir -p /root/dockerfile/entrypointandcmd/exec/ [root@docker ~]# cd /root/dockerfile/entrypointandcmd/exec/ [root@docker exec]# vim Dockerfile FROM centos:7 CMD ["hello world"] ENTRYPOINT ["echo"] -
构建镜像 build
docker build -f ./Dockerfile -t mycal5 .
-
运行新建镜像
docker run -it mycal5
-
添加命令选项
在 docker run –it mycal5 命令后添加选项>hello.log,用于将输出的内容重定向写入到hello.log 文件中,选项生效
docker run -it mycal5 > hello.log
-
覆盖CMD生效
在 docker run –it myecho 命令后指定新的参数,用于覆盖 CMD 中的参数,生效
docker run -it mycal5 "hi docker"
13.4.使用总结
ENTERYPOINT 指令都用于指定容器启动时要执行的命令
每个 Dockerfile 中都只能有一个 ENTERYPOINT 指令,多个 ENTERYPOINT 指令只会执行最后一个
ENTRYPOINT 指定的是容器启动时一定会执行的命令
即 docker run 时若指定了要运行的命令,Dockerfile 中的 CMD 指令指定的命令是不会执行的,而 ENTERYPOINT 中指定的命令是一定会执行的
Dockerfile 中的[command]或[“EXECUTABLE”]如果是通过 ENTRYPOINT 指定的,则该镜像的启动命令 docker run 中是可以添加参数[ARG]的
因为 Dockerfile 中的 ENTRYPOINT 是不能被命令中的[COMMAND]替代的
如果命令中的 IMAGE 后仍有内容,此时对于 docker daemon来说,其只能是[ARG]
不过docker daemon 对于 ENTRYPOINT 指定的[command]与[“EXECUTABLE”]的处理方式是不同的
如果是[command]指定的 shell,daemon 会直接运行,而不会与 docker run 中的 [ARG]进行拼接后运行
如果是[“EXECUTABLE”]指定的命令,daemon 则会先与 docker run 中的[ARG]进行拼接,然后再运行拼接后的结果
结论:无论是 CMD 还是 ENTRYPOINT,使用[“EXECUTABLE”]方式的通用性会更强些
14.EXPOSE
(1).语法格式
EXPOSE <port> [<port>…]
(2).语法解析
指定容器准备对外暴露的端口号,但该端口号并不会真正的对外暴露
若要真正暴露,则需要在执行 docker run 命令时使用-p(小 p)来指定说要真正暴露出的端口号
也就是说这个暴露的端口号实际上是没有什么用的,只是作为展示告诉别人可能会使用这个端口号对外暴露,但是实际上对外暴露哪个端口号是在docker run指令中指定的
(3).使用示例
略
15.VOLUME
(1).语法格式
VOLUME ["dir1", "dir2", ...]
(2).语法解析
在容器创建可以挂载的数据卷
创建一个可以从本地主机或其他容器挂载的挂载点,一般用来存放数据库和需要保持的数据等
在启动容器 docker run 的时候,可以通过 -v 参数修改挂载点
在启动容器时忘记挂载数据卷,会自动挂载到匿名卷
(3).使用示例
后面详解
三.构建镜像示例
1.构建自己的 HelloWorld 镜像
(1).scratch 镜像
在构建自己的镜像之前,首先要了解一个特殊的镜像 scratch
scratch 镜像是一个空镜像,是所有镜像的 Base Image(相当于面向对象编程中的 Object类)
scratch 镜像只能在 Dockerfile 中被继承,不能通过 pull 命令拉取,不能 run,也没有 tag,并且它也不会生成镜像中的文件系统层
在 Docker 中scratch 是一个保留字,用户不能作为自己的镜像名称使用
(2).安装编译器
由于下面要编写、编译一段 C 语言代码,所以这里先安装一下 C 语言的编译器
yum install -y gcc gcc-c++

(3).修改镜像源配置
vim /etc/yum.repos.d/centos.repo

(4).安装静态库
由于后面在编译时要使用C 的静态库,所以要再安装 glibc-static
yum install -y glibc-static

(5).创建 hello.c
在宿主机任意目录创建一个名称为 hello.c 的文件
这里在/root 下 mkdir 一个目录 hw,然后将 hello.c 文件创建在这里
文件内容如下
[root@docker ~]# cd /root/
[root@docker ~]# mkdir hw
[root@docker ~]# cd hw/
[root@docker hw]# vim hello.c
#include<stdio.h>
int main()
{
printf("hello my docker world\n");
return 0;
}

(6).编译测试 hello.c
使用 gcc 编译 hello.c 文件
gcc --static -o hello hello.c

(7).创建 Dockerfile
在 hw 目录中新建 Dockerfile
[root@docker hw]# vim Dockerfile
FROM scratch
ADD hello /
CMD ["/hello"]
(8).构建镜像
docker build -t hello-my-world .

-
-t 用于指定要生成的镜像的<repository>与<tag>(若省略 tag,则默认为 latest)
-
最后的点(.)
是一个宿主机的路径,构建镜像时会从该路径中查找 Dockerfile 文件
同时该路径也是在 Dockerfile 中 ADD、COPY 指令中若使用的是相对路径,那个相对路径就相对的这个路径
不过需要注意,即使 ADD、COPY 指令中使用绝对路径来指定源文件,该源文件所在路径也必须要在这个 URL 指定目录或子目录内,否则将无法找到该文件
(9).查看生成的镜像
通过 docker images 查看本地镜像,可以看到新构建的 hello-my-world 镜像
docker images

(10).运行新镜像
在任意目录下都可运行该镜像
docker run hello-my-world

(11).为镜像重打标签
某镜像被指定为 latest 后,后期又出现了更新的版本需要被指定为 latest,那么原 latest镜像就应被重打<tag>标签,否则当最新版被发布为 latest 后,原镜像就会变为悬虚镜像
通过 docker tag 命令可对镜像重打标签
所谓重打标签,实际是复制了一份原镜像,并为新的镜像指定新的<tag>
当然重新指定<repository>也是可以的
所以新镜像的 ImageID、 Digest 都有原镜像的相同
docker tag hello-my-world:latest hello-my-world:2.0

查看镜像发现增加了一个新的镜像
docker images

2.构建自己的 CentOS 镜像
从镜像中心拉取来的 centos:7 镜像中是没有vim、ifconfig、wget 等常用命令的,这里要构建一个自己的 centos7 镜像,使这些命令都可以使用
(1).创建 Dockerfile
在宿主机任意目录创建一个文件,并命名为 Dockerfile
这里在/root下 mkdir 一个目录dfs,然后将如下内容复制到该文件中
[root@docker ~]# cd /root/
[root@docker ~]#
[root@docker ~]# mkdir /root/dockerfile/dfs
[root@docker ~]# cd /root/dockerfile/dfs
[root@docker dfs]# vim Dockerfile
FROM centos:7
MAINTAINER zhangsan zs@163.com
LABEL version="1.0" description="this is a custom centos image"
ENV WORKPATH /usr/local
WORKDIR $WORKPATH
CMD /bin/bash

(2).构建镜像 build
docker build -t owncentos7:1.0 .
当看到下面的日志时说明构建完成

此时通过 docker images 命令可以查看到刚刚生成的新的镜像

(3).运行新建镜像
运行了新镜像后发现默认路径是/usr/local 了
docker run --name owncentos -it owncentos7:1.0

3.构建悬虚镜像
悬虚镜像是指既没有 Repository 又没有 Tag 的镜像
当新建了一个镜像后为该镜像指定了一个已经存在的TAG,那么原来的镜像就会变为悬空镜像
为了演示悬虚镜像的生成过程,这里先修改前面定义的 Dockerfile,然后再生成镜像,且生成的新的镜像与前面构建的镜像的名称与 Tag 均相同
(1).修改 Dockerfile
修改/root/dfs 中的 Dockerfile,修改任意内容均可
这里仅将原来的 LABEL 中的 version值由 1.0 修改为了 2.0,其它没变
[root@docker dfs]# vim Dockerfile
FROM centos:7
MAINTAINER zhangsan zs@163.com
LABEL version="2.0" description="this is a custom centos image"
ENV WORKPATH /usr/local
WORKDIR $WORKPATH
CMD /bin/bash
(2).构建镜像 build
在构建镜像之前,先查看前面构建的 cucentos:1.0 镜像的 ID,以备在后面进行对比
docker images

构建镜像时仍然指定镜像为 cucentos:1.0,与前面的镜像完全重名
docker build -t owncentos7:1.0 .

构建完毕后,再次查看镜像,发现原来 cucentos:1.0 镜像的名称与Tag 均变为了<none>,即变为了悬虚镜像
docker images

(3).删除悬虚镜像
悬虚镜像是一种"无用"镜像,其存在只能是浪费存储空间,所以一般都是要删除的
对于悬虚镜像的删除
-
可以通过 docker rmi <imageID>进行删除外
-
通过删除命令"docker image prune"删除
该命令能够一次性删除本地全部的悬空镜像
不过有个前提就是这些悬虚镜像不能是已经启动了容器的,无论容器是否是退出状态
当然如果再加上-a选项则会同时再将没有被任何容器使用的镜像也删除
-
命令 docker system prune 也可以删除悬虚镜像
使用 docker system prune 命令可删除系统中的四类"无用"内容,其中就包含悬虚镜像dangling images
在删除这个悬虚镜像之前,首先查看其是否启动了容器,如果启动了则先将容器删除
docker ps -a

在删除了相关容器后再运行 docker image prune
docker image prune

此时再查看就发现悬虚镜像已经被删除了
docker images

4.构建自己的tomcat
(1).创建目录
创建"mytomcat"目录
mkdir -p /root/dockerfile/mytomcat
cd /root/dockerfile/mytomcat
(2).下载JDK和Tomcat
下载JDK和Tomcat的安装包并上传到"mytomcat"目录

(3).创建并编写Dockerfile文件
[root@docker mytomcat]# vim Dockerfile
#基于centos镜像
FROM centos:7
#设置作者和邮箱
LABEL name="longdidi" email="hailong2788@126.com"
#声明变量
ENV MYPATH=/usr/local/tomcat
#创建tomcat的目录
RUN mkdir -p /usr/local/java
#把tomcat和JDKcopy到/root/
ADD jdk-8u251-linux-x64.tar.gz /root/
ADD apache-tomcat-8.5.33.tar.gz /root/
#列出root目录下的所有内容
RUN ls -lh /root/
#把apache-tomcat-8.5.33修改成tomcat
RUN mv /root/apache-tomcat-8.5.33 /root/tomcat
#把tomcat 放到/usr/local/
RUN mv /root/tomcat /usr/local/
#把jdk1.8.0_181移动到/usr/local/java
RUN mv /root/jdk1.8.0_251 /usr/local/java
#设置工作目录
WORKDIR $MYPATH
#配置JAVA和tomcat环境变量
ENV JAVA_HOME=/usr/local/java/jdk1.8.0_251
ENV CLASSPATH=$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
ENV CATALINA_HOME=/usr/local/tomcat
ENV CATALINA_BASE=/usr/local/tomcat
ENV PATH=$PATH:$JAVA_HOME/bin:$CATALINA_HOME/lib:$CATALINA_HOME/bin
#设置对名暴露的端口 纯提示作用
EXPOSE 8080
#打开一个终端
CMD bin/startup.sh && tail -F logs/catalina.out
(4).构造镜像
docker build -t mytomcat:1.1.1 .

(5).运行一个容器
docker run -d -p 9999:8080 mytomcat:1.1.1

四.发布应用
通过将一个Spring Boot 应用部署到 Docker 为例来说明开发出的应用程序如何通过 Dockerfile 部署到 Docker 容器的过程
1.使用jar包做项目镜像
(1).准备jar包
创建一个项目将项目打成jar包

(2).准备目录
在宿主机中需要为应用创建一个专门的目录
该目录不仅用于存放应用的 Jar 包,还用于存放应用的 Dockerfile 文件与数据卷目录
目录名随意,一般为项目名称
本例在/root/目录下创建一个目录docker-export-test
mkdir /root/docker-export-test
cd /root/docker-export-test
将前面应用打好的 Jar 包上传到该目录

(3).编写Dockerfile文件
在/root/docker-export-test 目录中创建 Dockerfile 文件
文件内容如下
[root@docker docker-export-test]# touch Dockerfile
[root@docker docker-export-test]# chmod 777 Dockerfile
[root@docker docker-export-test]# vi Dockerfile
#openjdk的镜像
FROM openjdk:8u102
MAINTAINER zhangsan zs@163.com
LABEL version="1.0" description="my own app"
#声明工作区
ENV WORKPATH=/app
WORKDIR $WORKPATH
#把当前文件所在目录的docker-export-test-0.0.1-SNAPSHOT.jar添加到里面并改成docker.jar
COPY docker-export-test-0.0.1-SNAPSHOT.jar docker.jar
#添加容器卷
VOLUME $WORKPATH
#使用java -jar docker.jar运行
ENTRYPOINT ["java","-jar","docker.jar"]
EXPOSE 8080
(4).构造镜像
docker build -t myjarproject:1.0 .

查看镜像
docker images

(5).运行容器
docker run --name myjarproject -d -p 9080:8080 myjarproject:1.0

(6).访问
http://192.168.1.10:9080/test/testDocker

再通过 docker log 命令可查看到输出的日志
docker logs myjarproject

(7).棘手问题
有可能遇到如下问题

解决方式
-
调整主机的系统默认值
先用 ulimit -n 查看了一下, 系统默认值是1024
在 /etc/profile 中添加 ulimit -n 65535 ,然后使用 source /etc/profile 命令使配置生效
-
调整Docker下的默认值
在 /etc/systemd/system/ 目录下, 创建 docker.service.d 目录
进入该目录,创建一个文件,名为 docker.conf
在文件中加入以下配置
[Service] ExecStart= ExecStart=/usr/bin/dockerd --default-ulimit nofile=65535:65535 -H fd://重启Docker daemon
systemctl daemon-reload重启Docker 服务
systemctl restart docker
2.使用war包做项目镜像
将SpringBoot后端项目打成war包,部署到Tomcat服务器,启动后访问接口报404错误
SpringApplicationBuilder用于构建 Spring 应用,是SpringApplication和ApplicationContext实例的构建器,具有便利的流利的 API 和上下文层次结构支持
如果没有在启动类中添加SpringApplicationBuilder,tomcat将无法构建SpringBoot应用
在启动类中
-
继承
org.springframework.boot.context.web.SpringBootServletInitializer -
重写configure(SpringApplicationBuilder application)方法
package com.docker; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.builder.SpringApplicationBuilder; import org.springframework.boot.web.servlet.support.SpringBootServletInitializer; @SpringBootApplication public class MyDockerApplication extends SpringBootServletInitializer { public static void main(String[] args) { SpringApplication.run(MyDockerApplication.class, args); } @Override protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) { return builder.sources(MyDockerApplication.class); } }
(1).准备war包
创建一个项目,将项目打成war包
(2).准备目录
在宿主机中需要为应用创建一个专门的目录
该目录不仅用于存放应用的 war 包,还用于存放应用的 Dockerfile 文件与数据卷目录
目录名随意,一般为项目名称
本例在/root/目录下mkdir一个目录hello-docker-war
mkdir -p /root/hello-docker-war
cd /root/hello-docker-war
将前面应用打好的 war 包上传到该目录

(3).创建并编写Dockerfile文件
[root@docker hello-docker-war]# touch Dockerfile
[root@docker hello-docker-war]# chmod 777 Dockerfile
[root@docker hello-docker-war]# vi Dockerfile
FROM tomcat:8.5.49
##作者
MAINTAINER zhanghailong
#声明变量
ENV TOMCATPATH=/usr/local/tomcat
#设置工作目录
WORKDIR ${TOMCATPATH}/webapps
#删除工作目录里面的所有内容
RUN rm -rf *
#添加war包到webapps
COPY MyDocker-0.0.1-SNAPSHOT.war ./MyDocker.war
#改名字
RUN mv ./MyDocker.war ./ROOT.war
#创建一个ROOT文件夹
RUN mkdir ROOT
#解压war包
RUN unzip ./ROOT.war -d ./ROOT
#删除ROOT.war
RUN rm -rf ./ROOT.war
#暴露端口
EXPOSE 8080
#启动tomcat
CMD ["../bin/catalina.sh","run"]
(4).构造镜像
docker build -t mywarproject:1.0 .

(5).使用镜像运行容器测试
docker run --name mywarproject -d -p 8888:8080 mywarproject:1.0

(6).访问
http://192.168.1.10:8888/hello

五.BuildCache
Docker Daemnon 通过 Dockerfile 构建镜像时,当发现即将新构建出的镜像(层)与本地已存在的某镜像(层)重复时,默认会复用已存在镜像(层)而不是重新构建新的镜像(层),这种机制称为 docker build cache 机制
该机制不仅加快了镜像的构建过程,同时也大量节省了 Docker 宿主机的空间
docker build cache 并不是占用内存的cache,而是一种对磁盘中相应镜像层的检索、复用机制
所以无论是关闭 Docker 引擎还是重启 Docker 宿主机,只要该镜像(层)存在于本地,那么就会复用
1.测试环境构建
为了了解什么是 build cache,理解镜像构建过程中 build cache 机制,这里需要先搭建一个测试环境
-
新建 hello.log
在/root 下 mkdir 一个目录cache,在其中新建 hello.log 文件
mkdir -p /root/cache cd /root/cache/ echo "hello world" >> hello.log -
创建Dockerfile
在/root/cache 中创建一个 Dockerfile 文件,内容如下
[root@docker cache]# vim Dockerfile FROM centos:7 LABEL auth="Tom" COPY hello.log /var/log/ RUN rm -rf /etc/yum.repos.d/* \ && curl -o /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo \ && yum -y install vim \ && yum -y install net-tools \ && yum -y install wget \ && yum clean all CMD /bin/bash -
第一次构建镜像
这是使用前面的 Dockerfile 第一次构建镜像
docker build -t test:1.0 .
2.镜像的生成过程
为了了解什么是 build cache,理解镜像构建过程中 build cache 机制,需要先了解镜像的生成过程
Docker 镜像的构建过程大量应用了镜像间的父子关系
- 下层镜像是作为上层镜像的父镜像出现
- 下层镜像是作为上层镜像的输入出现
- 上层镜像是在下层镜像的基础之上变化而来
下面将针对上面的例子逐条指令的分析镜像的构建过程
-
FROM centos:7
FROM 指令是 Dockerfile 中唯一不可缺少的指令,它为最终构建出的镜像设定了一个基础镜像(Base Image)
该语句并不会产生新的镜像层,它是使用指定的镜像作为基础镜像层的
docker build 命令解析 Dockerfile 的 FROM 指令时可以立即获悉在哪一个镜像基础上完成下一条指令镜像层构建
对于本例Docker Daemon 首先从 centos:7 镜像的文件系统获取到该镜像的 ID,然后再根据镜像 ID 提取出该镜像的 json 文件内容,以备下一条指令镜像层构建时使用
-
LABEL auth=“Tom”
LABEL 指令仅修改上一步中提取出的镜像 json 文件内容,在 json 中添加 LABEL auth=“Tom”,无需更新镜像文件系统
但也会生成一个新的镜像层,只不过该镜像层中只记录了 json 文件内容的修改变化,没有文件系统的变化
如果该指令就是最后一条指令,那么此时形成的镜像的文件系统其实就是原来 FROM 后指定镜像的文件系统,只是 json 文件发生了变化
但由于 json 文件内容发生了变化,所以产生了新的镜像层
-
COPY hello.log /var/log/
COPY 指令会将宿主机中的指定文件复制到容器中的指定目录,所以会改变该镜像层文件系统大小,并生成新的镜像层文件系统内容
所以 json 文件中的镜像 ID 也就发生了变化,产生了新的镜像层
-
RUN yum -y install vim
RUN 指令本身并不会改变镜像层文件系统大小,但由于其 RUN 的命令是 yum install,而该命令运行的结果是下载并安装一个工具,所以导致 RUN 命令最终也改变了镜像层文件系统大小,所以也就生成了新的镜像层文件系统内容
所以 json 文件中的镜像 ID 也就发生了变化,产生了新的镜像层
-
CMD /bin/bash
对于 CMD 或 ENTRYPOINT 指令,其是不会改变镜像层文件系统大小的,因为其不会在docker build 过程中执行
所以该条指令没有改变镜像层文件系统大小
但对于 CMD 或 ENTRYPOINT 指令,由于其是将来容器启动后要执行的命令,所以会将该条指令写入到 json 文件中,会引发 json 文件的变化
所以 json 文件中的镜像 ID 也就发生了变化,产生了新的镜像层
3.修改 Dockerfile 后重新构建
-
修改 Dockerfile
在前面 Dockerfile 中再增加一条 EXPOSE 指令
[root@docker cache]# vim Dockerfile FROM centos:7 LABEL auth="Tom" COPY hello.log /var/log/ RUN rm -rf /etc/yum.repos.d/* \ && curl -o /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo \ && yum -y install vim \ && yum -y install net-tools \ && yum -y install wget \ && yum clean all CMD /bin/bash EXPOSE 9000 -
构建新镜像
此时再构建新的镜像test:2.0,会发现没有下载安装 vim 的过程了,但发现了很多的 Using cache
说明这是使用了 build cache
docker build -t test:2.0 .
各自查看它们的 docker history
docker history test:1.0 docker history test:2.0
发现 test:2.0 中的镜像层,除了新增加指令 EXPOSE 镜像层外,其它层完全与 test:1.0 的相同test:2.0 在构建时复用了 test:1.0 的镜像层
-
删除 test:1.0 镜像
docker rmi -f test:1.0
此时将 test:1.0 镜像删除
-
再构建新镜像
再次构建 test:3.0 镜像
发现仍然使用了大量的 build cache,就连 EXPOSE 指令镜像也使用了 build cache
docker build -t test:3.0 .
4.build cache 失效
docker build cache 在以下几种情况下会失效
(1).Dockerfile 文件发生变化
当 Dockerfile 文件中某个指令内容发生变化,那么从发生变化的这个指令层开始的所有镜像层 cache 全部失效
即从该指令行开始的镜像层将构建出新的镜像层,而不再使用 buildcache,即使后面的指令并未发生变化
因为镜像关系本质上是一种树状关系,只要其上层节点变了,那么该发生变化节点的所有下层节点也就全部变化了
(2).ADD 或 COPY 指令内容变化
Dockerfile 文件内容没有变化,但 ADD 或 COPY 指令所复制的文件内容发生了变化,同样会使从该指令镜像层开始的后面所有镜像层的 build cache 失效
(3).RUN 指令外部依赖变化
与 ADD/COPY 指令相似
Dockerfile 文件内容没有变化,但 RUN 命令的外部依赖发生了变化,例如本例中要安装的 vim 软件源发生了变更(版本变化、下载地址变化等),那么从发生变化的这个指令层开始的所有镜像层 cache 全部失效
(4).指定不使用 build cache
有些时候为了确保在镜像构建过程中使用到新的数据,在镜像构建 docker build 时,通过–no-cache 选项指定不使用 build cache
5.5.5.清理dangling build cache
dangling build cache,即悬虚 build cache,指的是无法使用的 build cache
一般为悬虚镜像 dangling image 所产生的 build cache
通过 docker system prune 命令可以清除
docker system prune
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐



所有评论(0)