336

In my Dockerfile I've got :

ADD ../../myapp.war /opt/tomcat7/webapps/

That file exists as ls ../../myapp.war returns me the correct file but when I execute sudo docker build -t myapp . I've got :

Step 1 : ADD ../../myapp.war /opt/tomcat7/webapps/
2014/07/02 19:18:09 ../../myapp.war: no such file or directory

Does somebody know why and how to do it correctly?

Anthony O.
  • 19,289
  • 14
  • 99
  • 157

9 Answers9

382

You can build the Dockerfile from the parent directory:

docker build -t <some tag> -f <dir/dir/Dockerfile> .
Pang
  • 9,073
  • 146
  • 84
  • 117
Boedy
  • 4,862
  • 1
  • 20
  • 24
  • 5
    Thank you! This works fine on a local box, but Docker Hub fails to build the image since it tries to do it from its same directory (tbh, just what one would normally expect). Is there any way to do the same trick in Docker Hub? – Marcel Hernandez Mar 25 '16 at 20:31
  • Not that I know of. You could push the image to the registry instead of using automated build. – Boedy Mar 29 '16 at 09:15
  • 2
    @eduncan911 I don't think this is deprecated at the the time I am writing my comment. They might've changed their mind since then? If I am wrong, can you link to the documentation where it says it's being deprecated. Thanks! – omninonsense Jul 04 '17 at 09:26
  • @omninonsense you cannot specify a `Dockerfile` from a sub-folder to build the files in the parent or current folder (as your answer eludes to, with the `.` currently path) any longer. The Dockerfile only supports a *build context* of files local to the location of the Dockerfile itself, and sub-folders down from it. Not documented, but a GitHub issue on security as Dockerfiles are not supposed to have access to files outside or its *build context*. A fix is to move the Dockerfile location higher up to the root of your project (ugly!), or use `docker-compose`. – eduncan911 Jul 04 '17 at 11:36
  • 10
    `-f` *doesn't* appear to be deprecated per the docs -> _Specify a Dockerfile (-f)_: https://docs.docker.com/engine/reference/commandline/build/#specify-a-dockerfile--f – Ray Jan 24 '18 at 21:29
  • As I read this bulletin, the '-f' flag has only been deprecated on the 'tag' command - https://docs.docker.com/engine/deprecated/#separator--of---security-opt-flag-on-docker-run – Carter Sanders Feb 22 '18 at 01:09
  • 12
    @eduncan911 can you delete your comment since it apparently isn't deprecated? I skipped over this answer initially because of your comment. – chris Jan 03 '19 at 23:47
  • I just ran into something that I thought I might be worth adding. While trying to copy a file from inside a folder named `bin` this error still came up for this command, moving it to folder with a different name allowed it to complete. No idea why. – Geoff Johnson Aug 27 '19 at 19:30
  • Won't *any* changes to files in the parent dir bump the docker versions and force a rebuild though? – mathtick Apr 18 '20 at 16:16
  • you can also do relative path to up folder with ../.. so now you are one level above =) just make sure in your Dockerfile in the copy section that you also start from the same level, that way you can incorporate folder that are outside where the Dockerfile lives – pelos May 05 '21 at 18:53
  • but why doesn't `COPY ../../.. .` work for me - I keep seing the contents of the current directory where I ran docker build? – Charlie Parker Aug 18 '21 at 21:55
  • @Boedy can you give a concrete example? I tried `docker build -t my_img -f /Users/miranda9/repo .` and I still can't get it to work with error: `failed to solve with frontend dockerfile.v0: failed to read dockerfile: error from sender: open /Users/miranda9/.Trash: operation not permitted`. Not sure why its trying to do that...? what is going on? – Charlie Parker Aug 18 '21 at 22:18
191

With docker-compose, you could set context folder:

# docker-compose.yml

version: '3.3'    
services:
  yourservice:
    build:
      context: ./
      dockerfile: ./docker/yourservice/Dockerfile
Brian Burns
  • 17,878
  • 8
  • 77
  • 67
Nikita Kuznetsov
  • 1,987
  • 1
  • 9
  • 12
  • 8
    Be careful where you set your context to because large files/folders will make the process hang. You'll want to ignore them with .dockerignore and more appropriately set your context to the point where you really need it. – Matt Kenefick Feb 17 '21 at 16:44
  • 1
    Using docker-compose as a shortcut to solve this problem of context build is not bad at the moment anyway. – gia huy May 28 '21 at 16:20
  • Should dockerfile path be relative to the new context or to docker compose file? – Noname Aug 13 '21 at 04:58
  • "When the value supplied is a relative path, it is interpreted as relative to the location of the Compose file. " https://docs.docker.com/compose/compose-file/compose-file-v3/ – 00schneider Mar 26 '22 at 16:26
162

Unfortunately, (for practical and security reasons I guess), if you want to add/copy local content, it must be located under the same root path than the Dockerfile.

From the documentation:

The <src> path must be inside the context of the build; you cannot ADD ../something/something, because the first step of a docker build is to send the context directory (and subdirectories) to the docker daemon.

EDIT: There's now an option (-f) to set the path of your Dockerfile ; it can be used to achieve what you want, see @Boedy 's response.

hooknc
  • 4,540
  • 5
  • 32
  • 55
mbarthelemy
  • 11,891
  • 4
  • 39
  • 42
  • 43
    Is there a "clean" workaround for this? I'd rather not restructure my whole project directory just to accommodate this. – ben_frankly Nov 21 '14 at 18:35
  • 1
    As said by @Günter, there is a workaround here http://superuser.com/a/842690/136024 ... is it really "clean"? Well at least it's a "workaround" :) – Anthony O. Dec 02 '14 at 08:39
  • 3
    See better answer from @Boedy http://stackoverflow.com/a/34300129/2950621 – nmgeek Jun 19 '16 at 19:27
  • is this why my `COPY` is failing? `COPY /Users/miranda9/ /miranda9`...yes it is: The path must be inside the context of the build; you cannot COPY ../something /something, because the first step of a docker build is to send the context directory (and subdirectories) to the docker daemon. – Charlie Parker Aug 18 '21 at 22:02
  • 1
    I'd like to hear any "security reason" for this, really – flm Mar 25 '22 at 14:40
33

Adding some code snippets to support the accepted answer.

Directory structure :

setup/
 |__docker/DockerFile
 |__target/scripts/<myscripts.sh>
src/
 |__<my source files>

Docker file entry:

RUN mkdir -p /home/vagrant/dockerws/chatServerInstaller/scripts/
RUN mkdir -p /home/vagrant/dockerws/chatServerInstaller/src/
WORKDIR /home/vagrant/dockerws/chatServerInstaller

#Copy all the required files from host's file system to the container file system.
COPY setup/target/scripts/install_x.sh scripts/
COPY setup/target/scripts/install_y.sh scripts/
COPY src/ src/

Command used to build the docker image

docker build -t test:latest -f setup/docker/Dockerfile .
Binita Bharati
  • 4,026
  • 1
  • 34
  • 22
  • great approach. Is it possible to share the code of `install_x.sh` as well? – Ariful Haque Feb 17 '20 at 03:03
  • I don't understand what `-f setup/docker/Dockerfile` flag is doing. What is it doing in your example? – Charlie Parker Aug 18 '21 at 22:27
  • also why does the docker command need the final dot if you are already specifying the path to the build context and Dockerfile? – Charlie Parker Aug 18 '21 at 22:28
  • also from where did you run that docker build command? what is the `pwd`? – Charlie Parker Aug 18 '21 at 22:29
  • @CharlieParker - `-f` option specifies the relative path of the `Dockerfile` wrt current working directory. The dot at the end specifies the current working directory. My answer already depicts how the current working directory looks like. Hope that clarifies it for you. – Binita Bharati Aug 22 '21 at 13:22
13

Since -f caused another problem, I developed another solution.

  • Create a base image in the parent folder
  • Added the required files.
  • Used this image as a base image for the project which in a descendant folder.

The -f flag does not solved my problem because my onbuild image looks for a file in a folder and had to call like this:

-f foo/bar/Dockerfile foo/bar

instead of

-f foo/bar/Dockerfile .

Also note that this is only solution for some cases as -f flag

guneysus
  • 5,797
  • 2
  • 42
  • 41
  • 1
    Clever idea! multi-stage build to carry over files you need! Thanks for sharing that! – codea Apr 05 '21 at 07:26
2

The solution for those who use composer is to use a volume pointing to the parent folder:

#docker-composer.yml

foo:
  build: foo
  volumes:
    - ./:/src/:ro

But I'm pretty sure the can be done playing with volumes in Dockerfile.

Pang
  • 9,073
  • 146
  • 84
  • 117
wikier
  • 2,395
  • 1
  • 25
  • 37
  • 6
    It can't. _Note: The host directory is, by its nature, host-dependent. For this reason, **you can’t mount a host directory from Dockerfile** because built images should be portable._ A host directory wouldn’t be available on all potential hosts. https://docs.docker.com/engine/tutorials/dockervolumes/#mount-a-host-directory-as-a-data-volume – Peeter Kokk Jul 08 '16 at 22:23
2

If you are using skaffold, use 'context:' to specify context location for each image dockerfile - context: ../../../

            apiVersion: skaffold/v2beta4
            kind: Config
            metadata:
                name: frontend
            build:
                artifacts:
                    - image: nginx-angular-ui
                      context: ../../../
                      sync:
                          # A local build will update dist and sync it to the container
                          manual:
                              - src: './dist/apps'
                                dest: '/usr/share/nginx/html'
                      docker:
                          dockerfile: ./tools/pipelines/dockerfile/nginx.dev.dockerfile
                    - image: webapi/image
                      context: ../../../../api/
                      docker:
                          dockerfile: ./dockerfile
            deploy:
                kubectl:
                    manifests:
                        - ./.k8s/*.yml

skaffold run -f ./skaffold.yaml

Sukhminder Sandhu
  • 429
  • 1
  • 4
  • 5
1
  • build the img from an upper dir

  • name the img

  • enable proper volume sharing

  • check the Makefile in the link above on how-to start the container ...

    docker build . -t proj-devops-img --no-cache --build-arg UID=$(shell id -u) --build-arg GID=$(shell id -g) -f src/docker/devops/Dockerfile
    
Yordan Georgiev
  • 4,572
  • 1
  • 48
  • 52
1

Let's say you have your directories tree like this:

dir0
├───dir1
│   └───dir11
|   |   └───dockerfile
|   └───dir12 (current)
└───dir2 (content to be copied)

and your dockerfile look like this:

FROM baseImage
COPY / /content

Let's say you want to copy dir2 content into a new docker image using COPY or ADD of dockerfile that is in dir11 and your current directory is dir12

You will have to run this command in order to build your image properly:

docker build -t image-name:tag -f ../dir11/dockerfile ../../dir2
  • -t your-image-name Name and optionally a tag in the 'name:tag' format
  • -f ../dir11/dockerfile Name of the Dockerfile (Default is 'PATH/Dockerfile')
  • ../../dir2 path to be current for COPY or ADD commands

Update

Let's say you run this by mistake:

docker build -t image-name:tag -f ../dir11/dockerfile ../../

This will not solve your problem because in this case the COPY / /content will look like it's copying dir0 content (dir1 & dir2) so in order to fix that you can either change the command using the right path or you can also change the COPY source path in the dockerfile like this:

COPY /dir2 /content
Affes Salem
  • 686
  • 6
  • 18