ADD

ADD

ADD有两种形式:

ADD [--chown=<user>:<group>] <src>... <dest>
ADD [--chown=<user>:<group>] ["<src>",... "<dest>"]

对于包含空格的路径,需要使用后一种形式。

NOTE:

--chown功能仅在用于构建Linux容器的Dockerfiles上受到支持,在Windows容器上不起作用。由于用户和组所有权概念无法在LinuxWindows之间进行转换,因此使用/etc/passwd/etc/group用户名和组名转换为ID限制了该功能,使得该功能仅适用于基于Linux OS的容器。

ADD指令从复制新文件,目录或远程文件URL,并将它们添加到镜像文件系统中的路径中。

每个都可以包含通配符,并且匹配根据Gofilepath.Match规则进行。例如:

要添加所有以"hom"开头的文件:

ADD hom* /mydir/

在下面的示例中,?可以被替换为任何单个字符,例如"home.txt"

ADD hom?.txt /mydir/

是绝对路径,或相对于WORKDIR的路径,源文件将被复制到目标容器所在文件系统的路径中。

下面的示例使用相对路径,并将"test.txt“添加到 /relativeDir/

ADD test.txt relativeDir/

而此示例使用了绝对路径,并向/absoluteDir/添加了"test.txt"

在添加包含特殊字符的文件或目录(如 [和]) 时,需要按照Golang规则对这些路径进行转义,以防止它们被视为匹配模式。例如,要添加名为arr[0].txt的文件,请使用以下文件:

附go代码示例

所有新文件和目录均以值为0UIDGID创建,除非通过可选的--chown指定用户名组名UID/GID组合,来为添加的内容指定所有权(ownership)--chown允许使用用户名组名字符串的格式,或直接使用整数形式UIDGID。如果使用不带组名用户名或不带GIDUID的形式,则会使用与UID相同的值来作为GID。如果提供了用户名组名,则会根据容器根文件系统中的/etc/passwd/etc/group文件来将用户名组名name的形式转换为整数的形式。以下示例显示了--chown的有效定义:

示例:

通过上述Dockerfile构建镜像时,会产生下面这样的错误。

虽然我们对ADD指令的定义没有任何问题,但是我们忽略了一个问题。由于我们在指令中使用的用户名和组名,以及用户ID组ID在系统中并不存在,所以构建镜像时,无法从/etc/passwd和/etc/group中找到相关记录(在Linux中创建用户时,用户的记录会被保存在/etc/passwd中,而组的记录会被保存在/etc/group文件中),因此构建失败。

如何解决上述问题?

通过在ADD指令之前,创建好ADD指令所需的用户和组,就能够解决上述问题。这里我们通过RUN指令来执行这些创建任务。

如果容器的根文件系统不包含/etc/passwd/etc/group文件,并且以用户组名的形式使用--chown,那么关于ADD构建的操作将会失败。使用数值ID形式的用户,则不需要查询且不会去依赖容器根文件系统的内容。

如果是一个URL形式的远端文件,目标文件将拥有600的文件权限。如果被检索的远端文件拥有一个HTTP Last-Modified头部,那么来自头部的时间戳将被用于设置目标文件的mtime。然而,像在ADD期间被处理的任意其他文件那样,mtime不会被用来决定文件是否被更改和缓存是否应该被更新。

NOTE:

在构建镜像时,如果通过标准输入来传递Dockerfile(docker build - < somefile),则不会存在构建上下文,因此Dockerfile中只能使用基于URLADD指令。我们也可以通过标准输入传递一个压缩文件:(docker build - < archive.tar.gz), 在压缩文件根目录下的Dockerfile和余下的一些文件将被作为构建上下文。

如果URL文件需要进行身份认证,那么我们需要使用RUN wgetRUN curl或者使用容器内部的其他工具来获取文件,因为ADD指令不支持身份认证功能。

NOTE:

如果<src>中的内容被更改了,在构建镜像时,遇到的第一个ADD指令会使后续指令的缓存失效。这其中还包含了RUN指令的缓存。查看Dockerfile Best Practice guide - Leverage build cache来获取更多信息。

ADD指令遵照以下规则:

  • <src>路径必须包含在构建上下文之中;不能使用ADD ../something /something, 因为docker build的第一步就是将上下文目录(及其子目录)发送给docker守护进程。

  • 如果<src>是一个URL,并且<dest>并没有以斜线结尾,那么将会从URL下载一个文件然后拷贝<dest>。

  • 如果<src>是一个URL,并且<dest>以斜线结尾,那么docker会根据URL推断出文件名,然后文件会下载到<dest>/<filename>。例如,ADD http://example.com/foobar / 将创建一个/foobar文件。URL必须包含一个资源路径,以便可以通过这个路径找到适当的文件名。(http://example.com将无法执行)。

NOTE:

目录本身并不会被拷贝,仅仅只是拷贝目录中的内容。

  • 如果<src>是一个能够被识别的本地压缩文件(例如identitygzipbzip2xz),那么它会被解压成一个目录。来自远端URL的资源无法被解压。当一个目录被拷贝或者解压时,它与tar -x命令有着相同的行为。

NOTE:

文件是否被识别为压缩格式的文件仅基于文件的内容,而不是文件的名称。例如,如果一个空文件碰巧以.tar.gz结尾,这个文件不会被识别为压缩文件,也不会生成任何类型的减压错误消息,而是将这个文件简单地复制到目的地。

  • 如果<src>是任意其他类型的文件,它和它的元数据会被单独拷贝。在这种情况下,如果<dest>以斜线结尾,它会被当作目录,<src>的内容会被写入到<dest>/base(<src>)

  • 如果通过直接或使用通配符的方式指定了多个<src>资源,那么<dest>必须是一个目录,并且必须以斜线结尾。

  • 如果<dest>没有以斜线结尾,那么它会被当成一个正常的文件,而<src>的内容会被写入到这个文件中。

  • 如果<dest>不存在,那么会在它的路径下创建所有缺失的目录。

Last updated

Was this helpful?