Docker:当 Docker 文件位于子目录时使用 COPY
Docker: Using COPY when the Dockerfile is located in a subdirectory
我正在使用 multiple dockerfiles 构建一个应用程序(每项服务一个)。我的应用程序的目录结构如下:
app
├── dockerfiles
│ ├── webserver
│ │ └── Dockerfile
│ └── database
│ └── Dockerfile
├── public
└── <frontend>
├── db
└── <data>
[...]
├── LICENSE
├── README.md
└── docker-compose.yml
在我的网络服务器 Dockerfile
中,我想使用 COPY
命令复制我现有的代码:
# Dockerfile
COPY ./public /var/www/html
我想使用我的 docker-compose.yml
文件部署应用程序:
# docker-compose.yml
version: "3"
services:
webserver:
build: ./dockerfiles/webserver
image: webserver:php-apache
但是,当我从工作目录 (app
) 运行 docker-compose
时,出现以下错误:
Building webserver
Step 1/2 : FROM php:7.1.11-apache-jessie
---> cb6a5015ad72
Step 2/2 : COPY ./public /var/www/html
Service 'webserver' failed to build: COPY failed: stat /var/lib/docker/tmp/docker-builder193736188/public: no such file or directory
如果我将网络服务器的 Dockerfile
移动到应用程序的根目录,此错误就会消失,因此我知道它是由路径或构建上下文问题引起的。
知道这一点后,我们可以通过以下两种方式之一解决问题:
(1) 对整个应用程序(在应用程序的根目录中)使用一个 Dockerfile
,或
app
└── Dockerfile
(2) 为每个服务使用多个 Dockerfiles
(在应用程序的根目录中)。
app
├── Dockerfile.webserver
└── Dockerfile.database
这些解决方案很糟糕,因为对所有内容使用一个 dockerfile/container 并不是 best practice (1),并且以这种方式组织多个 dockerfile 看起来很乱 (2)。
那么,我的问题是:
我们如何在不改变我们原来的目录结构的情况下解决这个问题?
- 需要对 dockerfiles、
docker-compose.yml
或基本 运行time 命令进行哪些更改?
- 有没有更好的方法来组织一切?
WORKDIR
命令呢?
理想情况下,最好的解决方案应该适用于开发(本地)和生产(远程)环境,所以让我们暂时避免使用大量...
COPY
指令的范围是Dockerfile所在的文件夹。我的建议是将您的 Dockerfile 更改为 public 文件夹并将指令更改为 COPY . /var/www/html
.
您在这里需要做的就是在 docker-compose.yml 文件中的构建部分中添加 context: .
和 dockerfile
,以便您的服务了解完整的目录结构。
# docker-compose.yml
version: "3"
services:
webserver:
build:
context: .
dockerfile: ./dockerfiles/webserver/Dockerfile
image: webserver:php-apache
正如其他地方已经阐明的那样,context
和 dockerfile
的组合可以达到目的。我只想补充一点,您甚至不需要在应用程序的根目录中找到 docker-compose.yml
文件本身就可以工作。
例如,在我的一个项目中,我有多个组合配置来支持多个环境(development、staging、production, etc.) 我决定把所有的东西都放在它们自己的子目录里,为了干净。我的目录树如下:
.
+-- README.md
+-- scripts
| +-- docker
| +-- compose.yml
| +-- compose-stage.yml
| +-- compose-prod.yml
| +-- dockerfile
| +-- ...
| +-- ...
其中 compose.yml
如下所示:
# compose.yml
version: "3.9"
services:
web:
build:
context: ../../
dockerfile: ./scripts/docker/dockerfile
....
注意 context
,它指向应用程序的根目录——比 compose.yml
文件所在的目录高两级——和 dockerfile
,它是相对于context
.
有了上面的目录树和compose.yml
文件,我们所要做的就是运行下面的命令从应用程序的根目录( README.md
所在的目录,即:
> docker compose -f scripts/docker/compose.yml up
而且一切都很有魅力!
我知道听起来有点令人费解,可能确实如此,但是当需要处理将应用程序部署到三个(或更多!)不同环境时,所花费的时间将得到回报。
不完全是 OP 的场景,但如果您不使用 docker-compose
,您也可以分别指定上下文和 Dockerfile:
docker build . -f app/dockerfiles/webserver/Dockerfile
这将以当前目录 .
作为上下文构建,但使用子目录中的 Dockerfile
。
我正在使用 multiple dockerfiles 构建一个应用程序(每项服务一个)。我的应用程序的目录结构如下:
app
├── dockerfiles
│ ├── webserver
│ │ └── Dockerfile
│ └── database
│ └── Dockerfile
├── public
└── <frontend>
├── db
└── <data>
[...]
├── LICENSE
├── README.md
└── docker-compose.yml
在我的网络服务器 Dockerfile
中,我想使用 COPY
命令复制我现有的代码:
# Dockerfile
COPY ./public /var/www/html
我想使用我的 docker-compose.yml
文件部署应用程序:
# docker-compose.yml
version: "3"
services:
webserver:
build: ./dockerfiles/webserver
image: webserver:php-apache
但是,当我从工作目录 (app
) 运行 docker-compose
时,出现以下错误:
Building webserver
Step 1/2 : FROM php:7.1.11-apache-jessie
---> cb6a5015ad72
Step 2/2 : COPY ./public /var/www/html
Service 'webserver' failed to build: COPY failed: stat /var/lib/docker/tmp/docker-builder193736188/public: no such file or directory
如果我将网络服务器的 Dockerfile
移动到应用程序的根目录,此错误就会消失,因此我知道它是由路径或构建上下文问题引起的。
知道这一点后,我们可以通过以下两种方式之一解决问题:
(1) 对整个应用程序(在应用程序的根目录中)使用一个 Dockerfile
,或
app
└── Dockerfile
(2) 为每个服务使用多个 Dockerfiles
(在应用程序的根目录中)。
app
├── Dockerfile.webserver
└── Dockerfile.database
这些解决方案很糟糕,因为对所有内容使用一个 dockerfile/container 并不是 best practice (1),并且以这种方式组织多个 dockerfile 看起来很乱 (2)。
那么,我的问题是:
我们如何在不改变我们原来的目录结构的情况下解决这个问题?
- 需要对 dockerfiles、
docker-compose.yml
或基本 运行time 命令进行哪些更改? - 有没有更好的方法来组织一切?
WORKDIR
命令呢?
理想情况下,最好的解决方案应该适用于开发(本地)和生产(远程)环境,所以让我们暂时避免使用大量...
COPY
指令的范围是Dockerfile所在的文件夹。我的建议是将您的 Dockerfile 更改为 public 文件夹并将指令更改为 COPY . /var/www/html
.
您在这里需要做的就是在 docker-compose.yml 文件中的构建部分中添加 context: .
和 dockerfile
,以便您的服务了解完整的目录结构。
# docker-compose.yml
version: "3"
services:
webserver:
build:
context: .
dockerfile: ./dockerfiles/webserver/Dockerfile
image: webserver:php-apache
正如其他地方已经阐明的那样,context
和 dockerfile
的组合可以达到目的。我只想补充一点,您甚至不需要在应用程序的根目录中找到 docker-compose.yml
文件本身就可以工作。
例如,在我的一个项目中,我有多个组合配置来支持多个环境(development、staging、production, etc.) 我决定把所有的东西都放在它们自己的子目录里,为了干净。我的目录树如下:
.
+-- README.md
+-- scripts
| +-- docker
| +-- compose.yml
| +-- compose-stage.yml
| +-- compose-prod.yml
| +-- dockerfile
| +-- ...
| +-- ...
其中 compose.yml
如下所示:
# compose.yml
version: "3.9"
services:
web:
build:
context: ../../
dockerfile: ./scripts/docker/dockerfile
....
注意 context
,它指向应用程序的根目录——比 compose.yml
文件所在的目录高两级——和 dockerfile
,它是相对于context
.
有了上面的目录树和compose.yml
文件,我们所要做的就是运行下面的命令从应用程序的根目录( README.md
所在的目录,即:
> docker compose -f scripts/docker/compose.yml up
而且一切都很有魅力!
我知道听起来有点令人费解,可能确实如此,但是当需要处理将应用程序部署到三个(或更多!)不同环境时,所花费的时间将得到回报。
不完全是 OP 的场景,但如果您不使用 docker-compose
,您也可以分别指定上下文和 Dockerfile:
docker build . -f app/dockerfiles/webserver/Dockerfile
这将以当前目录 .
作为上下文构建,但使用子目录中的 Dockerfile
。