什么是Dockerfile 文件
Dockerfile 文件
是用于构建 docker 镜像的脚本文件,由一系列的指令
构成。- 通过
docker build
命令构建镜像时,Dockerfile 文件中的指令会由上到下执行,每条 指令都将会构建出一个镜像层,这就是镜像的分层。- 因此,指令越多,层次就越多,构建的镜像就越多,效率就会越低。
所以,在定义Dockerfile时,能在一个指令内完成的动作,就不要分为两条。
文件名
通常情况下,该文件名为
Dockerfile
docker build 构建命令
【注意】 : 命令最后有个点
.
, 表示 在执行该命令的目录下 寻找Dockerfile
文件。
这个点.
很关键。
$ docker build -t 镜像名称:tag .
指令
基本介绍
- 指令大小写不敏感,但习惯上全用大写;
- 指令后至少会携带一个参数;
#
号开头的,表示这一行是注释行。
FROM 指令
语法 :
FROM <image>[:tag]
例如 : FROM centos:7.9.2009
作用 :指定构建新镜像所基于的基础镜像。
* 必须为 Dockerfile 文件的第一条。
* 若 镜像的标签 tag 不写的话,默认就是 latest。
* 若 镜像本地没有的话,会先执行下载。
补充 : 一个scratch 镜像。
* scratch 镜像是一个空镜像,是所有镜像的 Base 镜像。
* scratch 镜像只能在Dockerfile 中被继承,不能pull拉取,不能run,也没有tag。
* scratch 是一个保留字,用户不能作为自己的镜像名称使用。
* 使用 scratch 作为基础镜像意味着你从零开始构建你的镜像,没有预装任何文件、库或运行时环境。
* 这通常用于创建极其精简的容器镜像,尤其是对于静态编译的二进制文件来说非常有用。
MAINTAINER 指令
语法 :
MAINTAINER 作者名字 作者邮箱
例如 : MAINTAINER northcastle norcastle@123.com
作用 : 标注镜像维护者的姓名和邮箱。
但是,官方现在已经不推荐使用此指令,而是用 【LABEL】 指令代替。
LABEL 指令
语法 :
LABEL key1=value1 key2=value2 ...
例如 : LABEL author=northcastle email=northcastle@123.com
作用 : 给镜像添加元数据(metadata)。
特点 : 以键值对的方式定义,可以自定义任何的信息;信息会被包含在镜像的json文件中。
查看 : 通过 docker inspect 命令查看镜像元信息时可以查看到自定义的内容。
RUN 指令
语法1 :
RUN shell-command
例如 : RUN yum install -y vim
语法2 :
RUN ["executable", "param1", "param2", ...]
例如 : RUN [“yum”,“install”,“-y”,“vim”]
作用 : 在基于当前构建阶段的镜像上执行命令,并将执行的结果(包括文件系统的变化)保存为新的镜像层。
补充 : 基于 centos 构建镜像时,使用 yum 命令报错的解决方案
在Dockerfile 中添加如下内容:RUN cd /etc/yum.repos.d/
RUN sed -i 's/mirrorlist/#mirrorlist/g' /etc/yum.repos.d/CentOS-*
RUN sed -i 's|#baseurl=http://mirror.centos.org|baseurl=http://vault.centos.org|g' /etc/yum.repos.d/CentOS-*
RUN yum makecache
RUN yum update -y但是,上述方案有一个缺点:镜像层太大了,非常的臃肿。
WORKDIR 指令
语法 :
WORKDIR 工作路径
例如 : WORKDIR /usr/local
作用 : 为容器内的文件系统设置一个基础目录,使得后续命令可以基于此目录进行操作。
特点 :* 如果指定的目录不存在,WORKDIR 会自动创建该目录。* 这个目录会被用作所有 RUN、CMD、ENTRYPOINT、COPY 和 ADD 指令的上下文路径。* 可以写多个 WORKDIR 指令。* 当写多个时,第一个为绝对路径,后续用相对路径会基于第一个的绝对路径。* docker run 的 -w 参数 可以覆盖这个指令置顶的默认工作目录。
ENV 指令
语法1 :
ENV key value
单个定义
语法2 :ENV key1=value1 key2=value2 ...
同时定义多个
作用:定义环境变量。1、在Dockerfile 中可以被后续的指令直接引用,减少重复代码。2、运行容器时,可以通过 -e 参数动态的传入环境变量的值,从而使配置更加灵活。例如:ENV wd=/usr/localWORKDIR $wdCMD ["sh","-c","echo $wd"]下面是运行容器时覆盖的例子:
* 只有一个环境变量需要覆盖时:
docker run --name xxx -e wd=xxx -it imageName:tag* 当有多个需要覆盖时,就写 多个 -e k1=v1 -e k2=v2
docker run --name xxx -e wd=xxx -e wd2=xxx -e wd3=xxx ... -it imageName:tag
注意 :
-e 参数,并不是所有情况下都能生效。
只有是与容器相关的才会生效,例如 CMD 指令是容器运行的程序入口,会生效。
但 WORKDIR 指令是在构建镜像的时候用,这个对于容器来说就不会生效。
ARG 指令
语法 :
ARG 变量名[=默认值]
作用 : 定义在构建过程中使用的变量。
使用方式 :
* 如果有多个变量,则需要写`多个ARG` 指令即可;
* 可以出现在FROM 指令之前,常用于指定 FROM 的基础镜像的版本;
* ARG 定义的变量只能在构建阶段生效,容器运行后不可用。
* 构建时 使用 【--build-arg 变量名=值】 的方式 指定 变量的值,如果有多个变量,则重复写多个即可。例如 Dockerfile 如下 :
FROM centos:centos7.9.2009
ARG wd=/usr # 定义变量
WORKDIR $wd
CMD ["/bin/bash"]构建命令 :
docker build -t mycentos:1.0 --build-arg wd=/usr/local .
此命令即将 变量 wd 的值覆盖成 [/usr/local]
ADD 指令
语法1 :
ADD src dest
语法2 :ADD ["src","dest"]
作用: 将 构建上下文中的 文件/目录(src) 复制到 容器中指定的路径中 (dest)。注意:
* src 可以是URL,会自动下载该路径的资源并添加到镜像中;
* src 可以是压缩文件,复制到容器中后会自动解压;
* src 可以是目录,但不建议是目录,因为会把该目录下所有的内容全都复制到镜像中;
* dest 是一个绝对路径,最后要添加上斜杠[/],表示 一个目录;
* dest 如果没有[/] 则表示将原文件 复制到容器中并重命名为 dest 的名称。例如 :
ADD hello.java /usr/local/javafile/
将 Dockerfile 文件所在目录下的 hello.java 文件 复制到 镜像的 /usr/local/javafile/ 目录下。
特别注意:
【构建上下文限制】:* 当您构建一个 Docker 镜像时,您通过 docker build 命令指定一个构建上下文(通常是包含 Dockerfile 的目录)。* Docker 客户端会将这个上下文发送给 Docker 守护进程,这意味着 ADD 和 COPY 指令只能访问该上下文内的文件。* 因此,虽然 <src> 可以采用相对路径形式来指向上下文内的文件或目录,但它不能直接引用上下文之外的绝对路径。【相对路径 vs 绝对路径】:
* 在 Dockerfile 中,ADD 指令的 <src> 参数通常使用相对于构建上下文的路径。
* 如果您尝试提供一个位于构建上下文外部的绝对路径,比如 /home/user/file.txt,Docker 将无法找到该文件,并导致构建失败。
COPY 指令
语法1 :
COPY src dest
语法2 :COPY ["src","dest"]
作用 :从主机的文件系统中复制文件或目录到 Docker 镜像中的指定位置。注意 :
* 不支持自动解压缩 tar 文件;
* 不支持从 URL 下载文件;
* 行为单一,推荐使用。例如 :
COPY . /usr/loca/hostfile/
将 构建上下文 目录中的所有文件 全都复制到 /usr/local/hostfile/ 目录中去COPY f1 f2 f3 /usr/local/files/
COPY ["f1","f2","f3","/usr/local/files/"]
支持写多个文件,中间用空格隔开。COPY *.txt /usr/local/allfiles/
支持通配符 *
EXPOSE 指令
语法1 :
EXPOSE port1 port2 ...
默认以 TCP 协议的方式 声明端口号 (可以写多个)
语法2 :EXPOSE port/protocol ...
以 指定protocol协议的方式 声明端口号 (可以写多个)
作用 : 声明容器运行时监听的网络端口。
注意 :
* 它并不直接将端口暴露给主机,而是作为一种文档化手段,告知使用者该容器希望在运行时开放哪些端口。
* 真正的端口映射 需要在 docker run 时 通过 -p 参数指定
* 例如 : docker run --name t1 -p 8081:8080 -d tomcat:8.5.49
* 将主机端口 8081 与 容器端口 8080 进行映射,这样访问主机的 8081 端口即可访问到容器的 8080端口。
CMD 指令(*)
作用:
【提供默认的容器启动命令】:当用户没有通过 docker run 命令指定任何命令时,将使用 CMD 提供的默认命令来启动容器。
【为 ENTRYPOINT 提供默认参数】:如果 Dockerfile 中同时定义了 ENTRYPOINT 和 CMD,那么 CMD 的值会被作为参数传递给 ENTRYPOINT。这种组合非常强大,因为它允许你创建一个具有固定入口点(如脚本或应用)的基础镜像,并且允许最终用户覆盖默认参数而不必重新定义整个命令。
语法1 :
CMD command param1 param2...
例如 :CMD cal -y 2005
command
是 shell 命令, 会在 /bin/sh -c 中运行命令,这意味着它会在一个 shell 环境中执行。
会被 docker run 后面的 命令覆盖,但不支持拼接 ducker run 后面的参数。
语法2 :
CMD ["executable","param1","param2" ...]
例如:CMD [“cal”,“-y”,“2005”]
executable
是可执行文件的路径,后面的是参数;
会被 docker run 后面的 命令覆盖,但不支持拼接 ducker run 后面的参数。
语法3 :
CMD ["param1","param2",...]
例如:
ENTRYPOINT [“echo”]
CMD [“hello”,“world”]
给ENTRYPOINT
指令中声明的 可执行脚本 提供默认参数,
会被 docker run 命令后面的 参数完全覆盖,不支持拼接参数。
ENTRYPOINT 指令(*)
作用:配置容器启动时要运行的命令。
* 并且这个命令不容易被覆盖,除非显式地使用 --entrypoint 标志。
与 CMD 指令结合使用时,ENTRYPOINT 可以提供固定的入口点,而 CMD 则可以用来指定默认参数,这些参数可以在运行容器时被用户提供的参数覆盖。
语法1 :
ENTRYPOINT command param1 param2...
例如 :ENTRYPOINT cal -y 2005
command
是 shell 命令, 会在 /bin/sh -c 中运行命令,这意味着它会在一个 shell 环境中执行。
会被 docker run 后面的 命令覆盖,但不支持拼接 ducker run 后面的参数。
语法2 :
ENTRYPOINT ["executable","param1","param2" ...]
例如:ENTRYPOINT [“cal”,“-y”,“2005”]
executable
是可执行文件的路径,后面的是参数;
支持 docker run 后面的参数 与 executable 命令进行拼接。
【组合
CMD
指令一起使用 】:
例如:
ENTRYPOINT [“echo”]
CMD [“hello”,“world”]
给ENTRYPOINT
指令中声明的 可执行脚本 提供默认参数,
会被 docker run 命令后面的 参数完全覆盖,不支持拼接参数。
CMD & ENTRYPOINT 的小结
ONBUILD 指令
语法 :
ONBUILD [INSTRUCTION]
[INSTRUCTION]
:可以是任何有效的 Dockerfile 指令,如RUN, COPY, ADD, ENV,
等等。
但 ONBUILD 不支持FROM, MAINTAINER, ONBUILD
这几个指令作为其参数。
例如 : ONBUILD RUN yum installl -y vim
作用 :
* 在当前镜像被用作其他镜像的基础镜像时,触发特定的操作。
* 当一个镜像(我们称它为父镜像)包含 ONBUILD 指令,并且另一个 Dockerfile 使用这个父镜像作为基础镜像(通过 FROM 指令),那么在执行 FROM 指令后,立即触发并执行该父镜像中定义的所有 ONBUILD 后面的指令。
VOLUME 指令
语法1 :
VOLUME container_path
语法2 :VOLUME ["container_path1","container_path2"...]
作用 : 在容器内定义多个持久化的挂载点,用于数据的持久化。但是,这种方式并不能指定宿主机上对应的持久化目录。查看 : 通过 [docker inspect 容器ID] 命令,可以查看容器的详细信息,其中,有一个 Mounts 数组,可以查看到对应的持久化数据卷的详细信息。
补充 :
更推荐使用docker run --name c1 -v host_path:container_path image:tag
中的-v
参数的方式进行数据卷的挂载。
这种方式更直观。
build cache
概述
Docker Daemon
通过Dockerfile
构建镜像时,当发现即将新构建出的镜像层与本地已经存在的某个镜像层重复时,默认会复用已经存在的镜像层。这种机制称为docker build cache 机制
。- 此机制不仅加快了镜像的构建过程,同时也大量节省了Docker宿主机的空间。
docker build cache
并不是占用内存的 cache,而是一种对磁盘中相应镜像层的检索复用机制。所以无论是关闭Docker引擎,还是重启Docker宿主机,只要该镜像层存在就会复用。
失效的情况
1、Dockerfile 本身发生了变化 : 从发生变化指令开始,后面的所有指令层全部失效。(因为后面的是基于前面的层)
2、Dockerfile 文件内容未变,但是 ADD/COPY 指令所添加/复制的源文件发生了变化,则后续的全部失效。(即文件系统变了)
3、RUN 指令的外部依赖发生改变。(也是相当于文件系统变了)
4、明确指定不使用 build cache [--no-cache 参数]构建命令 :docker build --no-cache -t xxx:tag清理cache : docker system prune