我正在运行一个带有两个 COPY 语句的 Dockerfile:
WORKDIR /app
COPY requirements.txt entrypoint.sh ./
COPY binaries/ ./binaries
它工作正常,我最终得到了我需要的东西:
root:/# ls /app
requirements.txt
entrypoint.sh
binaries/
├── executable1
├── executable2
└── executable3
但我想保持尽可能少的层数,因此我尝试将两个 COPY 语句合并为一个:
WORKDIR /app
COPY requirements.txt entrypoint.sh binaries/ ./
但这是从binaries/
文件夹中"提取"所有文件,并将它们放在其他两个文件旁边:
root:/# ls /app
requirements.txt
entrypoint.sh
executable1
executable2
executable3
问题
如何将某些文件和一个或多个(或多个)特定文件夹合并为 Dockerfile 中的一个唯一 COPY 语句(当然,如果可能的话)?
环境信息:
Docker version 20.10.0, build 7287ab3
Host: ubuntu 18.04.5
测试兆威
从localhost:~$
mkdir -p doc && cd doc && mkdir -p binaries && touch entrypoint.sh
requirements.txt binaries/ex1 binaries/ex2 binaries/ex3
&& echo 'FROM debian:buster-slim
WORKDIR /app
COPY requirements.txt entrypoint.sh binaries ./' >> Dockerfile
从localhost:~$
docker build --no-cache -t test:latest .
&& docker run -it --rm --name test test:latest bash
从容器内部:
root:/app# ls
给我:
entrypoint.sh ex1 ex2 ex3 requirements.txt
使用ADD
而不是COPY
时会遇到相同的行为。
您可以在 Dockerfile 旁边创建一个具有以下结构的文件夹,然后将内容复制到您的 apps 目录中,
$ tree
.
├── Dockerfile
└── folder
├── binaries
│ ├── executable1
│ ├── executable2
│ └── executable3
├── entrypoint.sh
└── requirements.txt
2 directories, 6 files
Dockerfile,
FROM debian:buster-slim
WORKDIR /app
COPY folder .
<小时 />root@b111e73a17c1:/app# tree
.
|-- binaries
| |-- executable1
| |-- executable2
| `-- executable3
|-- entrypoint.sh
`-- requirements.txt
1 directory, 5 files
如果不指定目标目录,您将无法COPY
或ADD
目录,如文档所示:
- 如果
<src>
是目录,则会复制目录的全部内容,包括文件系统元数据。注意
目录本身不会被复制,只会复制其内容。
来源:https://docs.docker.com/engine/reference/builder/#add https://docs.docker.com/engine/reference/builder/#copy
但是这里有两种可能性,因为 docker 不会递归地进入您的文件夹,您可以更改主机上的文件结构并执行以下操作:
.
└── to_mount
├── binaries
│ ├── executable1
│ ├── executable2
│ └── executable3
├── entrypoint.sh
└── requirements.txt
然后简单地:
COPY to_mount .
您可以使用另一种方式,这总是很高兴知道的,但根据您的用例可能会证明是非常不切实际的,那就是使用.dockerignore文件。
在 docker CLI 将上下文发送到 docker 守护程序之前,它会在上下文的根目录中查找名为
.dockerignore
的文件。如果此文件存在,CLI 将修改上下文以排除与其中的模式匹配的文件和目录。这有助于避免不必要地将大型或敏感文件和目录发送到守护程序,并可能使用ADD
或COPY
将它们添加到映像中。
来源: https://docs.docker.com/engine/reference/builder/#dockerignore-file
有了这个,您可以复制.
然后添加.docker忽略当前主机文件夹中但您不想在映像中复制的其他文件。
这是我的码头工人文件夹
.
├── .dockerignore
├── Dockerfile
├── binaries
│ ├── executable1
│ ├── executable2
│ └── executable3
├── docker-compose.yml
├── entrypoint.sh
└── requirements.txt
.dockerignore包含
Dockerfile
docker-compose.yml
.dockerignore
所以,做:
COPY . .
我最终得到
.
├── binaries
│ ├── executable1
│ ├── executable2
│ └── executable3
├── entrypoint.sh
└── requirements.txt
使用Dockerfile
FROM alpine
RUN apk add --no-cache tree
WORKDIR /tmp
COPY . .
我们得到
$ tree -a
.
├── .dockerignore
├── Dockerfile
├── binaries
│ ├── executable1
│ ├── executable2
│ └── executable3
├── docker-compose.yml
├── entrypoint.sh
└── requirements.txt
1 directory, 8 files
$ docker run --rm -ti $(docker build -q .) tree -a
.
├── binaries
│ ├── executable1
│ ├── executable2
│ └── executable3
├── entrypoint.sh
└── requirements.txt
1 directory, 5 files