目录
摘要:本文全面介绍了 Dockerfile 的核心概念与使用方法。Dockerfile 是一个用于自动化构建 Docker 镜像的文本文件,通过一系列指令定义镜像的每一层。相较于 docker commit,使用 Dockerfile 构建镜像更加标准化、可重复且易于维护。文章详细讲解了 docker build 命令的使用,并逐一剖析了 FROM、RUN、COPY、ADD、CMD、ENTRYPOINT、ENV、WORKDIR、VOLUME 等关键指令的语法、功能及实战示例,是掌握 Docker 镜像定制与构建的实用指南。
Dockerfile 是什么
镜像的定制实际上就是定制每一层所添加的配置、文件。如果我们可以把每一层修改、安装、构建、操作的命令都写入一个脚本,用这个脚本来构建、定制镜像,这个脚本就Dockerfile
Dockerfile 是一个文本文件,其内包含了一条条的指令(Instruction),每一条指令构建一层,因此每一条指令的内容,就是描述该层应当如何构建。
为什么需要Dockerfile
可以按照需求自定义镜像:
可以和docker commit 一样能够自定义镜像,官方的镜像可以说很少能直接满足我们应用的,都需要我们自己打包自己的代码进去然后做成对应的应用镜像对外使用。
很方便的自动化构建,重复执行:
通过 dockerfile 可以自动化的完成镜像构建,而不是像 docker commit 一样,手动一个命令一个命令执行,而且可以重复执行,docker commit 的话很容易忘记执行了哪个命令,哪个命令没有执行。
维护修改方便,不再是黑箱操作:
使用 docker commit 意味着所有对镜像的操作都是黑箱操作,生成的镜像也被称为黑箱镜像,dockerfile 很容易二次开发。
更加标准化,体积可以做的更小:
docker 容器启动后,系统运行会生成很多运行时的文件,如果使用 commit 会导致这些文件也存储到镜像里面,而且 commit 的时候安装了很多的依赖文件,没有有效的清理机制的话会导致镜像非常的臃肿。使用 Dockerfile 则会更加标准化,而且提供多级构建,将编译和构建分开,不会有运行时的多余文件,更加的标准化。
制作指令build
docker build
功能
docker build 命令用于使用 Dockerfile 创建镜像。
语法
docker build [OPTIONS] PATH | URL | -
关键参数
--build-arg=[] :设置镜像创建时的变量;
-f :指定要使用的 Dockerfile 路径;
--label=[] :设置镜像使用的元数据;
--no-cache :创建镜像的过程不使用缓存;
--pull :尝试去更新镜像的新版本;
--quiet, -q :安静模式,成功后只输出镜像 ID;
--tag, -t: 镜像的名字及标签,通常 name:tag 或者 name 格式;可以在一次构建中为一个镜像设置多个标签。
--network: 默认 default。在构建期间设置 RUN 指令的网络模式
Dockerfile指令
指令清单
| 指令 | 功能 |
| FORM | 指定构建镜像的基础镜像 |
| MAINTAINER | 镜像制作者的姓名或邮箱 |
| LABEL | 为镜像添加元数据(标签) |
| COPY | 从宿主机拷贝文件到镜像,不具备自动解压和解析URL |
| ADD | 从宿主机拷贝文件到镜像,具备自动解压和解析URL |
| WORKDIR | 修改工作目录 |
| RUN | 指定docker build 过程中运行的指令 |
| VOLUME | 指定容器挂载点 |
| EXPOSE | 声名容器暴露的端口 |
| ENV | 添加环境变量 |
| CMD | 运行容器时执行的命令 |
| ENTRYPOINT | 容器启动时执行的命令 |
| ARG | 指定构建是的参数或变量 |
| SHELL | 指定采用那个shell |
| USER | 指定用户 |
| HEALTHCHECK | 健康检测 |
| ONBUILD |
在当前镜像构建时并不会被执行。只有当以当前镜像为基础镜像,去构建下一级镜像的时候才会被执行
|
| STOPSIGNAL |
允许您覆盖发送到容器的默认信号
|
指令详解
FROM
功能:
FROM 指令用于为镜像文件构建过程指定基础镜像,后续的指令运行于此基础镜像所提供的运行环境中;
注意事项:
- FROM 指令必须是 Dockerfile 中非注释行或者 ARG 之后的第一个指令;
- 实践中,基准镜像可以是任何可用镜像文件,默认情况下,docker build 会在docker 主机上查找指定的镜像文件,在其不存在时,则会自动从 Docker 的公共库 pull 镜像下来。如果找不到指定的镜像文件,docker build 会返回一个错误信息;
- FROM 可以在一个 Dockerfile 中出现多次,如果有需求在一个 Dockerfile 中创建多个镜像,或将一个构建阶段作为另一个的依赖。
- 如果 FROM 语句没有指定镜像标签,则默认使用 latest 标签。
语法:
FROM [--platform=<platform>] <image> [AS <name>]
FROM [--platform=<platform>] <image>[:<tag>] [AS <name>]
FROM [--platform=<platform>] <image>[@<digest>] [AS <name>]
参数:
<platform>:构建的 cpu 架构,如 linux/amd64, linux/arm64, windows/amd64
<image>:指定作为 base image 的名称;
<tag>:base image 的标签,省略时默认 latest;
<digest>:是镜像的哈希码;
AS <name>: 指定构建步骤的名称,配合 COPY --from=<name>可以完成多级构建
实战演示:
编写Dockerfile脚本,以centos:7为基础镜像

使用docker build命令构建:

查看容器是否存在:

运行testv0.1容器,查看操作系统版本:

MAINTAINER
功能:
- 用于让 dockerfile 制作者提供本人的详细信息
- 该功能已经废弃,由 label 替代
语法:
MAINTAINER <authtor's detail>
参数:
<authtor's detail>:作者信息
实战演示:
编写docker file脚本:

可以看到会提示我们的MAINTAINER以及废弃了

构建成功:

查看是否存在作者信息:

LABEL
功能 :
为镜像添加元数据,元数据是 kv 对形式
语法:
LABEL <key>=<value> <key>=<value> <key>=<value>
实战演示:
编写dockerfile脚本

查看结果:

COPY
功能:
用于从 docker 主机复制新文件或者目录至创建的新镜像指定路径中 。
语法:
COPY [--chown=<user>:<group>] <src>... <dest>
COPY [--chown=<user>:<group>] ["<src>",... "<dest>"]
参数:
- <src>:要复制的源文件或目录,支持使用通配符;
- <dest>:目标路径,即正在创建的 image 的文件系统路径;建议<dest>使用绝对路径,否则,COPY 指定以 WORKDIR 为当前路径,在路径中有空白字符时,通常使用第 2 种格式;
- --chown:修改用户和组
- --from <name>(可选项) : 可以从之前构建的步骤中拷贝内容,结合 FROM .. AS <name>往往用作多级构建
注意事项:
- <src>必须是 build 上下文中的路径,不能是其父目录中的文件;如果<src>是目录,则其内部文件或子目录会被递归复制,但<src>目录自身不会被复制
- 如果指定了多个<src>,或在<src>中使用了通配符,则<dest>必须是一个目录,且必须以 / 结尾;
- 如果<dest>事先不存在,它将会被自动创建,这包括父目录路径。
实战演示:
编写脚本:

编写一个测试文本:

进行build 构建:

查看结果:

ENV
功能:
- 用于为镜像定义所需的环境变量,并可被 Dockerfile 文件中位于其后的其它指令(如 ENV、ADD、COPY 等)所调用
- 调用格式为$variable_name 或 ${variable_name}
语法:
ENV <key>=<value> ...
实战演示:
编写dockerfile脚本:

利用docker build 构建:

查看容器环境变量:

WORKDIR
功能:
为 Dockerfile 中所有的 RUN、CMD、ENTRYPOINT、COPY 和 ADD 指定工作目录
语法:
WORKDIR /path/to/workdir
注意事项:
- 默认的工作目录是/
- 如果提供了相对路径,它将相对于前一条 WORKDIR 指令的路径。
- WORKDIR 指令可以解析先前使用设置的环境变量 ENV
实战演示:
编写dockerfile脚本:

构建容器:

查看结果:

ADD
功能:
语法:
ADD [--chown=<user>:<group>] <src>... <dest>ADD [--chown=<user>:<group>] ["<src>",... "<dest>"]
参数:
- <src>:要复制的源文件或目录,支持使用通配符;
- <dest>:目标路径,即正在创建的 image 的文件系统路径;建议<dest>使用绝对路径,否则,ADD 指定以 WORKDIR 为其实路径;在路径中有空白字符时,通常使用第 2 种格式;
- --chown:修改用户和组
实战演示:
编写Dockerfile脚本:

查看结果:URL地址成功下载

下面我们来测试自动解压功能:
编写Dockerfile脚本

查看结果:

RUN
功能:
用于指定 docker build 过程中运行的程序,其可以是任何命令
语法:
RUN <command>
RUN ["executable", "param1", "param2"]
参数:
第一种格式中,<command>通常是一个 shell 命令, 且以“/bin/sh -c”来运行它,Windows 默认为 cmd /S /C。如果一个脚本 test.sh 不能自己执行,必须要 /bin/sh -c test.sh 的方式来执行,那么,如果使用 RUN 的 shell 形式,最后得到的命令相当于:
/bin/sh -c "/bin/sh -c 'test.sh'"
第二种语法格式中的参数是一个 JSON 格式的数组,其中<executable>为要运行的命令,后面的 <paramN>为传递给命令的选项或参数;然而,此种格式指定的命令不会以“/bin/sh -c”来发起,因此常见的 shell 操作如变量替换以及通配符(?,*等)替换将不会进行;不过,如果要运行的命令依赖于此 shell 特性的话,可以将其替换为类似下面的格式。 RUN ["/bin/bash", "-c", "<executable>", "<param1>"]
实战演示:
利用RUN命令解压我们的nginx压缩包
编写Dockerfile脚本:

查看结果:

CMD
功能:
- 类似于 RUN 指令,CMD 指令也可用于运行任何命令或应用程序,不过,二者的运行时间点不同 ,RUN 指令运行于映像文件构建过程中,而 CMD 指令运行于基于 Dockerfile构建出的新映像文件启动一个容器时
- CMD 指令的首要目的在于为启动的容器指定默认要运行的程序,且其运行结束后,容器也将终止;不过,CMD 指定的命令其可以被 docker run 的命令行选项所覆盖
- 在 Dockerfile 中可以存在多个 CMD 指令,但仅最后一个会生效
语法:
CMD ["executable","param1","param2"] (exec form, this is the preferred form)
CMD ["param1","param2"] (as default parameters to ENTRYPOINT)
CMD command param1 param2 (shell form)
注意事项:
- 第二种则用于为 ENTRYPOINT 指令提供默认参数
- json 数组中,要使用双引号,单引号会出错
实战演示:
编写shell脚本:让nginx在前台运行

查看是否运行成功:

EXPOSE
功能:
用于为容器声明打开指定要监听的端口以实现与外部通信 ,该 EXPOSE 指令实际上并不发布端口。它充当构建图像的人和运行容器的人之间的一种文档,关于要发布哪些端口。要在运行容器时实际发布端口,使用-p 参数发布和映射一个或多个端口,或者使用-Pflag 发布所有暴露的端口并将它们映射宿主机端口。
语法 :
EXPOSE <port> [<port>/<protocol>...]
参数:
<protocol>:tcp/udp 协议
<port>:端口
ENTRYPOINT
功能:
用于指定容器的启动入口
语法
#exec from
ENTRYPOINT ["executable", "param1", "param2"]
# shell form
ENTRYPOINT command param1 param2
注意:
json 数组中,要使用双引号,单引号会出错
实战演示:
将CMD替换为ENTRYPOINT

启动容器我们依旧可以访问nginx

ARG
功能:
- ARG 指令类似 ENV,定义了一个变量;区别于来说 ENV:ARG可以在构建时 docker build --build-arg <varname> = <value> 进行对变量的修改而ENV 不可以
- 如果用户指定了未在 Dockerfile 中定义的构建参数,那么构建输出警告。
语法:
ARG <name>[=<default value>]
注意事项:
Dockerfile 可以包含一个或多个 ARG 指令
ARG 支持指定默认值
使用范围:定义之后才能使用,定义之前为空,如下面的案例,执行命令 docker build --build-arg username=what_user .第二行计算结果为 some_user ,不是我们指定的 build-arg 中的参数值 what_user
FROM busybox
USER ${username:some_user}
ARG username
USER $username
ENV 和 ARG 同时存在,ENV 会覆盖 ARG
FROM ubuntu
ARG CONT_IMG_VER
ENV CONT_IMG_VER=v1.0.0
RUN echo $CONT_IMG_VER
执行下面指令输出 v1.0.0
docker build --build-arg CONT_IMG_VER=v2.0.1 .
我们可以优化写法为
FROM ubuntu
ARG CONT_IMG_VER
ENV CONT_IMG_VER=${CONT_IMG_VER:-v1.0.0}
RUN echo $CONT_IMG_VER
系统内置了一些 ARG 变量
- HTTP_PROXY
- http_proxy
- HTTPS_PROXY
- https_proxy
- FTP_PROXY
- ftp_proxy
- NO_PROXY
- no_proxy
- ALL_PROXY
- all_proxy
实战演示:
可以利用ARG来控制我们的版本

VOLUME
功能:
-
用于在 image 中创建一个挂载点目录
-
通过 VOLUME 指令创建的挂载点,无法指定主机上对应的目录,是自动生成的。
语法:
VOLUME <mountpoint>
VOLUME ["<mountpoint>"]
参数:
mountpoint : 挂载点目录
注意事项:
- 如果挂载点目录路径下此前有文件存在,docker run 命令会在卷挂载完成后将此前的所有文件复制到新挂载的卷中
- 其实 VOLUME 指令只是起到了声明了容器中的目录作为匿名卷,但是并没有将匿名卷绑定到宿主机指定目录的功能
- volume 只是指定了一个目录,用以在用户忘记启动时指定-v 参数也可以保证容器的正常运行。比如 mysql,你不能说用户启动时没有指定-v,然后删了容器,就把 mysql 的数据文件都删了,那样生产上是会出大事故的,所以 mysql 的 dockerfile 里面就需要配置 volume,这样即使用户没有指定-v,容器被删后也不会导致数据文件都不在了。还是可以恢复的
- volume 与-v 指令一样,容器被删除以后映射在主机上的文件不会被删除
- 如果-v 和 volume 指定了同一个位置,会以-v 设定的目录为准,其实volume 指令的设定的目的就是为了避免用户忘记指定-v 的时候导致的数据丢失,那么如果用户指定了-v,自然而然就不需要 volume 指定的位置了
实战演示:
编写dockerfile脚本:

启动容器查看结果:

SHELL
功能:
-
SHELL 指令允许覆盖用于 shell 命令形式的默认 shell。
-
Linux 上的默认 shell 是["/bin/sh","-c"],在 Windows 上是["cmd","/S", "/C"]
-
SHELL 指令必须以 JSON 格式写入 Dockerfile
语法:
SHELL ["executable", "parameters"]
参数:
executable:shell 可执行文件的位置
parameters:shell 执行的参数
注意事项:
- SHELL 指令可以多次出现。
- 每个 SHELL 指令都会覆盖所有先前的 SHELL 指令,并影响所有后续指令
- 该 SHELL 指令在 Windows 上特别有用,因为 windows 行有两种不同的shell:cmd 和 powershell
实战演示:
编写dockerfile脚本:

查看运行结果:

USER
功能:
- 用于指定运行 image 时的或运行 Dockerfile 中任何 RUN、CMD 或 ENTRYPOINT 指令定的程序时的用户名或 UID
-
默认情况下,container 的运行身份为 root 用户
语法:
USER <user>[:<group>]
USER <UID>[:<GID>]
参数:
- user:用户
- group:用户组
- uid:用户 id
- gid:组 id
实战演示:
编写dockerfile脚本:

查看结果:

HEALTHCHECK
功能:
- HEALTHCHECK 指令告诉 Docker 如何测试容器以检查它是否仍在工作。
- 即使服务器进程仍在运行,这也可以检测出陷入无限循环且无法处理新连接的 Web 服务器等情况。
语法:
HEALTHCHECK [OPTIONS] CMD command (check container health by running a command inside the container)
HEALTHCHECK NONE (disable any healthcheck inherited from the base image)
参数:
OPTIONS 选项有:
- --interval=DURATION (default: 30s):每隔多长时间探测一次,默认 30 秒
- -- timeout= DURATION (default: 30s):服务响应超时时长,默认 30 秒
- --start-period= DURATION (default: 0s):服务启动多久后开始探测,默认 0 秒
- --retries=N (default: 3):认为检测失败几次为宕机,默认 3 次
返回值:
- 0:容器成功是健康的,随时可以使用
- 1:不健康的容器无法正常工作
- 2:保留不使用此退出代码
实战演示:
编写dockerfile脚本

查看结果:发现结果确实是健康状态

ONBUILD
功能
- 用于在 Dockerfile 中定义一个触发器
- 以该 Dockerfile 中的作为基础镜像由 FROM 指令在 build 过程中被执行时,将会“触发”创建其 base image 的 Dockerfile 文件中的 ONBUILD 指令定义的触发器
语法
ONBUILD <INSTRUCTION>
参数:
INSTRUCTION : dockerfile 的一条指令
STOPSIGNAL
功能:
-
STOPSIGNAL 指令设置发送到容器的系统调用信号。
-
此信号可以是与内核的系统调用表中的位置匹配的有效无符号数,例如 9, 或者 SIGNAME 格式的信号名,例如 SIGKILL。
语法:
STOPSIGNAL signal
参数:
STOPSIGNAL 指令设置将发送到容器出口的系统调用信号。 此信号可以是与内核的系统调用表中的位置匹配的有效无符号数,例如 9,或者 SIGNAME 格式的信号名,例如 SIGKILL。常见的信号如下:
SIGHUP:1
启动被终止的程序,可让该进程重新读取自己的配置文件,类似重新启动。
SIGINT :2
相当于用键盘输入 [ctrl]-c 来中断一个程序的进行。
SIGKILL:9
代表强制中断一个程序的进行,如果该程序进行到一半, 那么尚未完成的部分可能会有“半产品”产生,类似 vim 会有 .filename.swp 保留下来。
SIGTERM:19
以正常的方式来终止该程序。由于是正常的终止,所以后 续的动作会将他完成。不过,如果该程序已经发生问题, 就是无法使用正常的方法终止时,输入这个 signal 也是没有用的。
SIGSTOP:19
相当于用键盘输入 [ctrl]-z 来暂停一个程序的进行

1706

被折叠的 条评论
为什么被折叠?



