跳转至

Dockerfile 指令详解

COPY 复制文件

命令格式: - COPY [--chown=<user>:<group>] <源和路径>... <目标路径> - COPY [--chown=<user>:<group>] ["<源和路径>",... "<目标路径>"]RUN 指令一样,也有两种格式,一种类似于命令行,一种类似于函数调用。

COPY 指令将从构建上下文目录中 <源路径> 的文件/目录复制到新的一层的镜像内的 <目标路径> 位置。 <源路径> 可以是多个, 甚至可以是通配符,其通配符规则要满足 Go 的 filepath.Match规则。 <目标路径> 可以是容器内的绝对路径,也可以是相对于工作目录的相对路径(工作目录可以用 WORKDIR 指令来指定)。目标路径不需要事先创建,如果目录不存在会在复制文件前先行创建缺失目录。

注意:使用 COPY 指令,源文件的各种元数据都会保留。比如读,写,执行权限,文件变更时间等。

在使用该指令的时候还可以加上 --chown=<user>:<group> 选项来改变文件的所属用户及所属组。

如果源路径为文件夹,复制的时候不是直接复制该文件夹,而是将文件夹中的内容复制到目标路径。

ADD 更高级的复制文件

ADD 指令和 COPY 的格式和性质基本一致。但是在 COPY 基础上增加来一些功能。

  1. <源路径> 可以是一个 URL,这种情况下,Docker 引擎会试图去下载这个链接的文件放到 <目标路径> 去。下载之后的文件权限自动设置为 600 ,如果这并不是想要的权限,那么还需要增加额外的一层 RUN 进行权限调整,另外,如果下载的是一个压缩包,需要解压缩,也一样还需要额外的一层 RUN 指令进行解压缩。因此,这个功能其实并不实用,不推荐使用
  2. 如果 <源路径> 为一个 tar 压缩文件的话,压缩格式为 gzipbzip2 以及 xz 的情况下,ADD 指令将会自动解压缩到 <目标路径>

在 Docker 官方的 Dockerfile 最佳实践文档 中要求,尽可能的使用 COPY,因为 COPY 的语义很明确,就是复制文件。最适合使用 ADD 的场景,就是提及的需要自动解压缩的场合。

另外需要注意的是,ADD 指令会另镜像构建缓存失效,从而可能会令镜像构建变得比较缓慢。

CMD 容器启动命令

CMD 指令的格式和 RUN 相似,也是两种格式: - shell 格式:CMD <命令> - exec 格式: CMD ["可执行文件", "参数1", "参数2"...] - 参数列表格式:CMD ["参数1","参数2"...] 。在指定了 ENTRYPOINT 指令后,用 CMD 指定具体的参数 在指令格式上,一般推荐使用 exec 格式,这类格式在解析时会被解析为 JSON 数组,因此一定要使用双引号 " , 而不要使用单引号

如果使用 shell 格式的话,实际的命令会被包装为 sh -c 的参数的形式进行执行。比如:

CMD echo $HOME
在实际执行中,会将其变更为:
CMD ["sh", "-c" "echo $HOME"]
Docker 不是虚拟机,容器中的应用都应该以前台执行,而不是虚拟机,物理机里面那样,用 systemd 去启动后台服务,容器内没有后台服务的概念。

对于容器而言,其启动程序就是容器应用进程,容器就是为了主进程而存在的,主进程退出,容器就失去了存在的意义,从而退出,其他辅助进程不是它需要关心的东西。

ENTRYPOINT 入口点

ENTRYPOINT 的格式和 RUN 指令格式一样,分为 exec 格式和 shell 格式。 ENTRYPOINT 的目的和 CMD 一样,都是在指定容器启动程序及参数。 ENTRYPOINT 在运行时也可以替代,不过比 CMD 要略显烦琐,需要通过 docker run 的参数 --entrypoint 来指定

当指定了 ENTRYPOINT 后,CMD 的含义就发生了改变,不再是直接的运行其命令,而是将 CMD 的内容作为参数传给 ENTRYPOINT 指令,换句话说实际执行时将变为:

<ENTRYPOINT> "<CMD>"

ENV 设置环境变量

格式有两种: - ENV <key> <value> - ENV <key1>=<value1> <key2>=<value2>

ENV VERSION=1.0 DEBUG=on \
    NAME="happy"

ARG 构建参数

格式: ARG <参数名>[=<默认值>] 构建参数和 ENV 的效果一样,都是设置环境变量。所不同的是,ARG 所设置的构建环境的环境变量,在将来容器运行时是不会存在这些环境变量的。docker history 还是可以看到所有值的。

Dockerfile 中的 ARG 指令是定义参数名称,以及定义其默认值。该默认值可以在构建命令 docker build 中用 --build-arg <参数>=<值> 来覆盖。 ARG指令有生效范围,如果在 FROM 指令之前指定,那么只能用于 FROM 指令中。对于多阶段构建,尤其要注意这个问题。