Docker: Using COPY when the Dockerfile is located in a subdirectory

CodyAE picture CodyAE · Dec 13, 2017 · Viewed 7.7k times · Source

I'm building an app using multiple dockerfiles (one for each service). My app's directory structure is as follows:

app
├── dockerfiles
│   ├── webserver
│   │   └── Dockerfile
│   └── database
│       └── Dockerfile
├── public
    └── <frontend>
├── db
    └── <data>
  [...]
├── LICENSE
├── README.md
└── docker-compose.yml

In my webserver's Dockerfile, I want to copy in my existing code using the COPY command:

# Dockerfile
COPY ./public /var/www/html

And I want to deploy the app using my docker-compose.yml file:

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

However, when I run docker-compose from the working directory (app), I get the following error:

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

This error disappears if I move my webserver's Dockerfile to the app's root, so I know that it's being caused by a paths or build context issue.

And knowing this, we can fix the problem one of two ways, by either:

(1) Using one Dockerfile for the entire app (in the app's root), or

app
└── Dockerfile

(2) Using multiple Dockerfiles for each service (in the app's root).

app
├── Dockerfile.webserver
└── Dockerfile.database

These solutions are bad because using one dockerfile/container for everything is not best practice (1), and having multiple dockerfiles organized in this way just looks messy (2).


So, My Question is:

How do we fix this problem without changing our original directory structure?

  • What changes need to be made to the dockerfiles, to docker-compose.yml, or to the basic runtime commands?
  • Is there a better way to organize everything?
  • What about the WORKDIR command?

Ideally, the best solution should work for both dev (local) and production (remote) environments, so let's avoid volumes for now...

Answer

vivekyad4v picture vivekyad4v · Dec 13, 2017

All you need to do here is add context: . and dockerfile in your build section inside your docker-compose.yml file so that your service understands the complete directory structure.

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