Docker:当Dockerfile位于子目录

时间:2017-12-13 04:53:25

标签: docker copy docker-compose dockerfile directory-structure

我正在使用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

但是,当我从工作目录(docker-compose)运行app时,出现以下错误:

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 /容器不是best practice(1),并且以这种方式组织多个dockerfiles看起来很乱(2)。

所以,我的问题是:

如何在不更改原始目录结构的情况下解决此问题?

  • 需要对dockerfiles,docker-compose.yml或基本运行时命令进行哪些更改?
  • 有没有更好的方法来组织一切?
  • WORKDIR命令怎么样?

理想情况下,最佳解决方案应该适用于开发(本地)和生产(远程)环境,所以现在让我们避开卷...

3 个答案:

答案 0 :(得分:9)

您需要在此处执行的操作是在docker-compose.yml文件的构建部分中添加context: .dockerfile,以便您的服务了解完整的目录结构。

# docker-compose.yml
version: "3"
services:
  webserver:
    build:
      context: .
      dockerfile: ./dockerfiles/webserver/Dockerfile
    image: webserver:php-apache

答案 1 :(得分:0)

COPY指令的范围是Dockerfile所在的文件夹。我的建议是将Dockerfile更改为公用文件夹,并将指令更改为COPY . /var/www/html

答案 2 :(得分:0)

正如在别处已经阐明的那样,contextdockerfile 的组合可以解决问题。我只想补充一点,您甚至不需要在应用程序的根目录中找到 docker-compose.yml 文件本身即可使其工作。

例如,在我的一个项目中,我有多个组合配置来支持多种环境(developmentstagingproduction 等。 ),我决定把所有东西都放在他们自己的子目录中,以保持整洁。我的目录树如下:

.
+-- 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,它相对于 { {1}}。

有了上面的目录树和context文件,我们所要做的就是从应用程序的根目录compose.yml所在的目录)运行以下命令,即):

README.md

一切都充满魅力!

我知道这听起来有点令人费解,可能确实如此,但是当需要将应用程序部署到三个(或更多!)不同环境时,所花费的时间将得到回报。