Dockerfile 文件及指令详解

什么是Dockerfile 文件

  • Dockerfile 文件是用于构建 docker 镜像的脚本文件,由一系列的指令构成。
  • 通过 docker build 命令构建镜像时,Dockerfile 文件 中的指令 会由上到下执行,每条 指令都将会构建出一个镜像层,这就是镜像的分层。
  • 因此,指令越多,层次就越多,构建的镜像就越多,效率就会越低。
    所以,在定义Dockerfile时,能在一个指令内完成的动作,就不要分为两条。

文件名

通常情况下,该文件名为 Dockerfile

docker build 构建命令

【注意】 : 命令最后有个点 . , 表示 在执行该命令的目录下 寻找 Dockerfile 文件。
这个点. 很关键。

shell 复制代码
$ 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/local
   WORKDIR $wd
   CMD ["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
相关推荐
zyu6712 小时前
03-Docker存储和网络
网络·docker·容器
牛奔12 小时前
Docker Compose 两种安装与使用方式详解(适用于 Docker 19.03 版本)
运维·docker·云原生·容器·eureka
青州从事52118 小时前
20260108【mac】【brew】【docker】安装
macos·docker·eureka
菜鸟思维19 小时前
优化NextJs 项目的Docker 镜像 从3.62G 优化到 296.85M
docker
怣疯knight20 小时前
Docker Desktop 4.55.0版本安装成功教程
windows·docker
东方佑20 小时前
使用Docker Compose一键部署OnlyOffice:完整指南与配置解析
运维·docker·容器
赵文宇(温玉)21 小时前
Docker的价值、特点、创新与关键技术
运维·docker·容器
Coder码匠1 天前
Docker Compose 部署 Spring Boot 应用完全指南
spring boot·docker·容器
可爱又迷人的反派角色“yang”1 天前
k8s(二)
linux·运维·docker·云原生·容器·kubernetes·云计算
计算机小手1 天前
内网穿透系列十六:使用 wg-easy 快速搭建基于 wireguard 的虚拟局域网,支持Docker部署
经验分享·网络协议·docker·开源软件