# COPY

**COPY有两种形式：**

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

包含空白的路径需要后一种形式。

**NOTE:**

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

**COPY指令**从拷贝新的文件或目录，将它们添加到容器文件系统的指定路径中去。

每一个可能包含通配符的路径会通过**Go**的**filepath.Match（参考ADD中的解释）**&#x89C4;则进行匹配。例如：

添加所有文件名&#x4EE5;**”hom“**&#x5F00;头的文件：

```
COPY hom* /mydir/
```

在下面的示例中，**?**&#x53EF;以被替换为任何单个字符，例&#x5982;**"home.txt"**。

```
COPY hom?.txt /mydir/
```

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

下面的示例使用相对路径，并&#x5C06;**"test.txt“**&#x6DFB;加到 **/relativeDir/**：

```
COPY test.txt relativeDir/
```

而此示例使用了绝对路径，并&#x5411;**/absoluteDir/**&#x6DFB;加&#x4E86;**"test.txt"**

```
COPY test.txt /absoluteDir/
```

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

```
COPY arr[[]0].txt /mydir/
```

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

```
COPY --chown=55:mygroup files* /somedir/
COPY --chown=bin files* /somedir/
COPY --chown=1 files* /somedir/
COPY --chown=10:11 files* /somedir/
```

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

**NOTE:**

在构建镜像时，如果通过标准输入来传递**Dockerfile（docker build - < somefile)**，则不会存在构建上下文，**COPY**将无法被使用。

**COPY**接受可选&#x7684;**--from=**&#x9009;项标志，该标志可用于将拷贝的源位置设置为先前的构建阶段（使用**FROM .. AS** 创建），该阶段将代替用户发送给**docker守护进程**的构建上下文。如果找不到具有指定名称的构建阶段，则尝试改用具有相同名称的镜像。

示例：

```
ARG VERSION=7

FROM centos:$VERSION AS centos
RUN mkdir test_dir && cd test_dir && touch file{1,2} && echo hello world > file1

FROM alpine:latest
COPY --from=centos /test_dir/file1 /tmp
CMD ["/bin/echo", "process finished"]
```

```bash
docker run -it camelgem/copy:v1 /bin/sh

liuyang@liuyangdeiMac docker % docker run -it camelgem/copy:v1 /bin/sh               
$ cd /tmp && ls
file1

# 通过上面的Dockerfile，我们将镜像centos中我们新创建的file文件,通过COPY指令的--from=<name>选项标志拷贝到了alpine镜像的文件系统中。通过--from=centos，我们将COPY指令的上下文替换为centos文件系统的目录上下文，而不是我们在命令行指定的构建上下文。
```

**COPY指令遵照以下规则：**

* **\<src>路径必须包含在构建上下文之中；不能使用COPY ../something /something, 因为docker build的第一步就是将上下文目录（及其子目录）发送给docker守护进程。**
* **如果\<src>是一个目录，整个目录的内容包括文件系统的元数据都会被拷贝到目标路径中。**

**NOTE:**

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

* 如&#x679C;**\<src>**&#x662F;任意其他类型的文件，它和它的元数据会被单独拷贝。在这种情况下，如&#x679C;**\<dest>**&#x4EE5;斜线结尾，它会被当作目录，**\<src>**&#x7684;内容会被写入&#x5230;**\<dest>/base(\<src>)**。
* 如果通过直接或使用通配符的方式指定了多&#x4E2A;**\<src>**&#x8D44;源，那&#x4E48;**\<dest>**&#x5FC5;须是一个目录，并且必须以斜线结尾。
* 如&#x679C;**\<dest>**&#x6CA1;有以斜线结尾，那么它会被当成一个正常的文件，&#x800C;**\<src>**&#x7684;内容会被写入到这个文件中。
* 如&#x679C;**\<dest>**&#x4E0D;存在，那么会在它的路径下创建所有缺失的目录。

**NOTE:**

如&#x679C;**\<src>**&#x4E2D;的内容被更改了，在构建镜像时，遇到的第一个**COPY指令**会使后续指令的缓存失效。这其中还包含了**RUN指令**的缓存。查看[**Dockerfile Best Practice guide - Leverage build cache**](https://docs.docker.com/develop/develop-images/dockerfile_best-practices/#leverage-build-cache)来获取更多信息。
